Ruby 4.0.0dev (2025-11-29 revision 82b91ec7e55cb5ef4acd61213843614542bea3b3)
io.c (82b91ec7e55cb5ef4acd61213843614542bea3b3)
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 void
3160make_readconv(rb_io_t *fptr, int size)
3161{
3162 if (!fptr->readconv) {
3163 int ecflags;
3164 VALUE ecopts;
3165 const char *sname, *dname;
3166 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3167 ecopts = fptr->encs.ecopts;
3168 if (fptr->encs.enc2) {
3169 sname = rb_enc_name(fptr->encs.enc2);
3170 dname = rb_enc_name(io_read_encoding(fptr));
3171 }
3172 else {
3173 sname = dname = "";
3174 }
3175 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3176 if (!fptr->readconv)
3177 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3178 fptr->cbuf.off = 0;
3179 fptr->cbuf.len = 0;
3180 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3181 fptr->cbuf.capa = size;
3182 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3183 }
3184}
3185
3186#define MORE_CHAR_SUSPENDED Qtrue
3187#define MORE_CHAR_FINISHED Qnil
3188static VALUE
3189fill_cbuf(rb_io_t *fptr, int ec_flags)
3190{
3191 const unsigned char *ss, *sp, *se;
3192 unsigned char *ds, *dp, *de;
3194 int putbackable;
3195 int cbuf_len0;
3196 VALUE exc;
3197
3198 ec_flags |= ECONV_PARTIAL_INPUT;
3199
3200 if (fptr->cbuf.len == fptr->cbuf.capa)
3201 return MORE_CHAR_SUSPENDED; /* cbuf full */
3202 if (fptr->cbuf.len == 0)
3203 fptr->cbuf.off = 0;
3204 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3205 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3206 fptr->cbuf.off = 0;
3207 }
3208
3209 cbuf_len0 = fptr->cbuf.len;
3210
3211 while (1) {
3212 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3213 se = sp + fptr->rbuf.len;
3214 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3215 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3216 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3217 fptr->rbuf.off += (int)(sp - ss);
3218 fptr->rbuf.len -= (int)(sp - ss);
3219 fptr->cbuf.len += (int)(dp - ds);
3220
3221 putbackable = rb_econv_putbackable(fptr->readconv);
3222 if (putbackable) {
3223 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3224 fptr->rbuf.off -= putbackable;
3225 fptr->rbuf.len += putbackable;
3226 }
3227
3228 exc = rb_econv_make_exception(fptr->readconv);
3229 if (!NIL_P(exc))
3230 return exc;
3231
3232 if (cbuf_len0 != fptr->cbuf.len)
3233 return MORE_CHAR_SUSPENDED;
3234
3235 if (res == econv_finished) {
3236 return MORE_CHAR_FINISHED;
3237 }
3238
3239 if (res == econv_source_buffer_empty) {
3240 if (fptr->rbuf.len == 0) {
3241 READ_CHECK(fptr);
3242 if (io_fillbuf(fptr) < 0) {
3243 if (!fptr->readconv) {
3244 return MORE_CHAR_FINISHED;
3245 }
3246 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3247 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3248 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3249 fptr->cbuf.len += (int)(dp - ds);
3251 break;
3252 }
3253 }
3254 }
3255 }
3256 if (cbuf_len0 != fptr->cbuf.len)
3257 return MORE_CHAR_SUSPENDED;
3258
3259 return MORE_CHAR_FINISHED;
3260}
3261
3262static VALUE
3263more_char(rb_io_t *fptr)
3264{
3265 VALUE v;
3266 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3267 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3268 rb_exc_raise(v);
3269 return v;
3270}
3271
3272static VALUE
3273io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3274{
3275 VALUE str = Qnil;
3276 if (strp) {
3277 str = *strp;
3278 if (NIL_P(str)) {
3279 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3280 }
3281 else {
3282 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3283 }
3284 rb_enc_associate(str, fptr->encs.enc);
3285 }
3286 fptr->cbuf.off += len;
3287 fptr->cbuf.len -= len;
3288 /* xxx: set coderange */
3289 if (fptr->cbuf.len == 0)
3290 fptr->cbuf.off = 0;
3291 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3292 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3293 fptr->cbuf.off = 0;
3294 }
3295 return str;
3296}
3297
3298static int
3299io_setstrbuf(VALUE *str, long len)
3300{
3301#ifdef _WIN32
3302 if (len > 0)
3303 len = (len + 1) & ~1L; /* round up for wide char */
3304#endif
3305 if (NIL_P(*str)) {
3306 *str = rb_str_new(0, len);
3307 return TRUE;
3308 }
3309 else {
3310 VALUE s = StringValue(*str);
3311 rb_str_modify(s);
3312
3313 long clen = RSTRING_LEN(s);
3314 if (clen >= len) {
3315 return FALSE;
3316 }
3317 len -= clen;
3318 }
3319 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3321 }
3322 return FALSE;
3323}
3324
3325#define MAX_REALLOC_GAP 4096
3326static void
3327io_shrink_read_string(VALUE str, long n)
3328{
3329 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3330 rb_str_resize(str, n);
3331 }
3332}
3333
3334static void
3335io_set_read_length(VALUE str, long n, int shrinkable)
3336{
3337 if (RSTRING_LEN(str) != n) {
3338 rb_str_modify(str);
3339 rb_str_set_len(str, n);
3340 if (shrinkable) io_shrink_read_string(str, n);
3341 }
3342}
3343
3344static VALUE
3345read_all(rb_io_t *fptr, long siz, VALUE str)
3346{
3347 long bytes;
3348 long n;
3349 long pos;
3350 rb_encoding *enc;
3351 int cr;
3352 int shrinkable;
3353
3354 if (NEED_READCONV(fptr)) {
3355 int first = !NIL_P(str);
3356 SET_BINARY_MODE(fptr);
3357 shrinkable = io_setstrbuf(&str,0);
3358 make_readconv(fptr, 0);
3359 while (1) {
3360 VALUE v;
3361 if (fptr->cbuf.len) {
3362 if (first) rb_str_set_len(str, first = 0);
3363 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3364 }
3365 v = fill_cbuf(fptr, 0);
3366 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3367 if (fptr->cbuf.len) {
3368 if (first) rb_str_set_len(str, first = 0);
3369 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3370 }
3371 rb_exc_raise(v);
3372 }
3373 if (v == MORE_CHAR_FINISHED) {
3374 clear_readconv(fptr);
3375 if (first) rb_str_set_len(str, first = 0);
3376 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3377 return io_enc_str(str, fptr);
3378 }
3379 }
3380 }
3381
3382 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3383 bytes = 0;
3384 pos = 0;
3385
3386 enc = io_read_encoding(fptr);
3387 cr = 0;
3388
3389 if (siz == 0) siz = BUFSIZ;
3390 shrinkable = io_setstrbuf(&str, siz);
3391 for (;;) {
3392 READ_CHECK(fptr);
3393 n = io_fread(str, bytes, siz - bytes, fptr);
3394 if (n == 0 && bytes == 0) {
3395 rb_str_set_len(str, 0);
3396 break;
3397 }
3398 bytes += n;
3399 rb_str_set_len(str, bytes);
3400 if (cr != ENC_CODERANGE_BROKEN)
3401 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3402 if (bytes < siz) break;
3403 siz += BUFSIZ;
3404
3405 size_t capa = rb_str_capacity(str);
3406 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3407 if (capa < BUFSIZ) {
3408 capa = BUFSIZ;
3409 }
3410 else if (capa > IO_MAX_BUFFER_GROWTH) {
3411 capa = IO_MAX_BUFFER_GROWTH;
3412 }
3414 }
3415 }
3416 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3417 str = io_enc_str(str, fptr);
3418 ENC_CODERANGE_SET(str, cr);
3419 return str;
3420}
3421
3422void
3424{
3425 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3426 rb_sys_fail_path(fptr->pathv);
3427 }
3428}
3429
3430static VALUE
3431io_read_memory_call(VALUE arg)
3432{
3433 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3434
3435 VALUE scheduler = rb_fiber_scheduler_current();
3436 if (scheduler != Qnil) {
3437 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3438
3439 if (!UNDEF_P(result)) {
3440 // This is actually returned as a pseudo-VALUE and later cast to a long:
3442 }
3443 }
3444
3445 if (iis->nonblock) {
3446 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3447 }
3448 else {
3449 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3450 }
3451}
3452
3453static long
3454io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3455{
3456 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3457}
3458
3459#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3460
3461static VALUE
3462io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3463{
3464 rb_io_t *fptr;
3465 VALUE length, str;
3466 long n, len;
3467 struct io_internal_read_struct iis;
3468 int shrinkable;
3469
3470 rb_scan_args(argc, argv, "11", &length, &str);
3471
3472 if ((len = NUM2LONG(length)) < 0) {
3473 rb_raise(rb_eArgError, "negative length %ld given", len);
3474 }
3475
3476 shrinkable = io_setstrbuf(&str, len);
3477
3478 GetOpenFile(io, fptr);
3480
3481 if (len == 0) {
3482 io_set_read_length(str, 0, shrinkable);
3483 return str;
3484 }
3485
3486 if (!nonblock)
3487 READ_CHECK(fptr);
3488 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3489 if (n <= 0) {
3490 again:
3491 if (nonblock) {
3492 rb_io_set_nonblock(fptr);
3493 }
3494 io_setstrbuf(&str, len);
3495 iis.th = rb_thread_current();
3496 iis.fptr = fptr;
3497 iis.nonblock = nonblock;
3498 iis.fd = fptr->fd;
3499 iis.buf = RSTRING_PTR(str);
3500 iis.capa = len;
3501 iis.timeout = NULL;
3502 n = io_read_memory_locktmp(str, &iis);
3503 if (n < 0) {
3504 int e = errno;
3505 if (!nonblock && fptr_wait_readable(fptr))
3506 goto again;
3507 if (nonblock && (io_again_p(e))) {
3508 if (no_exception)
3509 return sym_wait_readable;
3510 else
3511 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3512 e, "read would block");
3513 }
3514 rb_syserr_fail_path(e, fptr->pathv);
3515 }
3516 }
3517 io_set_read_length(str, n, shrinkable);
3518
3519 if (n == 0)
3520 return Qnil;
3521 else
3522 return str;
3523}
3524
3525/*
3526 * call-seq:
3527 * readpartial(maxlen) -> string
3528 * readpartial(maxlen, out_string) -> out_string
3529 *
3530 * Reads up to +maxlen+ bytes from the stream;
3531 * returns a string (either a new string or the given +out_string+).
3532 * Its encoding is:
3533 *
3534 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3535 * - ASCII-8BIT, otherwise.
3536 *
3537 * - Contains +maxlen+ bytes from the stream, if available.
3538 * - Otherwise contains all available bytes, if any available.
3539 * - Otherwise is an empty string.
3540 *
3541 * With the single non-negative integer argument +maxlen+ given,
3542 * returns a new string:
3543 *
3544 * f = File.new('t.txt')
3545 * f.readpartial(20) # => "First line\nSecond l"
3546 * f.readpartial(20) # => "ine\n\nFourth line\n"
3547 * f.readpartial(20) # => "Fifth line\n"
3548 * f.readpartial(20) # Raises EOFError.
3549 * f.close
3550 *
3551 * With both argument +maxlen+ and string argument +out_string+ given,
3552 * returns modified +out_string+:
3553 *
3554 * f = File.new('t.txt')
3555 * s = 'foo'
3556 * f.readpartial(20, s) # => "First line\nSecond l"
3557 * s = 'bar'
3558 * f.readpartial(0, s) # => ""
3559 * f.close
3560 *
3561 * This method is useful for a stream such as a pipe, a socket, or a tty.
3562 * It blocks only when no data is immediately available.
3563 * This means that it blocks only when _all_ of the following are true:
3564 *
3565 * - The byte buffer in the stream is empty.
3566 * - The content of the stream is empty.
3567 * - The stream is not at EOF.
3568 *
3569 * When blocked, the method waits for either more data or EOF on the stream:
3570 *
3571 * - If more data is read, the method returns the data.
3572 * - If EOF is reached, the method raises EOFError.
3573 *
3574 * When not blocked, the method responds immediately:
3575 *
3576 * - Returns data from the buffer if there is any.
3577 * - Otherwise returns data from the stream if there is any.
3578 * - Otherwise raises EOFError if the stream has reached EOF.
3579 *
3580 * Note that this method is similar to sysread. The differences are:
3581 *
3582 * - If the byte buffer is not empty, read from the byte buffer
3583 * instead of "sysread for buffered IO (IOError)".
3584 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3585 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3586 * readpartial retries the system call.
3587 *
3588 * The latter means that readpartial is non-blocking-flag insensitive.
3589 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3590 * if the fd is blocking mode.
3591 *
3592 * Examples:
3593 *
3594 * # # Returned Buffer Content Pipe Content
3595 * r, w = IO.pipe #
3596 * w << 'abc' # "" "abc".
3597 * r.readpartial(4096) # => "abc" "" ""
3598 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3599 *
3600 * # # Returned Buffer Content Pipe Content
3601 * r, w = IO.pipe #
3602 * w << 'abc' # "" "abc"
3603 * w.close # "" "abc" EOF
3604 * r.readpartial(4096) # => "abc" "" EOF
3605 * r.readpartial(4096) # raises EOFError
3606 *
3607 * # # Returned Buffer Content Pipe Content
3608 * r, w = IO.pipe #
3609 * w << "abc\ndef\n" # "" "abc\ndef\n"
3610 * r.gets # => "abc\n" "def\n" ""
3611 * w << "ghi\n" # "def\n" "ghi\n"
3612 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3613 * r.readpartial(4096) # => "ghi\n" "" ""
3614 *
3615 */
3616
3617static VALUE
3618io_readpartial(int argc, VALUE *argv, VALUE io)
3619{
3620 VALUE ret;
3621
3622 ret = io_getpartial(argc, argv, io, Qnil, 0);
3623 if (NIL_P(ret))
3624 rb_eof_error();
3625 return ret;
3626}
3627
3628static VALUE
3629io_nonblock_eof(int no_exception)
3630{
3631 if (!no_exception) {
3632 rb_eof_error();
3633 }
3634 return Qnil;
3635}
3636
3637/* :nodoc: */
3638static VALUE
3639io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3640{
3641 rb_io_t *fptr;
3642 long n, len;
3643 struct io_internal_read_struct iis;
3644 int shrinkable;
3645
3646 if ((len = NUM2LONG(length)) < 0) {
3647 rb_raise(rb_eArgError, "negative length %ld given", len);
3648 }
3649
3650 shrinkable = io_setstrbuf(&str, len);
3651 rb_bool_expected(ex, "exception", TRUE);
3652
3653 GetOpenFile(io, fptr);
3655
3656 if (len == 0) {
3657 io_set_read_length(str, 0, shrinkable);
3658 return str;
3659 }
3660
3661 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3662 if (n <= 0) {
3663 rb_fd_set_nonblock(fptr->fd);
3664 shrinkable |= io_setstrbuf(&str, len);
3665 iis.fptr = fptr;
3666 iis.nonblock = 1;
3667 iis.fd = fptr->fd;
3668 iis.buf = RSTRING_PTR(str);
3669 iis.capa = len;
3670 iis.timeout = NULL;
3671 n = io_read_memory_locktmp(str, &iis);
3672 if (n < 0) {
3673 int e = errno;
3674 if (io_again_p(e)) {
3675 if (!ex) return sym_wait_readable;
3676 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3677 e, "read would block");
3678 }
3679 rb_syserr_fail_path(e, fptr->pathv);
3680 }
3681 }
3682 io_set_read_length(str, n, shrinkable);
3683
3684 if (n == 0) {
3685 if (!ex) return Qnil;
3686 rb_eof_error();
3687 }
3688
3689 return str;
3690}
3691
3692/* :nodoc: */
3693static VALUE
3694io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3695{
3696 rb_io_t *fptr;
3697 long n;
3698
3699 if (!RB_TYPE_P(str, T_STRING))
3700 str = rb_obj_as_string(str);
3701 rb_bool_expected(ex, "exception", TRUE);
3702
3703 io = GetWriteIO(io);
3704 GetOpenFile(io, fptr);
3706
3707 if (io_fflush(fptr) < 0)
3708 rb_sys_fail_on_write(fptr);
3709
3710 rb_fd_set_nonblock(fptr->fd);
3711 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3712 RB_GC_GUARD(str);
3713
3714 if (n < 0) {
3715 int e = errno;
3716 if (io_again_p(e)) {
3717 if (!ex) {
3718 return sym_wait_writable;
3719 }
3720 else {
3721 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3722 }
3723 }
3724 rb_syserr_fail_path(e, fptr->pathv);
3725 }
3726
3727 return LONG2FIX(n);
3728}
3729
3730/*
3731 * call-seq:
3732 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3733 *
3734 * Reads bytes from the stream; the stream must be opened for reading
3735 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3736 *
3737 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3738 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3739 *
3740 * Returns a string (either a new string or the given +out_string+)
3741 * containing the bytes read.
3742 * The encoding of the string depends on both +maxLen+ and +out_string+:
3743 *
3744 * - +maxlen+ is +nil+: uses internal encoding of +self+
3745 * (regardless of whether +out_string+ was given).
3746 * - +maxlen+ not +nil+:
3747 *
3748 * - +out_string+ given: encoding of +out_string+ not modified.
3749 * - +out_string+ not given: ASCII-8BIT is used.
3750 *
3751 * <b>Without Argument +out_string+</b>
3752 *
3753 * When argument +out_string+ is omitted,
3754 * the returned value is a new string:
3755 *
3756 * f = File.new('t.txt')
3757 * f.read
3758 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3759 * f.rewind
3760 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3761 * f.read(30) # => "rth line\r\nFifth line\r\n"
3762 * f.read(30) # => nil
3763 * f.close
3764 *
3765 * If +maxlen+ is zero, returns an empty string.
3766 *
3767 * <b> With Argument +out_string+</b>
3768 *
3769 * When argument +out_string+ is given,
3770 * the returned value is +out_string+, whose content is replaced:
3771 *
3772 * f = File.new('t.txt')
3773 * s = 'foo' # => "foo"
3774 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3775 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3776 * f.rewind
3777 * s = 'bar'
3778 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3779 * s # => "First line\r\nSecond line\r\n\r\nFou"
3780 * s = 'baz'
3781 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3782 * s # => "rth line\r\nFifth line\r\n"
3783 * s = 'bat'
3784 * f.read(30, s) # => nil
3785 * s # => ""
3786 * f.close
3787 *
3788 * Note that this method behaves like the fread() function in C.
3789 * This means it retries to invoke read(2) system calls to read data
3790 * with the specified maxlen (or until EOF).
3791 *
3792 * This behavior is preserved even if the stream is in non-blocking mode.
3793 * (This method is non-blocking-flag insensitive as other methods.)
3794 *
3795 * If you need the behavior like a single read(2) system call,
3796 * consider #readpartial, #read_nonblock, and #sysread.
3797 *
3798 * Related: IO#write.
3799 */
3800
3801static VALUE
3802io_read(int argc, VALUE *argv, VALUE io)
3803{
3804 rb_io_t *fptr;
3805 long n, len;
3806 VALUE length, str;
3807 int shrinkable;
3808#if RUBY_CRLF_ENVIRONMENT
3809 int previous_mode;
3810#endif
3811
3812 rb_scan_args(argc, argv, "02", &length, &str);
3813
3814 if (NIL_P(length)) {
3815 GetOpenFile(io, fptr);
3817 return read_all(fptr, remain_size(fptr), str);
3818 }
3819 len = NUM2LONG(length);
3820 if (len < 0) {
3821 rb_raise(rb_eArgError, "negative length %ld given", len);
3822 }
3823
3824 shrinkable = io_setstrbuf(&str,len);
3825
3826 GetOpenFile(io, fptr);
3828 if (len == 0) {
3829 io_set_read_length(str, 0, shrinkable);
3830 return str;
3831 }
3832
3833 READ_CHECK(fptr);
3834#if RUBY_CRLF_ENVIRONMENT
3835 previous_mode = set_binary_mode_with_seek_cur(fptr);
3836#endif
3837 n = io_fread(str, 0, len, fptr);
3838 io_set_read_length(str, n, shrinkable);
3839#if RUBY_CRLF_ENVIRONMENT
3840 if (previous_mode == O_TEXT) {
3841 setmode(fptr->fd, O_TEXT);
3842 }
3843#endif
3844 if (n == 0) return Qnil;
3845
3846 return str;
3847}
3848
3849static void
3850rscheck(const char *rsptr, long rslen, VALUE rs)
3851{
3852 if (!rs) return;
3853 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3854 rb_raise(rb_eRuntimeError, "rs modified");
3855}
3856
3857static const char *
3858search_delim(const char *p, long len, int delim, rb_encoding *enc)
3859{
3860 if (rb_enc_mbminlen(enc) == 1) {
3861 p = memchr(p, delim, len);
3862 if (p) return p + 1;
3863 }
3864 else {
3865 const char *end = p + len;
3866 while (p < end) {
3867 int r = rb_enc_precise_mbclen(p, end, enc);
3868 if (!MBCLEN_CHARFOUND_P(r)) {
3869 p += rb_enc_mbminlen(enc);
3870 continue;
3871 }
3872 int n = MBCLEN_CHARFOUND_LEN(r);
3873 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3874 return p + n;
3875 }
3876 p += n;
3877 }
3878 }
3879 return NULL;
3880}
3881
3882static int
3883appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3884{
3885 VALUE str = *strp;
3886 long limit = *lp;
3887
3888 if (NEED_READCONV(fptr)) {
3889 SET_BINARY_MODE(fptr);
3890 make_readconv(fptr, 0);
3891 do {
3892 const char *p, *e;
3893 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3894 if (searchlen) {
3895 p = READ_CHAR_PENDING_PTR(fptr);
3896 if (0 < limit && limit < searchlen)
3897 searchlen = (int)limit;
3898 e = search_delim(p, searchlen, delim, enc);
3899 if (e) {
3900 int len = (int)(e-p);
3901 if (NIL_P(str))
3902 *strp = str = rb_str_new(p, len);
3903 else
3904 rb_str_buf_cat(str, p, len);
3905 fptr->cbuf.off += len;
3906 fptr->cbuf.len -= len;
3907 limit -= len;
3908 *lp = limit;
3909 return delim;
3910 }
3911
3912 if (NIL_P(str))
3913 *strp = str = rb_str_new(p, searchlen);
3914 else
3915 rb_str_buf_cat(str, p, searchlen);
3916 fptr->cbuf.off += searchlen;
3917 fptr->cbuf.len -= searchlen;
3918 limit -= searchlen;
3919
3920 if (limit == 0) {
3921 *lp = limit;
3922 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3923 }
3924 }
3925 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3926 clear_readconv(fptr);
3927 *lp = limit;
3928 return EOF;
3929 }
3930
3931 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3932 do {
3933 long pending = READ_DATA_PENDING_COUNT(fptr);
3934 if (pending > 0) {
3935 const char *p = READ_DATA_PENDING_PTR(fptr);
3936 const char *e;
3937 long last;
3938
3939 if (limit > 0 && pending > limit) pending = limit;
3940 e = search_delim(p, pending, delim, enc);
3941 if (e) pending = e - p;
3942 if (!NIL_P(str)) {
3943 last = RSTRING_LEN(str);
3944 rb_str_resize(str, last + pending);
3945 }
3946 else {
3947 last = 0;
3948 *strp = str = rb_str_buf_new(pending);
3949 rb_str_set_len(str, pending);
3950 }
3951 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3952 limit -= pending;
3953 *lp = limit;
3954 if (e) return delim;
3955 if (limit == 0)
3956 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3957 }
3958 READ_CHECK(fptr);
3959 } while (io_fillbuf(fptr) >= 0);
3960 *lp = limit;
3961 return EOF;
3962}
3963
3964static inline int
3965swallow(rb_io_t *fptr, int term)
3966{
3967 if (NEED_READCONV(fptr)) {
3968 rb_encoding *enc = io_read_encoding(fptr);
3969 int needconv = rb_enc_mbminlen(enc) != 1;
3970 SET_BINARY_MODE(fptr);
3971 make_readconv(fptr, 0);
3972 do {
3973 size_t cnt;
3974 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3975 const char *p = READ_CHAR_PENDING_PTR(fptr);
3976 int i;
3977 if (!needconv) {
3978 if (*p != term) return TRUE;
3979 i = (int)cnt;
3980 while (--i && *++p == term);
3981 }
3982 else {
3983 const char *e = p + cnt;
3984 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3985 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3986 i = (int)(e - p);
3987 }
3988 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3989 }
3990 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3991 return FALSE;
3992 }
3993
3994 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3995 do {
3996 size_t cnt;
3997 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3998 char buf[1024];
3999 const char *p = READ_DATA_PENDING_PTR(fptr);
4000 int i;
4001 if (cnt > sizeof buf) cnt = sizeof buf;
4002 if (*p != term) return TRUE;
4003 i = (int)cnt;
4004 while (--i && *++p == term);
4005 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4006 rb_sys_fail_path(fptr->pathv);
4007 }
4008 READ_CHECK(fptr);
4009 } while (io_fillbuf(fptr) == 0);
4010 return FALSE;
4011}
4012
4013static VALUE
4014rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4015{
4016 VALUE str = Qnil;
4017 int len = 0;
4018 long pos = 0;
4019 int cr = 0;
4020
4021 do {
4022 int pending = READ_DATA_PENDING_COUNT(fptr);
4023
4024 if (pending > 0) {
4025 const char *p = READ_DATA_PENDING_PTR(fptr);
4026 const char *e;
4027 int chomplen = 0;
4028
4029 e = memchr(p, '\n', pending);
4030 if (e) {
4031 pending = (int)(e - p + 1);
4032 if (chomp) {
4033 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4034 }
4035 }
4036 if (NIL_P(str)) {
4037 str = rb_str_new(p, pending - chomplen);
4038 fptr->rbuf.off += pending;
4039 fptr->rbuf.len -= pending;
4040 }
4041 else {
4042 rb_str_resize(str, len + pending - chomplen);
4043 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4044 fptr->rbuf.off += chomplen;
4045 fptr->rbuf.len -= chomplen;
4046 if (pending == 1 && chomplen == 1 && len > 0) {
4047 if (RSTRING_PTR(str)[len-1] == '\r') {
4048 rb_str_resize(str, --len);
4049 break;
4050 }
4051 }
4052 }
4053 len += pending - chomplen;
4054 if (cr != ENC_CODERANGE_BROKEN)
4055 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4056 if (e) break;
4057 }
4058 READ_CHECK(fptr);
4059 } while (io_fillbuf(fptr) >= 0);
4060 if (NIL_P(str)) return Qnil;
4061
4062 str = io_enc_str(str, fptr);
4063 ENC_CODERANGE_SET(str, cr);
4064 fptr->lineno++;
4065
4066 return str;
4067}
4068
4070 VALUE io;
4071 VALUE rs;
4072 long limit;
4073 unsigned int chomp: 1;
4074};
4075
4076static void
4077extract_getline_opts(VALUE opts, struct getline_arg *args)
4078{
4079 int chomp = FALSE;
4080 if (!NIL_P(opts)) {
4081 static ID kwds[1];
4082 VALUE vchomp;
4083 if (!kwds[0]) {
4084 kwds[0] = rb_intern_const("chomp");
4085 }
4086 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4087 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4088 }
4089 args->chomp = chomp;
4090}
4091
4092static void
4093extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4094{
4095 VALUE rs = rb_rs, lim = Qnil;
4096
4097 if (argc == 1) {
4098 VALUE tmp = Qnil;
4099
4100 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4101 rs = tmp;
4102 }
4103 else {
4104 lim = argv[0];
4105 }
4106 }
4107 else if (2 <= argc) {
4108 rs = argv[0], lim = argv[1];
4109 if (!NIL_P(rs))
4110 StringValue(rs);
4111 }
4112 args->rs = rs;
4113 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4114}
4115
4116static void
4117check_getline_args(VALUE *rsp, long *limit, VALUE io)
4118{
4119 rb_io_t *fptr;
4120 VALUE rs = *rsp;
4121
4122 if (!NIL_P(rs)) {
4123 rb_encoding *enc_rs, *enc_io;
4124
4125 GetOpenFile(io, fptr);
4126 enc_rs = rb_enc_get(rs);
4127 enc_io = io_read_encoding(fptr);
4128 if (enc_io != enc_rs &&
4129 (!is_ascii_string(rs) ||
4130 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4131 if (rs == rb_default_rs) {
4132 rs = rb_enc_str_new(0, 0, enc_io);
4133 rb_str_buf_cat_ascii(rs, "\n");
4134 *rsp = rs;
4135 }
4136 else {
4137 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4138 rb_enc_name(enc_io),
4139 rb_enc_name(enc_rs));
4140 }
4141 }
4142 }
4143}
4144
4145static void
4146prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4147{
4148 VALUE opts;
4149 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4150 extract_getline_args(argc, argv, args);
4151 extract_getline_opts(opts, args);
4152 check_getline_args(&args->rs, &args->limit, io);
4153}
4154
4155static VALUE
4156rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4157{
4158 VALUE str = Qnil;
4159 int nolimit = 0;
4160 rb_encoding *enc;
4161
4163 if (NIL_P(rs) && limit < 0) {
4164 str = read_all(fptr, 0, Qnil);
4165 if (RSTRING_LEN(str) == 0) return Qnil;
4166 }
4167 else if (limit == 0) {
4168 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4169 }
4170 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4171 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4172 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4173 return rb_io_getline_fast(fptr, enc, chomp);
4174 }
4175 else {
4176 int c, newline = -1;
4177 const char *rsptr = 0;
4178 long rslen = 0;
4179 int rspara = 0;
4180 int extra_limit = 16;
4181 int chomp_cr = chomp;
4182
4183 SET_BINARY_MODE(fptr);
4184 enc = io_read_encoding(fptr);
4185
4186 if (!NIL_P(rs)) {
4187 rslen = RSTRING_LEN(rs);
4188 if (rslen == 0) {
4189 rsptr = "\n\n";
4190 rslen = 2;
4191 rspara = 1;
4192 swallow(fptr, '\n');
4193 rs = 0;
4194 if (!rb_enc_asciicompat(enc)) {
4195 rs = rb_usascii_str_new(rsptr, rslen);
4196 rs = rb_str_conv_enc(rs, 0, enc);
4197 OBJ_FREEZE(rs);
4198 rsptr = RSTRING_PTR(rs);
4199 rslen = RSTRING_LEN(rs);
4200 }
4201 newline = '\n';
4202 }
4203 else if (rb_enc_mbminlen(enc) == 1) {
4204 rsptr = RSTRING_PTR(rs);
4205 newline = (unsigned char)rsptr[rslen - 1];
4206 }
4207 else {
4208 rs = rb_str_conv_enc(rs, 0, enc);
4209 rsptr = RSTRING_PTR(rs);
4210 const char *e = rsptr + rslen;
4211 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4212 int n;
4213 newline = rb_enc_codepoint_len(last, e, &n, enc);
4214 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4215 }
4216 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4217 }
4218
4219 /* MS - Optimization */
4220 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4221 const char *s, *p, *pp, *e;
4222
4223 if (c == newline) {
4224 if (RSTRING_LEN(str) < rslen) continue;
4225 s = RSTRING_PTR(str);
4226 e = RSTRING_END(str);
4227 p = e - rslen;
4228 if (!at_char_boundary(s, p, e, enc)) continue;
4229 if (!rspara) rscheck(rsptr, rslen, rs);
4230 if (memcmp(p, rsptr, rslen) == 0) {
4231 if (chomp) {
4232 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4233 rb_str_set_len(str, p - s);
4234 }
4235 break;
4236 }
4237 }
4238 if (limit == 0) {
4239 s = RSTRING_PTR(str);
4240 p = RSTRING_END(str);
4241 pp = rb_enc_prev_char(s, p, p, enc);
4242 if (extra_limit && pp &&
4243 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4244 /* relax the limit while incomplete character.
4245 * extra_limit limits the relax length */
4246 limit = 1;
4247 extra_limit--;
4248 }
4249 else {
4250 nolimit = 1;
4251 break;
4252 }
4253 }
4254 }
4255
4256 if (rspara && c != EOF)
4257 swallow(fptr, '\n');
4258 if (!NIL_P(str))
4259 str = io_enc_str(str, fptr);
4260 }
4261
4262 if (!NIL_P(str) && !nolimit) {
4263 fptr->lineno++;
4264 }
4265
4266 return str;
4267}
4268
4269static VALUE
4270rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4271{
4272 rb_io_t *fptr;
4273 int old_lineno, new_lineno;
4274 VALUE str;
4275
4276 GetOpenFile(io, fptr);
4277 old_lineno = fptr->lineno;
4278 str = rb_io_getline_0(rs, limit, chomp, fptr);
4279 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4280 if (io == ARGF.current_file) {
4281 ARGF.lineno += new_lineno - old_lineno;
4282 ARGF.last_lineno = ARGF.lineno;
4283 }
4284 else {
4285 ARGF.last_lineno = new_lineno;
4286 }
4287 }
4288
4289 return str;
4290}
4291
4292static VALUE
4293rb_io_getline(int argc, VALUE *argv, VALUE io)
4294{
4295 struct getline_arg args;
4296
4297 prepare_getline_args(argc, argv, &args, io);
4298 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4299}
4300
4301VALUE
4303{
4304 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4305}
4306
4307VALUE
4308rb_io_gets_limit_internal(VALUE io, long limit)
4309{
4310 rb_io_t *fptr;
4311 GetOpenFile(io, fptr);
4312 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4313}
4314
4315VALUE
4316rb_io_gets_internal(VALUE io)
4317{
4318 return rb_io_gets_limit_internal(io, -1);
4319}
4320
4321/*
4322 * call-seq:
4323 * gets(sep = $/, chomp: false) -> string or nil
4324 * gets(limit, chomp: false) -> string or nil
4325 * gets(sep, limit, chomp: false) -> string or nil
4326 *
4327 * Reads and returns a line from the stream;
4328 * assigns the return value to <tt>$_</tt>.
4329 * See {Line IO}[rdoc-ref:IO@Line+IO].
4330 *
4331 * With no arguments given, returns the next line
4332 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4333 *
4334 * f = File.open('t.txt')
4335 * f.gets # => "First line\n"
4336 * $_ # => "First line\n"
4337 * f.gets # => "\n"
4338 * f.gets # => "Fourth line\n"
4339 * f.gets # => "Fifth line\n"
4340 * f.gets # => nil
4341 * f.close
4342 *
4343 * With only string argument +sep+ given,
4344 * returns the next line as determined by line separator +sep+,
4345 * or +nil+ if none;
4346 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4347 *
4348 * f = File.new('t.txt')
4349 * f.gets('l') # => "First l"
4350 * f.gets('li') # => "ine\nSecond li"
4351 * f.gets('lin') # => "ne\n\nFourth lin"
4352 * f.gets # => "e\n"
4353 * f.close
4354 *
4355 * The two special values for +sep+ are honored:
4356 *
4357 * f = File.new('t.txt')
4358 * # Get all.
4359 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4360 * f.rewind
4361 * # Get paragraph (up to two line separators).
4362 * f.gets('') # => "First line\nSecond line\n\n"
4363 * f.close
4364 *
4365 * With only integer argument +limit+ given,
4366 * limits the number of bytes in the line;
4367 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4368 *
4369 * # No more than one line.
4370 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4371 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4372 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4373 *
4374 * With arguments +sep+ and +limit+ given,
4375 * combines the two behaviors
4376 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4377 *
4378 * Optional keyword argument +chomp+ specifies whether line separators
4379 * are to be omitted:
4380 *
4381 * f = File.open('t.txt')
4382 * # Chomp the lines.
4383 * f.gets(chomp: true) # => "First line"
4384 * f.gets(chomp: true) # => "Second line"
4385 * f.gets(chomp: true) # => ""
4386 * f.gets(chomp: true) # => "Fourth line"
4387 * f.gets(chomp: true) # => "Fifth line"
4388 * f.gets(chomp: true) # => nil
4389 * f.close
4390 *
4391 */
4392
4393static VALUE
4394rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4395{
4396 VALUE str;
4397
4398 str = rb_io_getline(argc, argv, io);
4399 rb_lastline_set(str);
4400
4401 return str;
4402}
4403
4404/*
4405 * call-seq:
4406 * lineno -> integer
4407 *
4408 * Returns the current line number for the stream;
4409 * see {Line Number}[rdoc-ref:IO@Line+Number].
4410 *
4411 */
4412
4413static VALUE
4414rb_io_lineno(VALUE io)
4415{
4416 rb_io_t *fptr;
4417
4418 GetOpenFile(io, fptr);
4420 return INT2NUM(fptr->lineno);
4421}
4422
4423/*
4424 * call-seq:
4425 * lineno = integer -> integer
4426 *
4427 * Sets and returns the line number for the stream;
4428 * see {Line Number}[rdoc-ref:IO@Line+Number].
4429 *
4430 */
4431
4432static VALUE
4433rb_io_set_lineno(VALUE io, VALUE lineno)
4434{
4435 rb_io_t *fptr;
4436
4437 GetOpenFile(io, fptr);
4439 fptr->lineno = NUM2INT(lineno);
4440 return lineno;
4441}
4442
4443/* :nodoc: */
4444static VALUE
4445io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4446{
4447 long limit = -1;
4448 if (NIL_P(lim)) {
4449 VALUE tmp = Qnil;
4450 // If sep is specified, but it's not a string and not nil, then assume
4451 // it's the limit (it should be an integer)
4452 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4453 // If the user has specified a non-nil / non-string value
4454 // for the separator, we assume it's the limit and set the
4455 // separator to default: rb_rs.
4456 lim = sep;
4457 limit = NUM2LONG(lim);
4458 sep = rb_rs;
4459 }
4460 else {
4461 sep = tmp;
4462 }
4463 }
4464 else {
4465 if (!NIL_P(sep)) StringValue(sep);
4466 limit = NUM2LONG(lim);
4467 }
4468
4469 check_getline_args(&sep, &limit, io);
4470
4471 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4472 rb_lastline_set_up(line, 1);
4473
4474 if (NIL_P(line)) {
4475 rb_eof_error();
4476 }
4477 return line;
4478}
4479
4480static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4481
4482/*
4483 * call-seq:
4484 * readlines(sep = $/, chomp: false) -> array
4485 * readlines(limit, chomp: false) -> array
4486 * readlines(sep, limit, chomp: false) -> array
4487 *
4488 * Reads and returns all remaining line from the stream;
4489 * does not modify <tt>$_</tt>.
4490 * See {Line IO}[rdoc-ref:IO@Line+IO].
4491 *
4492 * With no arguments given, returns lines
4493 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4494 *
4495 * f = File.new('t.txt')
4496 * f.readlines
4497 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4498 * f.readlines # => []
4499 * f.close
4500 *
4501 * With only string argument +sep+ given,
4502 * returns lines as determined by line separator +sep+,
4503 * or +nil+ if none;
4504 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4505 *
4506 * f = File.new('t.txt')
4507 * f.readlines('li')
4508 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4509 * f.close
4510 *
4511 * The two special values for +sep+ are honored:
4512 *
4513 * f = File.new('t.txt')
4514 * # Get all into one string.
4515 * f.readlines(nil)
4516 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4517 * # Get paragraphs (up to two line separators).
4518 * f.rewind
4519 * f.readlines('')
4520 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4521 * f.close
4522 *
4523 * With only integer argument +limit+ given,
4524 * limits the number of bytes in each line;
4525 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4526 *
4527 * f = File.new('t.txt')
4528 * f.readlines(8)
4529 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4530 * f.close
4531 *
4532 * With arguments +sep+ and +limit+ given,
4533 * combines the two behaviors
4534 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4535 *
4536 * Optional keyword argument +chomp+ specifies whether line separators
4537 * are to be omitted:
4538 *
4539 * f = File.new('t.txt')
4540 * f.readlines(chomp: true)
4541 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4542 * f.close
4543 *
4544 */
4545
4546static VALUE
4547rb_io_readlines(int argc, VALUE *argv, VALUE io)
4548{
4549 struct getline_arg args;
4550
4551 prepare_getline_args(argc, argv, &args, io);
4552 return io_readlines(&args, io);
4553}
4554
4555static VALUE
4556io_readlines(const struct getline_arg *arg, VALUE io)
4557{
4558 VALUE line, ary;
4559
4560 if (arg->limit == 0)
4561 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4562 ary = rb_ary_new();
4563 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4564 rb_ary_push(ary, line);
4565 }
4566 return ary;
4567}
4568
4569/*
4570 * call-seq:
4571 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4572 * each_line(limit, chomp: false) {|line| ... } -> self
4573 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4574 * each_line -> enumerator
4575 *
4576 * Calls the block with each remaining line read from the stream;
4577 * returns +self+.
4578 * Does nothing if already at end-of-stream;
4579 * See {Line IO}[rdoc-ref:IO@Line+IO].
4580 *
4581 * With no arguments given, reads lines
4582 * as determined by line separator <tt>$/</tt>:
4583 *
4584 * f = File.new('t.txt')
4585 * f.each_line {|line| p line }
4586 * f.each_line {|line| fail 'Cannot happen' }
4587 * f.close
4588 *
4589 * Output:
4590 *
4591 * "First line\n"
4592 * "Second line\n"
4593 * "\n"
4594 * "Fourth line\n"
4595 * "Fifth line\n"
4596 *
4597 * With only string argument +sep+ given,
4598 * reads lines as determined by line separator +sep+;
4599 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4600 *
4601 * f = File.new('t.txt')
4602 * f.each_line('li') {|line| p line }
4603 * f.close
4604 *
4605 * Output:
4606 *
4607 * "First li"
4608 * "ne\nSecond li"
4609 * "ne\n\nFourth li"
4610 * "ne\nFifth li"
4611 * "ne\n"
4612 *
4613 * The two special values for +sep+ are honored:
4614 *
4615 * f = File.new('t.txt')
4616 * # Get all into one string.
4617 * f.each_line(nil) {|line| p line }
4618 * f.close
4619 *
4620 * Output:
4621 *
4622 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4623 *
4624 * f.rewind
4625 * # Get paragraphs (up to two line separators).
4626 * f.each_line('') {|line| p line }
4627 *
4628 * Output:
4629 *
4630 * "First line\nSecond line\n\n"
4631 * "Fourth line\nFifth line\n"
4632 *
4633 * With only integer argument +limit+ given,
4634 * limits the number of bytes in each line;
4635 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4636 *
4637 * f = File.new('t.txt')
4638 * f.each_line(8) {|line| p line }
4639 * f.close
4640 *
4641 * Output:
4642 *
4643 * "First li"
4644 * "ne\n"
4645 * "Second l"
4646 * "ine\n"
4647 * "\n"
4648 * "Fourth l"
4649 * "ine\n"
4650 * "Fifth li"
4651 * "ne\n"
4652 *
4653 * With arguments +sep+ and +limit+ given,
4654 * combines the two behaviors
4655 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4656 *
4657 * Optional keyword argument +chomp+ specifies whether line separators
4658 * are to be omitted:
4659 *
4660 * f = File.new('t.txt')
4661 * f.each_line(chomp: true) {|line| p line }
4662 * f.close
4663 *
4664 * Output:
4665 *
4666 * "First line"
4667 * "Second line"
4668 * ""
4669 * "Fourth line"
4670 * "Fifth line"
4671 *
4672 * Returns an Enumerator if no block is given.
4673 */
4674
4675static VALUE
4676rb_io_each_line(int argc, VALUE *argv, VALUE io)
4677{
4678 VALUE str;
4679 struct getline_arg args;
4680
4681 RETURN_ENUMERATOR(io, argc, argv);
4682 prepare_getline_args(argc, argv, &args, io);
4683 if (args.limit == 0)
4684 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4685 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4686 rb_yield(str);
4687 }
4688 return io;
4689}
4690
4691/*
4692 * call-seq:
4693 * each_byte {|byte| ... } -> self
4694 * each_byte -> enumerator
4695 *
4696 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4697 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4698 *
4699 * f = File.new('t.rus')
4700 * a = []
4701 * f.each_byte {|b| a << b }
4702 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4703 * f.close
4704 *
4705 * Returns an Enumerator if no block is given.
4706 *
4707 * Related: IO#each_char, IO#each_codepoint.
4708 *
4709 */
4710
4711static VALUE
4712rb_io_each_byte(VALUE io)
4713{
4714 rb_io_t *fptr;
4715
4716 RETURN_ENUMERATOR(io, 0, 0);
4717 GetOpenFile(io, fptr);
4718
4719 do {
4720 while (fptr->rbuf.len > 0) {
4721 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4722 fptr->rbuf.len--;
4723 rb_yield(INT2FIX(*p & 0xff));
4725 errno = 0;
4726 }
4727 READ_CHECK(fptr);
4728 } while (io_fillbuf(fptr) >= 0);
4729 return io;
4730}
4731
4732static VALUE
4733io_getc(rb_io_t *fptr, rb_encoding *enc)
4734{
4735 int r, n, cr = 0;
4736 VALUE str;
4737
4738 if (NEED_READCONV(fptr)) {
4739 rb_encoding *read_enc = io_read_encoding(fptr);
4740
4741 str = Qnil;
4742 SET_BINARY_MODE(fptr);
4743 make_readconv(fptr, 0);
4744
4745 while (1) {
4746 if (fptr->cbuf.len) {
4747 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4748 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4749 read_enc);
4750 if (!MBCLEN_NEEDMORE_P(r))
4751 break;
4752 if (fptr->cbuf.len == fptr->cbuf.capa) {
4753 rb_raise(rb_eIOError, "too long character");
4754 }
4755 }
4756
4757 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4758 if (fptr->cbuf.len == 0) {
4759 clear_readconv(fptr);
4760 return Qnil;
4761 }
4762 /* return an unit of an incomplete character just before EOF */
4763 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4764 fptr->cbuf.off += 1;
4765 fptr->cbuf.len -= 1;
4766 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4768 return str;
4769 }
4770 }
4771 if (MBCLEN_INVALID_P(r)) {
4772 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4773 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4774 read_enc);
4775 io_shift_cbuf(fptr, r, &str);
4777 }
4778 else {
4779 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4781 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4782 ISASCII(RSTRING_PTR(str)[0])) {
4783 cr = ENC_CODERANGE_7BIT;
4784 }
4785 }
4786 str = io_enc_str(str, fptr);
4787 ENC_CODERANGE_SET(str, cr);
4788 return str;
4789 }
4790
4791 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4792 if (io_fillbuf(fptr) < 0) {
4793 return Qnil;
4794 }
4795 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4796 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4797 fptr->rbuf.off += 1;
4798 fptr->rbuf.len -= 1;
4799 cr = ENC_CODERANGE_7BIT;
4800 }
4801 else {
4802 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4803 if (MBCLEN_CHARFOUND_P(r) &&
4804 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4805 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4806 fptr->rbuf.off += n;
4807 fptr->rbuf.len -= n;
4809 }
4810 else if (MBCLEN_NEEDMORE_P(r)) {
4811 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4812 fptr->rbuf.len = 0;
4813 getc_needmore:
4814 if (io_fillbuf(fptr) != -1) {
4815 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4816 fptr->rbuf.off++;
4817 fptr->rbuf.len--;
4818 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4819 if (MBCLEN_NEEDMORE_P(r)) {
4820 goto getc_needmore;
4821 }
4822 else if (MBCLEN_CHARFOUND_P(r)) {
4824 }
4825 }
4826 }
4827 else {
4828 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4829 fptr->rbuf.off++;
4830 fptr->rbuf.len--;
4831 }
4832 }
4833 if (!cr) cr = ENC_CODERANGE_BROKEN;
4834 str = io_enc_str(str, fptr);
4835 ENC_CODERANGE_SET(str, cr);
4836 return str;
4837}
4838
4839/*
4840 * call-seq:
4841 * each_char {|c| ... } -> self
4842 * each_char -> enumerator
4843 *
4844 * Calls the given block with each character in the stream; returns +self+.
4845 * See {Character IO}[rdoc-ref:IO@Character+IO].
4846 *
4847 * f = File.new('t.rus')
4848 * a = []
4849 * f.each_char {|c| a << c.ord }
4850 * a # => [1090, 1077, 1089, 1090]
4851 * f.close
4852 *
4853 * Returns an Enumerator if no block is given.
4854 *
4855 * Related: IO#each_byte, IO#each_codepoint.
4856 *
4857 */
4858
4859static VALUE
4860rb_io_each_char(VALUE io)
4861{
4862 rb_io_t *fptr;
4863 rb_encoding *enc;
4864 VALUE c;
4865
4866 RETURN_ENUMERATOR(io, 0, 0);
4867 GetOpenFile(io, fptr);
4869
4870 enc = io_input_encoding(fptr);
4871 READ_CHECK(fptr);
4872 while (!NIL_P(c = io_getc(fptr, enc))) {
4873 rb_yield(c);
4874 }
4875 return io;
4876}
4877
4878/*
4879 * call-seq:
4880 * each_codepoint {|c| ... } -> self
4881 * each_codepoint -> enumerator
4882 *
4883 * Calls the given block with each codepoint in the stream; returns +self+:
4884 *
4885 * f = File.new('t.rus')
4886 * a = []
4887 * f.each_codepoint {|c| a << c }
4888 * a # => [1090, 1077, 1089, 1090]
4889 * f.close
4890 *
4891 * Returns an Enumerator if no block is given.
4892 *
4893 * Related: IO#each_byte, IO#each_char.
4894 *
4895 */
4896
4897static VALUE
4898rb_io_each_codepoint(VALUE io)
4899{
4900 rb_io_t *fptr;
4901 rb_encoding *enc;
4902 unsigned int c;
4903 int r, n;
4904
4905 RETURN_ENUMERATOR(io, 0, 0);
4906 GetOpenFile(io, fptr);
4908
4909 READ_CHECK(fptr);
4910 enc = io_read_encoding(fptr);
4911 if (NEED_READCONV(fptr)) {
4912 SET_BINARY_MODE(fptr);
4913 r = 1; /* no invalid char yet */
4914 for (;;) {
4915 make_readconv(fptr, 0);
4916 for (;;) {
4917 if (fptr->cbuf.len) {
4918 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4919 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4920 enc);
4921 if (!MBCLEN_NEEDMORE_P(r))
4922 break;
4923 if (fptr->cbuf.len == fptr->cbuf.capa) {
4924 rb_raise(rb_eIOError, "too long character");
4925 }
4926 }
4927 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4928 clear_readconv(fptr);
4929 if (!MBCLEN_CHARFOUND_P(r)) {
4930 goto invalid;
4931 }
4932 return io;
4933 }
4934 }
4935 if (MBCLEN_INVALID_P(r)) {
4936 goto invalid;
4937 }
4938 n = MBCLEN_CHARFOUND_LEN(r);
4939 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4940 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4941 enc);
4942 fptr->cbuf.off += n;
4943 fptr->cbuf.len -= n;
4944 rb_yield(UINT2NUM(c));
4946 }
4947 }
4948 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4949 while (io_fillbuf(fptr) >= 0) {
4950 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4951 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4952 if (MBCLEN_CHARFOUND_P(r) &&
4953 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4954 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4955 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4956 fptr->rbuf.off += n;
4957 fptr->rbuf.len -= n;
4958 rb_yield(UINT2NUM(c));
4959 }
4960 else if (MBCLEN_INVALID_P(r)) {
4961 goto invalid;
4962 }
4963 else if (MBCLEN_NEEDMORE_P(r)) {
4964 char cbuf[8], *p = cbuf;
4965 int more = MBCLEN_NEEDMORE_LEN(r);
4966 if (more > numberof(cbuf)) goto invalid;
4967 more += n = fptr->rbuf.len;
4968 if (more > numberof(cbuf)) goto invalid;
4969 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4970 (p += n, (more -= n) > 0)) {
4971 if (io_fillbuf(fptr) < 0) goto invalid;
4972 if ((n = fptr->rbuf.len) > more) n = more;
4973 }
4974 r = rb_enc_precise_mbclen(cbuf, p, enc);
4975 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4976 c = rb_enc_codepoint(cbuf, p, enc);
4977 rb_yield(UINT2NUM(c));
4978 }
4979 else {
4980 continue;
4981 }
4983 }
4984 return io;
4985
4986 invalid:
4987 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4989}
4990
4991/*
4992 * call-seq:
4993 * getc -> character or nil
4994 *
4995 * Reads and returns the next 1-character string from the stream;
4996 * returns +nil+ if already at end-of-stream.
4997 * See {Character IO}[rdoc-ref:IO@Character+IO].
4998 *
4999 * f = File.open('t.txt')
5000 * f.getc # => "F"
5001 * f.close
5002 * f = File.open('t.rus')
5003 * f.getc.ord # => 1090
5004 * f.close
5005 *
5006 * Related: IO#readchar (may raise EOFError).
5007 *
5008 */
5009
5010static VALUE
5011rb_io_getc(VALUE io)
5012{
5013 rb_io_t *fptr;
5014 rb_encoding *enc;
5015
5016 GetOpenFile(io, fptr);
5018
5019 enc = io_input_encoding(fptr);
5020 READ_CHECK(fptr);
5021 return io_getc(fptr, enc);
5022}
5023
5024/*
5025 * call-seq:
5026 * readchar -> string
5027 *
5028 * Reads and returns the next 1-character string from the stream;
5029 * raises EOFError if already at end-of-stream.
5030 * See {Character IO}[rdoc-ref:IO@Character+IO].
5031 *
5032 * f = File.open('t.txt')
5033 * f.readchar # => "F"
5034 * f.close
5035 * f = File.open('t.rus')
5036 * f.readchar.ord # => 1090
5037 * f.close
5038 *
5039 * Related: IO#getc (will not raise EOFError).
5040 *
5041 */
5042
5043static VALUE
5044rb_io_readchar(VALUE io)
5045{
5046 VALUE c = rb_io_getc(io);
5047
5048 if (NIL_P(c)) {
5049 rb_eof_error();
5050 }
5051 return c;
5052}
5053
5054/*
5055 * call-seq:
5056 * getbyte -> integer or nil
5057 *
5058 * Reads and returns the next byte (in range 0..255) from the stream;
5059 * returns +nil+ if already at end-of-stream.
5060 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5061 *
5062 * f = File.open('t.txt')
5063 * f.getbyte # => 70
5064 * f.close
5065 * f = File.open('t.rus')
5066 * f.getbyte # => 209
5067 * f.close
5068 *
5069 * Related: IO#readbyte (may raise EOFError).
5070 */
5071
5072VALUE
5074{
5075 rb_io_t *fptr;
5076 int c;
5077
5078 GetOpenFile(io, fptr);
5080 READ_CHECK(fptr);
5081 VALUE r_stdout = rb_ractor_stdout();
5082 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5083 rb_io_t *ofp;
5084 GetOpenFile(r_stdout, ofp);
5085 if (ofp->mode & FMODE_TTY) {
5086 rb_io_flush(r_stdout);
5087 }
5088 }
5089 if (io_fillbuf(fptr) < 0) {
5090 return Qnil;
5091 }
5092 fptr->rbuf.off++;
5093 fptr->rbuf.len--;
5094 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5095 return INT2FIX(c & 0xff);
5096}
5097
5098/*
5099 * call-seq:
5100 * readbyte -> integer
5101 *
5102 * Reads and returns the next byte (in range 0..255) from the stream;
5103 * raises EOFError if already at end-of-stream.
5104 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5105 *
5106 * f = File.open('t.txt')
5107 * f.readbyte # => 70
5108 * f.close
5109 * f = File.open('t.rus')
5110 * f.readbyte # => 209
5111 * f.close
5112 *
5113 * Related: IO#getbyte (will not raise EOFError).
5114 *
5115 */
5116
5117static VALUE
5118rb_io_readbyte(VALUE io)
5119{
5120 VALUE c = rb_io_getbyte(io);
5121
5122 if (NIL_P(c)) {
5123 rb_eof_error();
5124 }
5125 return c;
5126}
5127
5128/*
5129 * call-seq:
5130 * ungetbyte(integer) -> nil
5131 * ungetbyte(string) -> nil
5132 *
5133 * Pushes back ("unshifts") the given data onto the stream's buffer,
5134 * placing the data so that it is next to be read; returns +nil+.
5135 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5136 *
5137 * Note that:
5138 *
5139 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5140 * - Calling #rewind on the stream discards the pushed-back data.
5141 *
5142 * When argument +integer+ is given, uses only its low-order byte:
5143 *
5144 * File.write('t.tmp', '012')
5145 * f = File.open('t.tmp')
5146 * f.ungetbyte(0x41) # => nil
5147 * f.read # => "A012"
5148 * f.rewind
5149 * f.ungetbyte(0x4243) # => nil
5150 * f.read # => "C012"
5151 * f.close
5152 *
5153 * When argument +string+ is given, uses all bytes:
5154 *
5155 * File.write('t.tmp', '012')
5156 * f = File.open('t.tmp')
5157 * f.ungetbyte('A') # => nil
5158 * f.read # => "A012"
5159 * f.rewind
5160 * f.ungetbyte('BCDE') # => nil
5161 * f.read # => "BCDE012"
5162 * f.close
5163 *
5164 */
5165
5166VALUE
5168{
5169 rb_io_t *fptr;
5170
5171 GetOpenFile(io, fptr);
5173 switch (TYPE(b)) {
5174 case T_NIL:
5175 return Qnil;
5176 case T_FIXNUM:
5177 case T_BIGNUM: ;
5178 VALUE v = rb_int_modulo(b, INT2FIX(256));
5179 unsigned char c = NUM2INT(v) & 0xFF;
5180 b = rb_str_new((const char *)&c, 1);
5181 break;
5182 default:
5183 StringValue(b);
5184 }
5185 io_ungetbyte(b, fptr);
5186 return Qnil;
5187}
5188
5189/*
5190 * call-seq:
5191 * ungetc(integer) -> nil
5192 * ungetc(string) -> nil
5193 *
5194 * Pushes back ("unshifts") the given data onto the stream's buffer,
5195 * placing the data so that it is next to be read; returns +nil+.
5196 * See {Character IO}[rdoc-ref:IO@Character+IO].
5197 *
5198 * Note that:
5199 *
5200 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5201 * - Calling #rewind on the stream discards the pushed-back data.
5202 *
5203 * When argument +integer+ is given, interprets the integer as a character:
5204 *
5205 * File.write('t.tmp', '012')
5206 * f = File.open('t.tmp')
5207 * f.ungetc(0x41) # => nil
5208 * f.read # => "A012"
5209 * f.rewind
5210 * f.ungetc(0x0442) # => nil
5211 * f.getc.ord # => 1090
5212 * f.close
5213 *
5214 * When argument +string+ is given, uses all characters:
5215 *
5216 * File.write('t.tmp', '012')
5217 * f = File.open('t.tmp')
5218 * f.ungetc('A') # => nil
5219 * f.read # => "A012"
5220 * f.rewind
5221 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5222 * f.getc.ord # => 1090
5223 * f.getc.ord # => 1077
5224 * f.getc.ord # => 1089
5225 * f.getc.ord # => 1090
5226 * f.close
5227 *
5228 */
5229
5230VALUE
5232{
5233 rb_io_t *fptr;
5234 long len;
5235
5236 GetOpenFile(io, fptr);
5238 if (FIXNUM_P(c)) {
5239 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5240 }
5241 else if (RB_BIGNUM_TYPE_P(c)) {
5242 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5243 }
5244 else {
5245 StringValue(c);
5246 }
5247 if (NEED_READCONV(fptr)) {
5248 SET_BINARY_MODE(fptr);
5249 len = RSTRING_LEN(c);
5250#if SIZEOF_LONG > SIZEOF_INT
5251 if (len > INT_MAX)
5252 rb_raise(rb_eIOError, "ungetc failed");
5253#endif
5254 make_readconv(fptr, (int)len);
5255 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5256 rb_raise(rb_eIOError, "ungetc failed");
5257 if (fptr->cbuf.off < len) {
5258 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5259 fptr->cbuf.ptr+fptr->cbuf.off,
5260 char, fptr->cbuf.len);
5261 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5262 }
5263 fptr->cbuf.off -= (int)len;
5264 fptr->cbuf.len += (int)len;
5265 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5266 }
5267 else {
5268 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5269 io_ungetbyte(c, fptr);
5270 }
5271 return Qnil;
5272}
5273
5274/*
5275 * call-seq:
5276 * isatty -> true or false
5277 *
5278 * Returns +true+ if the stream is associated with a terminal device (tty),
5279 * +false+ otherwise:
5280 *
5281 * f = File.new('t.txt').isatty #=> false
5282 * f.close
5283 * f = File.new('/dev/tty').isatty #=> true
5284 * f.close
5285 *
5286 */
5287
5288static VALUE
5289rb_io_isatty(VALUE io)
5290{
5291 rb_io_t *fptr;
5292
5293 GetOpenFile(io, fptr);
5294 return RBOOL(isatty(fptr->fd) != 0);
5295}
5296
5297#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5298/*
5299 * call-seq:
5300 * close_on_exec? -> true or false
5301 *
5302 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5303 *
5304 * f = File.open('t.txt')
5305 * f.close_on_exec? # => true
5306 * f.close_on_exec = false
5307 * f.close_on_exec? # => false
5308 * f.close
5309 *
5310 */
5311
5312static VALUE
5313rb_io_close_on_exec_p(VALUE io)
5314{
5315 rb_io_t *fptr;
5316 VALUE write_io;
5317 int fd, ret;
5318
5319 write_io = GetWriteIO(io);
5320 if (io != write_io) {
5321 GetOpenFile(write_io, fptr);
5322 if (fptr && 0 <= (fd = fptr->fd)) {
5323 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5324 if (!(ret & FD_CLOEXEC)) return Qfalse;
5325 }
5326 }
5327
5328 GetOpenFile(io, fptr);
5329 if (fptr && 0 <= (fd = fptr->fd)) {
5330 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5331 if (!(ret & FD_CLOEXEC)) return Qfalse;
5332 }
5333 return Qtrue;
5334}
5335#else
5336#define rb_io_close_on_exec_p rb_f_notimplement
5337#endif
5338
5339#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5340/*
5341 * call-seq:
5342 * self.close_on_exec = bool -> true or false
5343 *
5344 * Sets a close-on-exec flag.
5345 *
5346 * f = File.open(File::NULL)
5347 * f.close_on_exec = true
5348 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5349 * f.closed? #=> false
5350 *
5351 * Ruby sets close-on-exec flags of all file descriptors by default
5352 * since Ruby 2.0.0.
5353 * So you don't need to set by yourself.
5354 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5355 * if another thread use fork() and exec() (via system() method for example).
5356 * If you really needs file descriptor inheritance to child process,
5357 * use spawn()'s argument such as fd=>fd.
5358 */
5359
5360static VALUE
5361rb_io_set_close_on_exec(VALUE io, VALUE arg)
5362{
5363 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5364 rb_io_t *fptr;
5365 VALUE write_io;
5366 int fd, ret;
5367
5368 write_io = GetWriteIO(io);
5369 if (io != write_io) {
5370 GetOpenFile(write_io, fptr);
5371 if (fptr && 0 <= (fd = fptr->fd)) {
5372 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5373 if ((ret & FD_CLOEXEC) != flag) {
5374 ret = (ret & ~FD_CLOEXEC) | flag;
5375 ret = fcntl(fd, F_SETFD, ret);
5376 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5377 }
5378 }
5379
5380 }
5381
5382 GetOpenFile(io, fptr);
5383 if (fptr && 0 <= (fd = fptr->fd)) {
5384 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5385 if ((ret & FD_CLOEXEC) != flag) {
5386 ret = (ret & ~FD_CLOEXEC) | flag;
5387 ret = fcntl(fd, F_SETFD, ret);
5388 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5389 }
5390 }
5391 return Qnil;
5392}
5393#else
5394#define rb_io_set_close_on_exec rb_f_notimplement
5395#endif
5396
5397#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5398#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5399
5400static VALUE
5401finish_writeconv(rb_io_t *fptr, int noalloc)
5402{
5403 unsigned char *ds, *dp, *de;
5405
5406 if (!fptr->wbuf.ptr) {
5407 unsigned char buf[1024];
5408
5410 while (res == econv_destination_buffer_full) {
5411 ds = dp = buf;
5412 de = buf + sizeof(buf);
5413 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5414 while (dp-ds) {
5415 size_t remaining = dp-ds;
5416 long result = rb_io_write_memory(fptr, ds, remaining);
5417
5418 if (result > 0) {
5419 ds += result;
5420 if ((size_t)result == remaining) break;
5421 }
5422 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5423 if (fptr->fd < 0)
5424 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5425 }
5426 else {
5427 return noalloc ? Qtrue : INT2NUM(errno);
5428 }
5429 }
5430 if (res == econv_invalid_byte_sequence ||
5431 res == econv_incomplete_input ||
5433 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5434 }
5435 }
5436
5437 return Qnil;
5438 }
5439
5441 while (res == econv_destination_buffer_full) {
5442 if (fptr->wbuf.len == fptr->wbuf.capa) {
5443 if (io_fflush(fptr) < 0) {
5444 return noalloc ? Qtrue : INT2NUM(errno);
5445 }
5446 }
5447
5448 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5449 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5450 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5451 fptr->wbuf.len += (int)(dp - ds);
5452 if (res == econv_invalid_byte_sequence ||
5453 res == econv_incomplete_input ||
5455 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5456 }
5457 }
5458 return Qnil;
5459}
5460
5462 rb_io_t *fptr;
5463 int noalloc;
5464};
5465
5466static VALUE
5467finish_writeconv_sync(VALUE arg)
5468{
5469 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5470 return finish_writeconv(p->fptr, p->noalloc);
5471}
5472
5473static void*
5474nogvl_close(void *ptr)
5475{
5476 int *fd = ptr;
5477
5478 return (void*)(intptr_t)close(*fd);
5479}
5480
5481static int
5482maygvl_close(int fd, int keepgvl)
5483{
5484 if (keepgvl)
5485 return close(fd);
5486
5487 /*
5488 * close() may block for certain file types (NFS, SO_LINGER sockets,
5489 * inotify), so let other threads run.
5490 */
5491 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5492}
5493
5494static void*
5495nogvl_fclose(void *ptr)
5496{
5497 FILE *file = ptr;
5498
5499 return (void*)(intptr_t)fclose(file);
5500}
5501
5502static int
5503maygvl_fclose(FILE *file, int keepgvl)
5504{
5505 if (keepgvl)
5506 return fclose(file);
5507
5508 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5509}
5510
5511static void free_io_buffer(rb_io_buffer_t *buf);
5512
5513static void
5514fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5515{
5516 VALUE error = Qnil;
5517 int fd = fptr->fd;
5518 FILE *stdio_file = fptr->stdio_file;
5519 int mode = fptr->mode;
5520
5521 if (fptr->writeconv) {
5522 if (!NIL_P(fptr->write_lock) && !noraise) {
5523 struct finish_writeconv_arg arg;
5524 arg.fptr = fptr;
5525 arg.noalloc = noraise;
5526 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5527 }
5528 else {
5529 error = finish_writeconv(fptr, noraise);
5530 }
5531 }
5532 if (fptr->wbuf.len) {
5533 if (noraise) {
5534 io_flush_buffer_sync(fptr);
5535 }
5536 else {
5537 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5538 error = INT2NUM(errno);
5539 }
5540 }
5541 }
5542
5543 int done = 0;
5544
5545 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5546 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5547 done = 1;
5548 }
5549
5550 fptr->fd = -1;
5551 fptr->stdio_file = 0;
5553
5554 // wait for blocking operations to ensure they do not hit EBADF:
5555 rb_thread_io_close_wait(fptr);
5556
5557 // Disable for now.
5558 // if (!done && fd >= 0) {
5559 // VALUE scheduler = rb_fiber_scheduler_current();
5560 // if (scheduler != Qnil) {
5561 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5562 // if (!UNDEF_P(result)) done = 1;
5563 // }
5564 // }
5565
5566 if (!done && stdio_file) {
5567 // stdio_file is deallocated anyway even if fclose failed.
5568 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5569 if (!noraise) {
5570 error = INT2NUM(errno);
5571 }
5572 }
5573
5574 done = 1;
5575 }
5576
5577 if (!done && fd >= 0) {
5578 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5579 // We assumes it is closed.
5580
5581 keepgvl |= !(mode & FMODE_WRITABLE);
5582 keepgvl |= noraise;
5583 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5584 if (!noraise) {
5585 error = INT2NUM(errno);
5586 }
5587 }
5588
5589 done = 1;
5590 }
5591
5592 if (!NIL_P(error) && !noraise) {
5593 if (RB_INTEGER_TYPE_P(error))
5594 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5595 else
5596 rb_exc_raise(error);
5597 }
5598}
5599
5600static void
5601fptr_finalize(rb_io_t *fptr, int noraise)
5602{
5603 fptr_finalize_flush(fptr, noraise, FALSE);
5604 free_io_buffer(&fptr->rbuf);
5605 free_io_buffer(&fptr->wbuf);
5606 clear_codeconv(fptr);
5607}
5608
5609static void
5610rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5611{
5612 if (fptr->finalize) {
5613 (*fptr->finalize)(fptr, noraise);
5614 }
5615 else {
5616 fptr_finalize(fptr, noraise);
5617 }
5618}
5619
5620static void
5621free_io_buffer(rb_io_buffer_t *buf)
5622{
5623 if (buf->ptr) {
5624 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5625 buf->ptr = NULL;
5626 }
5627}
5628
5629static void
5630clear_readconv(rb_io_t *fptr)
5631{
5632 if (fptr->readconv) {
5633 rb_econv_close(fptr->readconv);
5634 fptr->readconv = NULL;
5635 }
5636 free_io_buffer(&fptr->cbuf);
5637}
5638
5639static void
5640clear_writeconv(rb_io_t *fptr)
5641{
5642 if (fptr->writeconv) {
5644 fptr->writeconv = NULL;
5645 }
5646 fptr->writeconv_initialized = 0;
5647}
5648
5649static void
5650clear_codeconv(rb_io_t *fptr)
5651{
5652 clear_readconv(fptr);
5653 clear_writeconv(fptr);
5654}
5655
5656static void
5657rb_io_fptr_cleanup_all(rb_io_t *fptr)
5658{
5659 fptr->pathv = Qnil;
5660 if (0 <= fptr->fd)
5661 rb_io_fptr_cleanup(fptr, TRUE);
5662 fptr->write_lock = Qnil;
5663 free_io_buffer(&fptr->rbuf);
5664 free_io_buffer(&fptr->wbuf);
5665 clear_codeconv(fptr);
5666}
5667
5668int
5670{
5671 if (!io) return 0;
5672 rb_io_fptr_cleanup_all(io);
5673 free(io);
5674
5675 return 1;
5676}
5677
5678size_t
5679rb_io_memsize(const rb_io_t *io)
5680{
5681 size_t size = sizeof(rb_io_t);
5682 size += io->rbuf.capa;
5683 size += io->wbuf.capa;
5684 size += io->cbuf.capa;
5685 if (io->readconv) size += rb_econv_memsize(io->readconv);
5686 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5687
5688 struct rb_io_blocking_operation *blocking_operation = 0;
5689
5690 // 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.
5691 rb_serial_t fork_generation = GET_VM()->fork_gen;
5692 if (io->fork_generation == fork_generation) {
5693 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5694 size += sizeof(struct rb_io_blocking_operation);
5695 }
5696 }
5697
5698 return size;
5699}
5700
5701#ifdef _WIN32
5702/* keep GVL while closing to prevent crash on Windows */
5703# define KEEPGVL TRUE
5704#else
5705# define KEEPGVL FALSE
5706#endif
5707
5708static rb_io_t *
5709io_close_fptr(VALUE io)
5710{
5711 rb_io_t *fptr;
5712 VALUE write_io;
5713 rb_io_t *write_fptr;
5714
5715 write_io = GetWriteIO(io);
5716 if (io != write_io) {
5717 write_fptr = RFILE(write_io)->fptr;
5718 if (write_fptr && 0 <= write_fptr->fd) {
5719 rb_io_fptr_cleanup(write_fptr, TRUE);
5720 }
5721 }
5722
5723 fptr = RFILE(io)->fptr;
5724 if (!fptr) return 0;
5725 if (fptr->fd < 0) return 0;
5726
5727 if (rb_thread_io_close_interrupt(fptr)) {
5728 /* calls close(fptr->fd): */
5729 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5730 }
5731 rb_io_fptr_cleanup(fptr, FALSE);
5732 return fptr;
5733}
5734
5735static void
5736fptr_waitpid(rb_io_t *fptr, int nohang)
5737{
5738 int status;
5739 if (fptr->pid) {
5740 rb_last_status_clear();
5741 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5742 fptr->pid = 0;
5743 }
5744}
5745
5746VALUE
5748{
5749 rb_io_t *fptr = io_close_fptr(io);
5750 if (fptr) fptr_waitpid(fptr, 0);
5751 return Qnil;
5752}
5753
5754/*
5755 * call-seq:
5756 * close -> nil
5757 *
5758 * Closes the stream for both reading and writing
5759 * if open for either or both; returns +nil+.
5760 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5761 *
5762 * If the stream is open for writing, flushes any buffered writes
5763 * to the operating system before closing.
5764 *
5765 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5766 * (child exit status).
5767 *
5768 * It is not an error to close an IO object that has already been closed.
5769 * It just returns nil.
5770 *
5771 * Example:
5772 *
5773 * IO.popen('ruby', 'r+') do |pipe|
5774 * puts pipe.closed?
5775 * pipe.close
5776 * puts $?
5777 * puts pipe.closed?
5778 * end
5779 *
5780 * Output:
5781 *
5782 * false
5783 * pid 13760 exit 0
5784 * true
5785 *
5786 * Related: IO#close_read, IO#close_write, IO#closed?.
5787 */
5788
5789static VALUE
5790rb_io_close_m(VALUE io)
5791{
5792 rb_io_t *fptr = rb_io_get_fptr(io);
5793 if (fptr->fd < 0) {
5794 return Qnil;
5795 }
5796 rb_io_close(io);
5797 return Qnil;
5798}
5799
5800static VALUE
5801io_call_close(VALUE io)
5802{
5803 rb_check_funcall(io, rb_intern("close"), 0, 0);
5804 return io;
5805}
5806
5807static VALUE
5808ignore_closed_stream(VALUE io, VALUE exc)
5809{
5810 enum {mesg_len = sizeof(closed_stream)-1};
5811 VALUE mesg = rb_attr_get(exc, idMesg);
5812 if (!RB_TYPE_P(mesg, T_STRING) ||
5813 RSTRING_LEN(mesg) != mesg_len ||
5814 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5815 rb_exc_raise(exc);
5816 }
5817 return io;
5818}
5819
5820static VALUE
5821io_close(VALUE io)
5822{
5823 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5824 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5825 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5826 rb_eIOError, (VALUE)0);
5827 return io;
5828}
5829
5830/*
5831 * call-seq:
5832 * closed? -> true or false
5833 *
5834 * Returns +true+ if the stream is closed for both reading and writing,
5835 * +false+ otherwise.
5836 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5837 *
5838 * IO.popen('ruby', 'r+') do |pipe|
5839 * puts pipe.closed?
5840 * pipe.close_read
5841 * puts pipe.closed?
5842 * pipe.close_write
5843 * puts pipe.closed?
5844 * end
5845 *
5846 * Output:
5847 *
5848 * false
5849 * false
5850 * true
5851 *
5852 * Related: IO#close_read, IO#close_write, IO#close.
5853 */
5854VALUE
5856{
5857 rb_io_t *fptr;
5858 VALUE write_io;
5859 rb_io_t *write_fptr;
5860
5861 write_io = GetWriteIO(io);
5862 if (io != write_io) {
5863 write_fptr = RFILE(write_io)->fptr;
5864 if (write_fptr && 0 <= write_fptr->fd) {
5865 return Qfalse;
5866 }
5867 }
5868
5869 fptr = rb_io_get_fptr(io);
5870 return RBOOL(0 > fptr->fd);
5871}
5872
5873/*
5874 * call-seq:
5875 * close_read -> nil
5876 *
5877 * Closes the stream for reading if open for reading;
5878 * returns +nil+.
5879 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5880 *
5881 * If the stream was opened by IO.popen and is also closed for writing,
5882 * sets global variable <tt>$?</tt> (child exit status).
5883 *
5884 * Example:
5885 *
5886 * IO.popen('ruby', 'r+') do |pipe|
5887 * puts pipe.closed?
5888 * pipe.close_write
5889 * puts pipe.closed?
5890 * pipe.close_read
5891 * puts $?
5892 * puts pipe.closed?
5893 * end
5894 *
5895 * Output:
5896 *
5897 * false
5898 * false
5899 * pid 14748 exit 0
5900 * true
5901 *
5902 * Related: IO#close, IO#close_write, IO#closed?.
5903 */
5904
5905static VALUE
5906rb_io_close_read(VALUE io)
5907{
5908 rb_io_t *fptr;
5909 VALUE write_io;
5910
5911 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5912 if (fptr->fd < 0) return Qnil;
5913 if (is_socket(fptr->fd, fptr->pathv)) {
5914#ifndef SHUT_RD
5915# define SHUT_RD 0
5916#endif
5917 if (shutdown(fptr->fd, SHUT_RD) < 0)
5918 rb_sys_fail_path(fptr->pathv);
5919 fptr->mode &= ~FMODE_READABLE;
5920 if (!(fptr->mode & FMODE_WRITABLE))
5921 return rb_io_close(io);
5922 return Qnil;
5923 }
5924
5925 write_io = GetWriteIO(io);
5926 if (io != write_io) {
5927 rb_io_t *wfptr;
5928 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5929 wfptr->pid = fptr->pid;
5930 fptr->pid = 0;
5931 RFILE(io)->fptr = wfptr;
5932 /* bind to write_io temporarily to get rid of memory/fd leak */
5933 fptr->tied_io_for_writing = 0;
5934 RFILE(write_io)->fptr = fptr;
5935 rb_io_fptr_cleanup(fptr, FALSE);
5936 /* should not finalize fptr because another thread may be reading it */
5937 return Qnil;
5938 }
5939
5940 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5941 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5942 }
5943 return rb_io_close(io);
5944}
5945
5946/*
5947 * call-seq:
5948 * close_write -> nil
5949 *
5950 * Closes the stream for writing if open for writing;
5951 * returns +nil+.
5952 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5953 *
5954 * Flushes any buffered writes to the operating system before closing.
5955 *
5956 * If the stream was opened by IO.popen and is also closed for reading,
5957 * sets global variable <tt>$?</tt> (child exit status).
5958 *
5959 * IO.popen('ruby', 'r+') do |pipe|
5960 * puts pipe.closed?
5961 * pipe.close_read
5962 * puts pipe.closed?
5963 * pipe.close_write
5964 * puts $?
5965 * puts pipe.closed?
5966 * end
5967 *
5968 * Output:
5969 *
5970 * false
5971 * false
5972 * pid 15044 exit 0
5973 * true
5974 *
5975 * Related: IO#close, IO#close_read, IO#closed?.
5976 */
5977
5978static VALUE
5979rb_io_close_write(VALUE io)
5980{
5981 rb_io_t *fptr;
5982 VALUE write_io;
5983
5984 write_io = GetWriteIO(io);
5985 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5986 if (fptr->fd < 0) return Qnil;
5987 if (is_socket(fptr->fd, fptr->pathv)) {
5988#ifndef SHUT_WR
5989# define SHUT_WR 1
5990#endif
5991 if (shutdown(fptr->fd, SHUT_WR) < 0)
5992 rb_sys_fail_path(fptr->pathv);
5993 fptr->mode &= ~FMODE_WRITABLE;
5994 if (!(fptr->mode & FMODE_READABLE))
5995 return rb_io_close(write_io);
5996 return Qnil;
5997 }
5998
5999 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6000 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6001 }
6002
6003 if (io != write_io) {
6004 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6005 fptr->tied_io_for_writing = 0;
6006 }
6007 rb_io_close(write_io);
6008 return Qnil;
6009}
6010
6011/*
6012 * call-seq:
6013 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6014 *
6015 * Behaves like IO#seek, except that it:
6016 *
6017 * - Uses low-level system functions.
6018 * - Returns the new position.
6019 *
6020 */
6021
6022static VALUE
6023rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6024{
6025 VALUE offset, ptrname;
6026 int whence = SEEK_SET;
6027 rb_io_t *fptr;
6028 rb_off_t pos;
6029
6030 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6031 whence = interpret_seek_whence(ptrname);
6032 }
6033 pos = NUM2OFFT(offset);
6034 GetOpenFile(io, fptr);
6035 if ((fptr->mode & FMODE_READABLE) &&
6036 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6037 rb_raise(rb_eIOError, "sysseek for buffered IO");
6038 }
6039 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6040 rb_warn("sysseek for buffered IO");
6041 }
6042 errno = 0;
6043 pos = lseek(fptr->fd, pos, whence);
6044 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6045
6046 return OFFT2NUM(pos);
6047}
6048
6049/*
6050 * call-seq:
6051 * syswrite(object) -> integer
6052 *
6053 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6054 * returns the number bytes written.
6055 * If +object+ is not a string is converted via method to_s:
6056 *
6057 * f = File.new('t.tmp', 'w')
6058 * f.syswrite('foo') # => 3
6059 * f.syswrite(30) # => 2
6060 * f.syswrite(:foo) # => 3
6061 * f.close
6062 *
6063 * This methods should not be used with other stream-writer methods.
6064 *
6065 */
6066
6067static VALUE
6068rb_io_syswrite(VALUE io, VALUE str)
6069{
6070 VALUE tmp;
6071 rb_io_t *fptr;
6072 long n, len;
6073 const char *ptr;
6074
6075 if (!RB_TYPE_P(str, T_STRING))
6076 str = rb_obj_as_string(str);
6077
6078 io = GetWriteIO(io);
6079 GetOpenFile(io, fptr);
6081
6082 if (fptr->wbuf.len) {
6083 rb_warn("syswrite for buffered IO");
6084 }
6085
6086 tmp = rb_str_tmp_frozen_acquire(str);
6087 RSTRING_GETMEM(tmp, ptr, len);
6088 n = rb_io_write_memory(fptr, ptr, len);
6089 if (n < 0) rb_sys_fail_path(fptr->pathv);
6090 rb_str_tmp_frozen_release(str, tmp);
6091
6092 return LONG2FIX(n);
6093}
6094
6095/*
6096 * call-seq:
6097 * sysread(maxlen) -> string
6098 * sysread(maxlen, out_string) -> string
6099 *
6100 * Behaves like IO#readpartial, except that it uses low-level system functions.
6101 *
6102 * This method should not be used with other stream-reader methods.
6103 *
6104 */
6105
6106static VALUE
6107rb_io_sysread(int argc, VALUE *argv, VALUE io)
6108{
6109 VALUE len, str;
6110 rb_io_t *fptr;
6111 long n, ilen;
6112 struct io_internal_read_struct iis;
6113 int shrinkable;
6114
6115 rb_scan_args(argc, argv, "11", &len, &str);
6116 ilen = NUM2LONG(len);
6117
6118 shrinkable = io_setstrbuf(&str, ilen);
6119 if (ilen == 0) return str;
6120
6121 GetOpenFile(io, fptr);
6123
6124 if (READ_DATA_BUFFERED(fptr)) {
6125 rb_raise(rb_eIOError, "sysread for buffered IO");
6126 }
6127
6128 rb_io_check_closed(fptr);
6129
6130 io_setstrbuf(&str, ilen);
6131 iis.th = rb_thread_current();
6132 iis.fptr = fptr;
6133 iis.nonblock = 0;
6134 iis.fd = fptr->fd;
6135 iis.buf = RSTRING_PTR(str);
6136 iis.capa = ilen;
6137 iis.timeout = NULL;
6138 n = io_read_memory_locktmp(str, &iis);
6139
6140 if (n < 0) {
6141 rb_sys_fail_path(fptr->pathv);
6142 }
6143
6144 io_set_read_length(str, n, shrinkable);
6145
6146 if (n == 0 && ilen > 0) {
6147 rb_eof_error();
6148 }
6149
6150 return str;
6151}
6152
6154 struct rb_io *io;
6155 int fd;
6156 void *buf;
6157 size_t count;
6158 rb_off_t offset;
6159};
6160
6161static VALUE
6162internal_pread_func(void *_arg)
6163{
6164 struct prdwr_internal_arg *arg = _arg;
6165
6166 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6167}
6168
6169static VALUE
6170pread_internal_call(VALUE _arg)
6171{
6172 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6173
6174 VALUE scheduler = rb_fiber_scheduler_current();
6175 if (scheduler != Qnil) {
6176 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6177
6178 if (!UNDEF_P(result)) {
6180 }
6181 }
6182
6183 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6184}
6185
6186/*
6187 * call-seq:
6188 * pread(maxlen, offset) -> string
6189 * pread(maxlen, offset, out_string) -> string
6190 *
6191 * Behaves like IO#readpartial, except that it:
6192 *
6193 * - Reads at the given +offset+ (in bytes).
6194 * - Disregards, and does not modify, the stream's position
6195 * (see {Position}[rdoc-ref:IO@Position]).
6196 * - Bypasses any user space buffering in the stream.
6197 *
6198 * Because this method does not disturb the stream's state
6199 * (its position, in particular), +pread+ allows multiple threads and processes
6200 * to use the same \IO object for reading at various offsets.
6201 *
6202 * f = File.open('t.txt')
6203 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6204 * f.pos # => 52
6205 * # Read 12 bytes at offset 0.
6206 * f.pread(12, 0) # => "First line\n"
6207 * # Read 9 bytes at offset 8.
6208 * f.pread(9, 8) # => "ne\nSecon"
6209 * f.close
6210 *
6211 * Not available on some platforms.
6212 *
6213 */
6214static VALUE
6215rb_io_pread(int argc, VALUE *argv, VALUE io)
6216{
6217 VALUE len, offset, str;
6218 rb_io_t *fptr;
6219 ssize_t n;
6220 struct prdwr_internal_arg arg;
6221 int shrinkable;
6222
6223 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6224 arg.count = NUM2SIZET(len);
6225 arg.offset = NUM2OFFT(offset);
6226
6227 shrinkable = io_setstrbuf(&str, (long)arg.count);
6228 if (arg.count == 0) return str;
6229 arg.buf = RSTRING_PTR(str);
6230
6231 GetOpenFile(io, fptr);
6233
6234 arg.io = fptr;
6235 arg.fd = fptr->fd;
6236 rb_io_check_closed(fptr);
6237
6238 rb_str_locktmp(str);
6239 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6240
6241 if (n < 0) {
6242 rb_sys_fail_path(fptr->pathv);
6243 }
6244 io_set_read_length(str, n, shrinkable);
6245 if (n == 0 && arg.count > 0) {
6246 rb_eof_error();
6247 }
6248
6249 return str;
6250}
6251
6252static VALUE
6253internal_pwrite_func(void *_arg)
6254{
6255 struct prdwr_internal_arg *arg = _arg;
6256
6257 VALUE scheduler = rb_fiber_scheduler_current();
6258 if (scheduler != Qnil) {
6259 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6260
6261 if (!UNDEF_P(result)) {
6263 }
6264 }
6265
6266
6267 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6268}
6269
6270/*
6271 * call-seq:
6272 * pwrite(object, offset) -> integer
6273 *
6274 * Behaves like IO#write, except that it:
6275 *
6276 * - Writes at the given +offset+ (in bytes).
6277 * - Disregards, and does not modify, the stream's position
6278 * (see {Position}[rdoc-ref:IO@Position]).
6279 * - Bypasses any user space buffering in the stream.
6280 *
6281 * Because this method does not disturb the stream's state
6282 * (its position, in particular), +pwrite+ allows multiple threads and processes
6283 * to use the same \IO object for writing at various offsets.
6284 *
6285 * f = File.open('t.tmp', 'w+')
6286 * # Write 6 bytes at offset 3.
6287 * f.pwrite('ABCDEF', 3) # => 6
6288 * f.rewind
6289 * f.read # => "\u0000\u0000\u0000ABCDEF"
6290 * f.close
6291 *
6292 * Not available on some platforms.
6293 *
6294 */
6295static VALUE
6296rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6297{
6298 rb_io_t *fptr;
6299 ssize_t n;
6300 struct prdwr_internal_arg arg;
6301 VALUE tmp;
6302
6303 if (!RB_TYPE_P(str, T_STRING))
6304 str = rb_obj_as_string(str);
6305
6306 arg.offset = NUM2OFFT(offset);
6307
6308 io = GetWriteIO(io);
6309 GetOpenFile(io, fptr);
6311
6312 arg.io = fptr;
6313 arg.fd = fptr->fd;
6314
6315 tmp = rb_str_tmp_frozen_acquire(str);
6316 arg.buf = RSTRING_PTR(tmp);
6317 arg.count = (size_t)RSTRING_LEN(tmp);
6318
6319 n = (ssize_t)rb_io_blocking_region_wait(fptr, internal_pwrite_func, &arg, RUBY_IO_WRITABLE);
6320 if (n < 0) rb_sys_fail_path(fptr->pathv);
6321 rb_str_tmp_frozen_release(str, tmp);
6322
6323 return SSIZET2NUM(n);
6324}
6325
6326VALUE
6328{
6329 rb_io_t *fptr;
6330
6331 GetOpenFile(io, fptr);
6332 if (fptr->readconv)
6334 if (fptr->writeconv)
6336 fptr->mode |= FMODE_BINMODE;
6337 fptr->mode &= ~FMODE_TEXTMODE;
6338 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6339#ifdef O_BINARY
6340 if (!fptr->readconv) {
6341 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6342 }
6343 else {
6344 setmode(fptr->fd, O_BINARY);
6345 }
6346#endif
6347 return io;
6348}
6349
6350static void
6351io_ascii8bit_binmode(rb_io_t *fptr)
6352{
6353 if (fptr->readconv) {
6354 rb_econv_close(fptr->readconv);
6355 fptr->readconv = NULL;
6356 }
6357 if (fptr->writeconv) {
6359 fptr->writeconv = NULL;
6360 }
6361 fptr->mode |= FMODE_BINMODE;
6362 fptr->mode &= ~FMODE_TEXTMODE;
6363 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6364
6365 fptr->encs.enc = rb_ascii8bit_encoding();
6366 fptr->encs.enc2 = NULL;
6367 fptr->encs.ecflags = 0;
6368 fptr->encs.ecopts = Qnil;
6369 clear_codeconv(fptr);
6370}
6371
6372VALUE
6374{
6375 rb_io_t *fptr;
6376
6377 GetOpenFile(io, fptr);
6378 io_ascii8bit_binmode(fptr);
6379
6380 return io;
6381}
6382
6383/*
6384 * call-seq:
6385 * binmode -> self
6386 *
6387 * Sets the stream's data mode as binary
6388 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6389 *
6390 * A stream's data mode may not be changed from binary to text.
6391 *
6392 */
6393
6394static VALUE
6395rb_io_binmode_m(VALUE io)
6396{
6397 VALUE write_io;
6398
6400
6401 write_io = GetWriteIO(io);
6402 if (write_io != io)
6403 rb_io_ascii8bit_binmode(write_io);
6404 return io;
6405}
6406
6407/*
6408 * call-seq:
6409 * binmode? -> true or false
6410 *
6411 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6412 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6413 *
6414 */
6415static VALUE
6416rb_io_binmode_p(VALUE io)
6417{
6418 rb_io_t *fptr;
6419 GetOpenFile(io, fptr);
6420 return RBOOL(fptr->mode & FMODE_BINMODE);
6421}
6422
6423static const char*
6424rb_io_fmode_modestr(enum rb_io_mode fmode)
6425{
6426 if (fmode & FMODE_APPEND) {
6427 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6428 return MODE_BTMODE("a+", "ab+", "at+");
6429 }
6430 return MODE_BTMODE("a", "ab", "at");
6431 }
6432 switch (fmode & FMODE_READWRITE) {
6433 default:
6434 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6435 case FMODE_READABLE:
6436 return MODE_BTMODE("r", "rb", "rt");
6437 case FMODE_WRITABLE:
6438 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6439 case FMODE_READWRITE:
6440 if (fmode & FMODE_CREATE) {
6441 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6442 }
6443 return MODE_BTMODE("r+", "rb+", "rt+");
6444 }
6445}
6446
6447static const char bom_prefix[] = "bom|";
6448static const char utf_prefix[] = "utf-";
6449enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6450enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6451
6452static int
6453io_encname_bom_p(const char *name, long len)
6454{
6455 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6456}
6457
6458enum rb_io_mode
6459rb_io_modestr_fmode(const char *modestr)
6460{
6461 enum rb_io_mode fmode = 0;
6462 const char *m = modestr, *p = NULL;
6463
6464 switch (*m++) {
6465 case 'r':
6466 fmode |= FMODE_READABLE;
6467 break;
6468 case 'w':
6470 break;
6471 case 'a':
6473 break;
6474 default:
6475 goto error;
6476 }
6477
6478 while (*m) {
6479 switch (*m++) {
6480 case 'b':
6481 fmode |= FMODE_BINMODE;
6482 break;
6483 case 't':
6484 fmode |= FMODE_TEXTMODE;
6485 break;
6486 case '+':
6487 fmode |= FMODE_READWRITE;
6488 break;
6489 case 'x':
6490 if (modestr[0] != 'w')
6491 goto error;
6492 fmode |= FMODE_EXCL;
6493 break;
6494 default:
6495 goto error;
6496 case ':':
6497 p = strchr(m, ':');
6498 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6499 fmode |= FMODE_SETENC_BY_BOM;
6500 goto finished;
6501 }
6502 }
6503
6504 finished:
6505 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6506 goto error;
6507
6508 return fmode;
6509
6510 error:
6511 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6513}
6514
6515int
6516rb_io_oflags_fmode(int oflags)
6517{
6518 enum rb_io_mode fmode = 0;
6519
6520 switch (oflags & O_ACCMODE) {
6521 case O_RDONLY:
6522 fmode = FMODE_READABLE;
6523 break;
6524 case O_WRONLY:
6525 fmode = FMODE_WRITABLE;
6526 break;
6527 case O_RDWR:
6528 fmode = FMODE_READWRITE;
6529 break;
6530 }
6531
6532 if (oflags & O_APPEND) {
6533 fmode |= FMODE_APPEND;
6534 }
6535 if (oflags & O_TRUNC) {
6536 fmode |= FMODE_TRUNC;
6537 }
6538 if (oflags & O_CREAT) {
6539 fmode |= FMODE_CREATE;
6540 }
6541 if (oflags & O_EXCL) {
6542 fmode |= FMODE_EXCL;
6543 }
6544#ifdef O_BINARY
6545 if (oflags & O_BINARY) {
6546 fmode |= FMODE_BINMODE;
6547 }
6548#endif
6549
6550 return fmode;
6551}
6552
6553static int
6554rb_io_fmode_oflags(enum rb_io_mode fmode)
6555{
6556 int oflags = 0;
6557
6558 switch (fmode & FMODE_READWRITE) {
6559 case FMODE_READABLE:
6560 oflags |= O_RDONLY;
6561 break;
6562 case FMODE_WRITABLE:
6563 oflags |= O_WRONLY;
6564 break;
6565 case FMODE_READWRITE:
6566 oflags |= O_RDWR;
6567 break;
6568 }
6569
6570 if (fmode & FMODE_APPEND) {
6571 oflags |= O_APPEND;
6572 }
6573 if (fmode & FMODE_TRUNC) {
6574 oflags |= O_TRUNC;
6575 }
6576 if (fmode & FMODE_CREATE) {
6577 oflags |= O_CREAT;
6578 }
6579 if (fmode & FMODE_EXCL) {
6580 oflags |= O_EXCL;
6581 }
6582#ifdef O_BINARY
6583 if (fmode & FMODE_BINMODE) {
6584 oflags |= O_BINARY;
6585 }
6586#endif
6587
6588 return oflags;
6589}
6590
6591int
6592rb_io_modestr_oflags(const char *modestr)
6593{
6594 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6595}
6596
6597static const char*
6598rb_io_oflags_modestr(int oflags)
6599{
6600#ifdef O_BINARY
6601# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6602#else
6603# define MODE_BINARY(a,b) (a)
6604#endif
6605 int accmode;
6606 if (oflags & O_EXCL) {
6607 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6608 }
6609 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6610 if (oflags & O_APPEND) {
6611 if (accmode == O_WRONLY) {
6612 return MODE_BINARY("a", "ab");
6613 }
6614 if (accmode == O_RDWR) {
6615 return MODE_BINARY("a+", "ab+");
6616 }
6617 }
6618 switch (accmode) {
6619 default:
6620 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6621 case O_RDONLY:
6622 return MODE_BINARY("r", "rb");
6623 case O_WRONLY:
6624 return MODE_BINARY("w", "wb");
6625 case O_RDWR:
6626 if (oflags & O_TRUNC) {
6627 return MODE_BINARY("w+", "wb+");
6628 }
6629 return MODE_BINARY("r+", "rb+");
6630 }
6631}
6632
6633/*
6634 * Convert external/internal encodings to enc/enc2
6635 * NULL => use default encoding
6636 * Qnil => no encoding specified (internal only)
6637 */
6638static void
6639rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6640{
6641 int default_ext = 0;
6642
6643 if (ext == NULL) {
6644 ext = rb_default_external_encoding();
6645 default_ext = 1;
6646 }
6647 if (rb_is_ascii8bit_enc(ext)) {
6648 /* If external is ASCII-8BIT, no transcoding */
6649 intern = NULL;
6650 }
6651 else if (intern == NULL) {
6652 intern = rb_default_internal_encoding();
6653 }
6654 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6655 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6656 /* No internal encoding => use external + no transcoding */
6657 *enc = (default_ext && intern != ext) ? NULL : ext;
6658 *enc2 = NULL;
6659 }
6660 else {
6661 *enc = intern;
6662 *enc2 = ext;
6663 }
6664}
6665
6666static void
6667unsupported_encoding(const char *name, rb_encoding *enc)
6668{
6669 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6670}
6671
6672static void
6673parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6674 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6675{
6676 const char *p;
6677 char encname[ENCODING_MAXNAMELEN+1];
6678 int idx, idx2;
6679 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6680 rb_encoding *ext_enc, *int_enc;
6681 long len;
6682
6683 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6684
6685 p = strrchr(estr, ':');
6686 len = p ? (p++ - estr) : (long)strlen(estr);
6687 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6688 estr += bom_prefix_len;
6689 len -= bom_prefix_len;
6690 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6691 fmode |= FMODE_SETENC_BY_BOM;
6692 }
6693 else {
6694 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6695 fmode &= ~FMODE_SETENC_BY_BOM;
6696 }
6697 }
6698 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6699 idx = -1;
6700 }
6701 else {
6702 if (p) {
6703 memcpy(encname, estr, len);
6704 encname[len] = '\0';
6705 estr = encname;
6706 }
6707 idx = rb_enc_find_index(estr);
6708 }
6709 if (fmode_p) *fmode_p = fmode;
6710
6711 if (idx >= 0)
6712 ext_enc = rb_enc_from_index(idx);
6713 else {
6714 if (idx != -2)
6715 unsupported_encoding(estr, estr_enc);
6716 ext_enc = NULL;
6717 }
6718
6719 int_enc = NULL;
6720 if (p) {
6721 if (*p == '-' && *(p+1) == '\0') {
6722 /* Special case - "-" => no transcoding */
6723 int_enc = (rb_encoding *)Qnil;
6724 }
6725 else {
6726 idx2 = rb_enc_find_index(p);
6727 if (idx2 < 0)
6728 unsupported_encoding(p, estr_enc);
6729 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6730 int_enc = (rb_encoding *)Qnil;
6731 }
6732 else
6733 int_enc = rb_enc_from_index(idx2);
6734 }
6735 }
6736
6737 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6738}
6739
6740int
6741rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6742{
6743 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6744 int extracted = 0;
6745 rb_encoding *extencoding = NULL;
6746 rb_encoding *intencoding = NULL;
6747
6748 if (!NIL_P(opt)) {
6749 VALUE v;
6750 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6751 if (v != Qnil) encoding = v;
6752 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6753 if (v != Qnil) extenc = v;
6754 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6755 if (!UNDEF_P(v)) intenc = v;
6756 }
6757 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6758 if (!NIL_P(ruby_verbose)) {
6759 int idx = rb_to_encoding_index(encoding);
6760 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6761 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6762 encoding, UNDEF_P(extenc) ? "internal" : "external");
6763 }
6764 encoding = Qnil;
6765 }
6766 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6767 extencoding = rb_to_encoding(extenc);
6768 }
6769 if (!UNDEF_P(intenc)) {
6770 if (NIL_P(intenc)) {
6771 /* internal_encoding: nil => no transcoding */
6772 intencoding = (rb_encoding *)Qnil;
6773 }
6774 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6775 char *p = StringValueCStr(tmp);
6776
6777 if (*p == '-' && *(p+1) == '\0') {
6778 /* Special case - "-" => no transcoding */
6779 intencoding = (rb_encoding *)Qnil;
6780 }
6781 else {
6782 intencoding = rb_to_encoding(intenc);
6783 }
6784 }
6785 else {
6786 intencoding = rb_to_encoding(intenc);
6787 }
6788 if (extencoding == intencoding) {
6789 intencoding = (rb_encoding *)Qnil;
6790 }
6791 }
6792 if (!NIL_P(encoding)) {
6793 extracted = 1;
6794 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6795 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6796 enc_p, enc2_p, fmode_p);
6797 }
6798 else {
6799 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6800 }
6801 }
6802 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6803 extracted = 1;
6804 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6805 }
6806 return extracted;
6807}
6808
6809static void
6810validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6811{
6812 enum rb_io_mode fmode = *fmode_p;
6813
6814 if ((fmode & FMODE_READABLE) &&
6815 !enc2 &&
6816 !(fmode & FMODE_BINMODE) &&
6817 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6818 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6819
6820 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6821 rb_raise(rb_eArgError, "newline decorator with binary mode");
6822 }
6823 if (!(fmode & FMODE_BINMODE) &&
6824 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6825 fmode |= FMODE_TEXTMODE;
6826 *fmode_p = fmode;
6827 }
6828#if !DEFAULT_TEXTMODE
6829 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6830 fmode &= ~FMODE_TEXTMODE;
6831 *fmode_p = fmode;
6832 }
6833#endif
6834}
6835
6836static void
6837extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
6838{
6839 if (!NIL_P(opthash)) {
6840 VALUE v;
6841 v = rb_hash_aref(opthash, sym_textmode);
6842 if (!NIL_P(v)) {
6843 if (*fmode & FMODE_TEXTMODE)
6844 rb_raise(rb_eArgError, "textmode specified twice");
6845 if (*fmode & FMODE_BINMODE)
6846 rb_raise(rb_eArgError, "both textmode and binmode specified");
6847 if (RTEST(v))
6848 *fmode |= FMODE_TEXTMODE;
6849 }
6850 v = rb_hash_aref(opthash, sym_binmode);
6851 if (!NIL_P(v)) {
6852 if (*fmode & FMODE_BINMODE)
6853 rb_raise(rb_eArgError, "binmode specified twice");
6854 if (*fmode & FMODE_TEXTMODE)
6855 rb_raise(rb_eArgError, "both textmode and binmode specified");
6856 if (RTEST(v))
6857 *fmode |= FMODE_BINMODE;
6858 }
6859
6860 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6861 rb_raise(rb_eArgError, "both textmode and binmode specified");
6862 }
6863}
6864
6865void
6866rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6867 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
6868{
6869 VALUE vmode;
6870 int oflags;
6871 enum rb_io_mode fmode;
6872 rb_encoding *enc, *enc2;
6873 int ecflags;
6874 VALUE ecopts;
6875 int has_enc = 0, has_vmode = 0;
6876 VALUE intmode;
6877
6878 vmode = *vmode_p;
6879
6880 /* Set to defaults */
6881 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6882
6883 vmode_handle:
6884 if (NIL_P(vmode)) {
6885 fmode = FMODE_READABLE;
6886 oflags = O_RDONLY;
6887 }
6888 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6889 vmode = intmode;
6890 oflags = NUM2INT(intmode);
6891 fmode = rb_io_oflags_fmode(oflags);
6892 }
6893 else {
6894 const char *p;
6895
6896 StringValue(vmode);
6897 p = StringValueCStr(vmode);
6898 fmode = rb_io_modestr_fmode(p);
6899 oflags = rb_io_fmode_oflags(fmode);
6900 p = strchr(p, ':');
6901 if (p) {
6902 has_enc = 1;
6903 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6904 }
6905 else {
6906 rb_encoding *e;
6907
6908 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6909 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6910 }
6911 }
6912
6913 if (NIL_P(opthash)) {
6914 ecflags = (fmode & FMODE_READABLE) ?
6917#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6918 ecflags |= (fmode & FMODE_WRITABLE) ?
6919 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6920 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6921#endif
6922 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6923 ecopts = Qnil;
6924 if (fmode & FMODE_BINMODE) {
6925#ifdef O_BINARY
6926 oflags |= O_BINARY;
6927#endif
6928 if (!has_enc)
6929 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6930 }
6931#if DEFAULT_TEXTMODE
6932 else if (NIL_P(vmode)) {
6933 fmode |= DEFAULT_TEXTMODE;
6934 }
6935#endif
6936 }
6937 else {
6938 VALUE v;
6939 if (!has_vmode) {
6940 v = rb_hash_aref(opthash, sym_mode);
6941 if (!NIL_P(v)) {
6942 if (!NIL_P(vmode)) {
6943 rb_raise(rb_eArgError, "mode specified twice");
6944 }
6945 has_vmode = 1;
6946 vmode = v;
6947 goto vmode_handle;
6948 }
6949 }
6950 v = rb_hash_aref(opthash, sym_flags);
6951 if (!NIL_P(v)) {
6952 v = rb_to_int(v);
6953 oflags |= NUM2INT(v);
6954 vmode = INT2NUM(oflags);
6955 fmode = rb_io_oflags_fmode(oflags);
6956 }
6957 extract_binmode(opthash, &fmode);
6958 if (fmode & FMODE_BINMODE) {
6959#ifdef O_BINARY
6960 oflags |= O_BINARY;
6961#endif
6962 if (!has_enc)
6963 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6964 }
6965#if DEFAULT_TEXTMODE
6966 else if (NIL_P(vmode)) {
6967 fmode |= DEFAULT_TEXTMODE;
6968 }
6969#endif
6970 v = rb_hash_aref(opthash, sym_perm);
6971 if (!NIL_P(v)) {
6972 if (vperm_p) {
6973 if (!NIL_P(*vperm_p)) {
6974 rb_raise(rb_eArgError, "perm specified twice");
6975 }
6976 *vperm_p = v;
6977 }
6978 else {
6979 /* perm no use, just ignore */
6980 }
6981 }
6982 ecflags = (fmode & FMODE_READABLE) ?
6985#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6986 ecflags |= (fmode & FMODE_WRITABLE) ?
6987 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6988 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6989#endif
6990
6991 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6992 if (has_enc) {
6993 rb_raise(rb_eArgError, "encoding specified twice");
6994 }
6995 }
6996 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6997 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
6998 }
6999
7000 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7001
7002 *vmode_p = vmode;
7003
7004 *oflags_p = oflags;
7005 *fmode_p = fmode;
7006 convconfig_p->enc = enc;
7007 convconfig_p->enc2 = enc2;
7008 convconfig_p->ecflags = ecflags;
7009 convconfig_p->ecopts = ecopts;
7010}
7011
7013 VALUE fname;
7014 int oflags;
7015 mode_t perm;
7016};
7017
7018static void *
7019sysopen_func(void *ptr)
7020{
7021 const struct sysopen_struct *data = ptr;
7022 const char *fname = RSTRING_PTR(data->fname);
7023 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7024}
7025
7026static inline int
7027rb_sysopen_internal(struct sysopen_struct *data)
7028{
7029 int fd;
7030 do {
7031 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7032 } while (fd < 0 && errno == EINTR);
7033 if (0 <= fd)
7034 rb_update_max_fd(fd);
7035 return fd;
7036}
7037
7038static int
7039rb_sysopen(VALUE fname, int oflags, mode_t perm)
7040{
7041 int fd = -1;
7042 struct sysopen_struct data;
7043
7044 data.fname = rb_str_encode_ospath(fname);
7045 StringValueCStr(data.fname);
7046 data.oflags = oflags;
7047 data.perm = perm;
7048
7049 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7050 rb_syserr_fail_path(first_errno, fname);
7051 }
7052 return fd;
7053}
7054
7055static inline FILE *
7056fdopen_internal(int fd, const char *modestr)
7057{
7058 FILE *file;
7059
7060#if defined(__sun)
7061 errno = 0;
7062#endif
7063 file = fdopen(fd, modestr);
7064 if (!file) {
7065#ifdef _WIN32
7066 if (errno == 0) errno = EINVAL;
7067#elif defined(__sun)
7068 if (errno == 0) errno = EMFILE;
7069#endif
7070 }
7071 return file;
7072}
7073
7074FILE *
7075rb_fdopen(int fd, const char *modestr)
7076{
7077 FILE *file = 0;
7078
7079 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7080 rb_syserr_fail(first_errno, 0);
7081 }
7082
7083 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7084#ifdef USE_SETVBUF
7085 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7086 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7087#endif
7088 return file;
7089}
7090
7091static int
7092io_check_tty(rb_io_t *fptr)
7093{
7094 int t = isatty(fptr->fd);
7095 if (t)
7096 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7097 return t;
7098}
7099
7100static VALUE rb_io_internal_encoding(VALUE);
7101static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7102
7103static int
7104io_strip_bom(VALUE io)
7105{
7106 VALUE b1, b2, b3, b4;
7107 rb_io_t *fptr;
7108
7109 GetOpenFile(io, fptr);
7110 if (!(fptr->mode & FMODE_READABLE)) return 0;
7111 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7112 switch (b1) {
7113 case INT2FIX(0xEF):
7114 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7115 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7116 if (b3 == INT2FIX(0xBF)) {
7117 return rb_utf8_encindex();
7118 }
7119 rb_io_ungetbyte(io, b3);
7120 }
7121 rb_io_ungetbyte(io, b2);
7122 break;
7123
7124 case INT2FIX(0xFE):
7125 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7126 if (b2 == INT2FIX(0xFF)) {
7127 return ENCINDEX_UTF_16BE;
7128 }
7129 rb_io_ungetbyte(io, b2);
7130 break;
7131
7132 case INT2FIX(0xFF):
7133 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7134 if (b2 == INT2FIX(0xFE)) {
7135 b3 = rb_io_getbyte(io);
7136 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7137 if (b4 == INT2FIX(0)) {
7138 return ENCINDEX_UTF_32LE;
7139 }
7140 rb_io_ungetbyte(io, b4);
7141 }
7142 rb_io_ungetbyte(io, b3);
7143 return ENCINDEX_UTF_16LE;
7144 }
7145 rb_io_ungetbyte(io, b2);
7146 break;
7147
7148 case INT2FIX(0):
7149 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7150 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7151 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7152 if (b4 == INT2FIX(0xFF)) {
7153 return ENCINDEX_UTF_32BE;
7154 }
7155 rb_io_ungetbyte(io, b4);
7156 }
7157 rb_io_ungetbyte(io, b3);
7158 }
7159 rb_io_ungetbyte(io, b2);
7160 break;
7161 }
7162 rb_io_ungetbyte(io, b1);
7163 return 0;
7164}
7165
7166static rb_encoding *
7167io_set_encoding_by_bom(VALUE io)
7168{
7169 int idx = io_strip_bom(io);
7170 rb_io_t *fptr;
7171 rb_encoding *extenc = NULL;
7172
7173 GetOpenFile(io, fptr);
7174 if (idx) {
7175 extenc = rb_enc_from_index(idx);
7176 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7177 rb_io_internal_encoding(io), Qnil);
7178 }
7179 else {
7180 fptr->encs.enc2 = NULL;
7181 }
7182 return extenc;
7183}
7184
7185static VALUE
7186rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7187 const struct rb_io_encoding *convconfig, mode_t perm)
7188{
7189 VALUE pathv;
7190 rb_io_t *fptr;
7191 struct rb_io_encoding cc;
7192 if (!convconfig) {
7193 /* Set to default encodings */
7194 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7195 cc.ecflags = 0;
7196 cc.ecopts = Qnil;
7197 convconfig = &cc;
7198 }
7199 validate_enc_binmode(&fmode, convconfig->ecflags,
7200 convconfig->enc, convconfig->enc2);
7201
7202 MakeOpenFile(io, fptr);
7203 fptr->mode = fmode;
7204 fptr->encs = *convconfig;
7205 pathv = rb_str_new_frozen(filename);
7206#ifdef O_TMPFILE
7207 if (!(oflags & O_TMPFILE)) {
7208 fptr->pathv = pathv;
7209 }
7210#else
7211 fptr->pathv = pathv;
7212#endif
7213 fptr->fd = rb_sysopen(pathv, oflags, perm);
7214 io_check_tty(fptr);
7215 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7216
7217 return io;
7218}
7219
7220static VALUE
7221rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7222{
7223 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7224 const char *p = strchr(modestr, ':');
7225 struct rb_io_encoding convconfig;
7226
7227 if (p) {
7228 parse_mode_enc(p+1, rb_usascii_encoding(),
7229 &convconfig.enc, &convconfig.enc2, &fmode);
7230 }
7231 else {
7232 rb_encoding *e;
7233 /* Set to default encodings */
7234
7235 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7236 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7237 }
7238
7239 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7242#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7243 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7244 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7245 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7246#endif
7247 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7248 convconfig.ecopts = Qnil;
7249
7250 return rb_file_open_generic(io, filename,
7251 rb_io_fmode_oflags(fmode),
7252 fmode,
7253 &convconfig,
7254 0666);
7255}
7256
7257VALUE
7258rb_file_open_str(VALUE fname, const char *modestr)
7259{
7260 FilePathValue(fname);
7261 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7262}
7263
7264VALUE
7265rb_file_open(const char *fname, const char *modestr)
7266{
7267 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7268}
7269
7270#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7271static struct pipe_list {
7272 rb_io_t *fptr;
7273 struct pipe_list *next;
7274} *pipe_list;
7275
7276static void
7277pipe_add_fptr(rb_io_t *fptr)
7278{
7279 struct pipe_list *list;
7280
7281 list = ALLOC(struct pipe_list);
7282 list->fptr = fptr;
7283 list->next = pipe_list;
7284 pipe_list = list;
7285}
7286
7287static void
7288pipe_del_fptr(rb_io_t *fptr)
7289{
7290 struct pipe_list **prev = &pipe_list;
7291 struct pipe_list *tmp;
7292
7293 while ((tmp = *prev) != 0) {
7294 if (tmp->fptr == fptr) {
7295 *prev = tmp->next;
7296 free(tmp);
7297 return;
7298 }
7299 prev = &tmp->next;
7300 }
7301}
7302
7303#if defined (_WIN32) || defined(__CYGWIN__)
7304static void
7305pipe_atexit(void)
7306{
7307 struct pipe_list *list = pipe_list;
7308 struct pipe_list *tmp;
7309
7310 while (list) {
7311 tmp = list->next;
7312 rb_io_fptr_finalize(list->fptr);
7313 list = tmp;
7314 }
7315}
7316#endif
7317
7318static void
7319pipe_finalize(rb_io_t *fptr, int noraise)
7320{
7321#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7322 int status = 0;
7323 if (fptr->stdio_file) {
7324 status = pclose(fptr->stdio_file);
7325 }
7326 fptr->fd = -1;
7327 fptr->stdio_file = 0;
7328 rb_last_status_set(status, fptr->pid);
7329#else
7330 fptr_finalize(fptr, noraise);
7331#endif
7332 pipe_del_fptr(fptr);
7333}
7334#endif
7335
7336static void
7337fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7338{
7339#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7340 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7341
7342 if (old_finalize == orig->finalize) return;
7343#endif
7344
7345 fptr->finalize = orig->finalize;
7346
7347#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7348 if (old_finalize != pipe_finalize) {
7349 struct pipe_list *list;
7350 for (list = pipe_list; list; list = list->next) {
7351 if (list->fptr == fptr) break;
7352 }
7353 if (!list) pipe_add_fptr(fptr);
7354 }
7355 else {
7356 pipe_del_fptr(fptr);
7357 }
7358#endif
7359}
7360
7361void
7363{
7365 fptr->mode |= FMODE_SYNC;
7366}
7367
7368void
7369rb_io_unbuffered(rb_io_t *fptr)
7370{
7371 rb_io_synchronized(fptr);
7372}
7373
7374int
7375rb_pipe(int *pipes)
7376{
7377 int ret;
7378 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7379 if (ret == 0) {
7380 rb_update_max_fd(pipes[0]);
7381 rb_update_max_fd(pipes[1]);
7382 }
7383 return ret;
7384}
7385
7386#ifdef _WIN32
7387#define HAVE_SPAWNV 1
7388#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7389#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7390#endif
7391
7392#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7393struct popen_arg {
7394 VALUE execarg_obj;
7395 struct rb_execarg *eargp;
7396 int modef;
7397 int pair[2];
7398 int write_pair[2];
7399};
7400#endif
7401
7402#ifdef HAVE_WORKING_FORK
7403# ifndef __EMSCRIPTEN__
7404static void
7405popen_redirect(struct popen_arg *p)
7406{
7407 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7408 close(p->write_pair[1]);
7409 if (p->write_pair[0] != 0) {
7410 dup2(p->write_pair[0], 0);
7411 close(p->write_pair[0]);
7412 }
7413 close(p->pair[0]);
7414 if (p->pair[1] != 1) {
7415 dup2(p->pair[1], 1);
7416 close(p->pair[1]);
7417 }
7418 }
7419 else if (p->modef & FMODE_READABLE) {
7420 close(p->pair[0]);
7421 if (p->pair[1] != 1) {
7422 dup2(p->pair[1], 1);
7423 close(p->pair[1]);
7424 }
7425 }
7426 else {
7427 close(p->pair[1]);
7428 if (p->pair[0] != 0) {
7429 dup2(p->pair[0], 0);
7430 close(p->pair[0]);
7431 }
7432 }
7433}
7434# endif
7435
7436#if defined(__linux__)
7437/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7438 * Since /proc may not be available, linux_get_maxfd is just a hint.
7439 * This function, linux_get_maxfd, must be async-signal-safe.
7440 * I.e. opendir() is not usable.
7441 *
7442 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7443 * However they are easy to re-implement in async-signal-safe manner.
7444 * (Also note that there is missing/memcmp.c.)
7445 */
7446static int
7447linux_get_maxfd(void)
7448{
7449 int fd;
7450 char buf[4096], *p, *np, *e;
7451 ssize_t ss;
7452 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7453 if (fd < 0) return fd;
7454 ss = read(fd, buf, sizeof(buf));
7455 if (ss < 0) goto err;
7456 p = buf;
7457 e = buf + ss;
7458 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7459 (np = memchr(p, '\n', e-p)) != NULL) {
7460 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7461 int fdsize;
7462 p += sizeof("FDSize:")-1;
7463 *np = '\0';
7464 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7465 close(fd);
7466 return fdsize;
7467 }
7468 p = np+1;
7469 }
7470 /* fall through */
7471
7472 err:
7473 close(fd);
7474 return (int)ss;
7475}
7476#endif
7477
7478/* This function should be async-signal-safe. */
7479void
7480rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7481{
7482#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7483 int fd, ret;
7484 int max = (int)max_file_descriptor;
7485# ifdef F_MAXFD
7486 /* F_MAXFD is available since NetBSD 2.0. */
7487 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7488 if (ret != -1)
7489 maxhint = max = ret;
7490# elif defined(__linux__)
7491 ret = linux_get_maxfd();
7492 if (maxhint < ret)
7493 maxhint = ret;
7494 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7495# endif
7496 if (max < maxhint)
7497 max = maxhint;
7498 for (fd = lowfd; fd <= max; fd++) {
7499 if (!NIL_P(noclose_fds) &&
7500 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7501 continue;
7502 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7503 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7504 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7505 }
7506# define CONTIGUOUS_CLOSED_FDS 20
7507 if (ret != -1) {
7508 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7509 max = fd + CONTIGUOUS_CLOSED_FDS;
7510 }
7511 }
7512#endif
7513}
7514
7515# ifndef __EMSCRIPTEN__
7516static int
7517popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7518{
7519 struct popen_arg *p = (struct popen_arg*)pp;
7520
7521 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7522}
7523# endif
7524#endif
7525
7526#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7527static VALUE
7528rb_execarg_fixup_v(VALUE execarg_obj)
7529{
7530 rb_execarg_parent_start(execarg_obj);
7531 return Qnil;
7532}
7533#else
7534char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7535#endif
7536
7537#ifndef __EMSCRIPTEN__
7538static VALUE
7539pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7540 const struct rb_io_encoding *convconfig)
7541{
7542 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7543 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7544 rb_pid_t pid = 0;
7545 rb_io_t *fptr;
7546 VALUE port;
7547 rb_io_t *write_fptr;
7548 VALUE write_port;
7549#if defined(HAVE_WORKING_FORK)
7550 int status;
7551 char errmsg[80] = { '\0' };
7552#endif
7553#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7554 int state;
7555 struct popen_arg arg;
7556#endif
7557 int e = 0;
7558#if defined(HAVE_SPAWNV)
7559# if defined(HAVE_SPAWNVE)
7560# define DO_SPAWN(cmd, args, envp) ((args) ? \
7561 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7562 spawne(P_NOWAIT, (cmd), (envp)))
7563# else
7564# define DO_SPAWN(cmd, args, envp) ((args) ? \
7565 spawnv(P_NOWAIT, (cmd), (args)) : \
7566 spawn(P_NOWAIT, (cmd)))
7567# endif
7568# if !defined(HAVE_WORKING_FORK)
7569 char **args = NULL;
7570# if defined(HAVE_SPAWNVE)
7571 char **envp = NULL;
7572# endif
7573# endif
7574#endif
7575#if !defined(HAVE_WORKING_FORK)
7576 struct rb_execarg sarg, *sargp = &sarg;
7577#endif
7578 FILE *fp = 0;
7579 int fd = -1;
7580 int write_fd = -1;
7581#if !defined(HAVE_WORKING_FORK)
7582 const char *cmd = 0;
7583
7584 if (prog)
7585 cmd = StringValueCStr(prog);
7586#endif
7587
7588#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7589 arg.execarg_obj = execarg_obj;
7590 arg.eargp = eargp;
7591 arg.modef = fmode;
7592 arg.pair[0] = arg.pair[1] = -1;
7593 arg.write_pair[0] = arg.write_pair[1] = -1;
7594# if !defined(HAVE_WORKING_FORK)
7595 if (eargp && !eargp->use_shell) {
7596 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7597 }
7598# endif
7599 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7601 if (rb_pipe(arg.write_pair) < 0)
7602 rb_sys_fail_str(prog);
7603 if (rb_pipe(arg.pair) < 0) {
7604 e = errno;
7605 close(arg.write_pair[0]);
7606 close(arg.write_pair[1]);
7607 rb_syserr_fail_str(e, prog);
7608 }
7609 if (eargp) {
7610 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7611 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7612 }
7613 break;
7614 case FMODE_READABLE:
7615 if (rb_pipe(arg.pair) < 0)
7616 rb_sys_fail_str(prog);
7617 if (eargp)
7618 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7619 break;
7620 case FMODE_WRITABLE:
7621 if (rb_pipe(arg.pair) < 0)
7622 rb_sys_fail_str(prog);
7623 if (eargp)
7624 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7625 break;
7626 default:
7627 rb_sys_fail_str(prog);
7628 }
7629 if (!NIL_P(execarg_obj)) {
7630 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7631 if (state) {
7632 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7633 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7634 if (0 <= arg.pair[0]) close(arg.pair[0]);
7635 if (0 <= arg.pair[1]) close(arg.pair[1]);
7636 rb_execarg_parent_end(execarg_obj);
7637 rb_jump_tag(state);
7638 }
7639
7640# if defined(HAVE_WORKING_FORK)
7641 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7642# else
7643 rb_execarg_run_options(eargp, sargp, NULL, 0);
7644# if defined(HAVE_SPAWNVE)
7645 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7646# endif
7647 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7648 /* exec failed */
7649 switch (e = errno) {
7650 case EAGAIN:
7651# if EWOULDBLOCK != EAGAIN
7652 case EWOULDBLOCK:
7653# endif
7654 rb_thread_sleep(1);
7655 continue;
7656 }
7657 break;
7658 }
7659 if (eargp)
7660 rb_execarg_run_options(sargp, NULL, NULL, 0);
7661# endif
7662 rb_execarg_parent_end(execarg_obj);
7663 }
7664 else {
7665# if defined(HAVE_WORKING_FORK)
7666 pid = rb_call_proc__fork();
7667 if (pid == 0) { /* child */
7668 popen_redirect(&arg);
7669 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7670 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7671 return Qnil;
7672 }
7673# else
7675# endif
7676 }
7677
7678 /* parent */
7679 if (pid < 0) {
7680# if defined(HAVE_WORKING_FORK)
7681 e = errno;
7682# endif
7683 close(arg.pair[0]);
7684 close(arg.pair[1]);
7686 close(arg.write_pair[0]);
7687 close(arg.write_pair[1]);
7688 }
7689# if defined(HAVE_WORKING_FORK)
7690 if (errmsg[0])
7691 rb_syserr_fail(e, errmsg);
7692# endif
7693 rb_syserr_fail_str(e, prog);
7694 }
7695 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7696 close(arg.pair[1]);
7697 fd = arg.pair[0];
7698 close(arg.write_pair[0]);
7699 write_fd = arg.write_pair[1];
7700 }
7701 else if (fmode & FMODE_READABLE) {
7702 close(arg.pair[1]);
7703 fd = arg.pair[0];
7704 }
7705 else {
7706 close(arg.pair[0]);
7707 fd = arg.pair[1];
7708 }
7709#else
7710 cmd = rb_execarg_commandline(eargp, &prog);
7711 if (!NIL_P(execarg_obj)) {
7712 rb_execarg_parent_start(execarg_obj);
7713 rb_execarg_run_options(eargp, sargp, NULL, 0);
7714 }
7715 fp = popen(cmd, modestr);
7716 e = errno;
7717 if (eargp) {
7718 rb_execarg_parent_end(execarg_obj);
7719 rb_execarg_run_options(sargp, NULL, NULL, 0);
7720 }
7721 if (!fp) rb_syserr_fail_path(e, prog);
7722 fd = fileno(fp);
7723#endif
7724
7725 port = io_alloc(rb_cIO);
7726 MakeOpenFile(port, fptr);
7727 fptr->fd = fd;
7728 fptr->stdio_file = fp;
7729 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7730 if (convconfig) {
7731 fptr->encs = *convconfig;
7732#if RUBY_CRLF_ENVIRONMENT
7735 }
7736#endif
7737 }
7738 else {
7739 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7741 }
7742#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7743 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7744 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7745 }
7746#endif
7747 }
7748 fptr->pid = pid;
7749
7750 if (0 <= write_fd) {
7751 write_port = io_alloc(rb_cIO);
7752 MakeOpenFile(write_port, write_fptr);
7753 write_fptr->fd = write_fd;
7754 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7755 fptr->mode &= ~FMODE_WRITABLE;
7756 fptr->tied_io_for_writing = write_port;
7757 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7758 }
7759
7760#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7761 fptr->finalize = pipe_finalize;
7762 pipe_add_fptr(fptr);
7763#endif
7764 return port;
7765}
7766#else
7767static VALUE
7768pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7769 const struct rb_io_encoding *convconfig)
7770{
7771 rb_raise(rb_eNotImpError, "popen() is not available");
7772}
7773#endif
7774
7775static int
7776is_popen_fork(VALUE prog)
7777{
7778 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7779#if !defined(HAVE_WORKING_FORK)
7780 rb_raise(rb_eNotImpError,
7781 "fork() function is unimplemented on this machine");
7782#else
7783 return TRUE;
7784#endif
7785 }
7786 return FALSE;
7787}
7788
7789static VALUE
7790pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
7791 const struct rb_io_encoding *convconfig)
7792{
7793 int argc = 1;
7794 VALUE *argv = &prog;
7795 VALUE execarg_obj = Qnil;
7796
7797 if (!is_popen_fork(prog))
7798 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7799 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7800}
7801
7802static VALUE
7803pipe_close(VALUE io)
7804{
7805 rb_io_t *fptr = io_close_fptr(io);
7806 if (fptr) {
7807 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7808 }
7809 return Qnil;
7810}
7811
7812static VALUE popen_finish(VALUE port, VALUE klass);
7813
7814/*
7815 * call-seq:
7816 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7817 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7818 *
7819 * Executes the given command +cmd+ as a subprocess
7820 * whose $stdin and $stdout are connected to a new stream +io+.
7821 *
7822 * This method has potential security vulnerabilities if called with untrusted input;
7823 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
7824 *
7825 * If no block is given, returns the new stream,
7826 * which depending on given +mode+ may be open for reading, writing, or both.
7827 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7828 *
7829 * If a block is given, the stream is passed to the block
7830 * (again, open for reading, writing, or both);
7831 * when the block exits, the stream is closed,
7832 * the block's value is returned,
7833 * and the global variable <tt>$?</tt> is set to the child's exit status.
7834 *
7835 * Optional argument +mode+ may be any valid \IO mode.
7836 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7837 *
7838 * Required argument +cmd+ determines which of the following occurs:
7839 *
7840 * - The process forks.
7841 * - A specified program runs in a shell.
7842 * - A specified program runs with specified arguments.
7843 * - A specified program runs with specified arguments and a specified +argv0+.
7844 *
7845 * Each of these is detailed below.
7846 *
7847 * The optional hash argument +env+ specifies name/value pairs that are to be added
7848 * to the environment variables for the subprocess:
7849 *
7850 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7851 * pipe.puts 'puts ENV["FOO"]'
7852 * pipe.close_write
7853 * pipe.gets
7854 * end => "bar\n"
7855 *
7856 * Optional keyword arguments +opts+ specify:
7857 *
7858 * - {Open options}[rdoc-ref:IO@Open+Options].
7859 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7860 * - Options for Kernel#spawn.
7861 *
7862 * <b>Forked Process</b>
7863 *
7864 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7865 * IO.popen('-') do |pipe|
7866 * if pipe
7867 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7868 * else
7869 * $stderr.puts "In child, pid is #{$$}\n"
7870 * end
7871 * end
7872 *
7873 * Output:
7874 *
7875 * In parent, child pid is 26253
7876 * In child, pid is 26253
7877 *
7878 * Note that this is not supported on all platforms.
7879 *
7880 * <b>Shell Subprocess</b>
7881 *
7882 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7883 * the program named +cmd+ is run as a shell command:
7884 *
7885 * IO.popen('uname') do |pipe|
7886 * pipe.readlines
7887 * end
7888 *
7889 * Output:
7890 *
7891 * ["Linux\n"]
7892 *
7893 * Another example:
7894 *
7895 * IO.popen('/bin/sh', 'r+') do |pipe|
7896 * pipe.puts('ls')
7897 * pipe.close_write
7898 * $stderr.puts pipe.readlines.size
7899 * end
7900 *
7901 * Output:
7902 *
7903 * 213
7904 *
7905 * <b>Program Subprocess</b>
7906 *
7907 * When argument +cmd+ is an array of strings,
7908 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7909 *
7910 * IO.popen(['du', '..', '.']) do |pipe|
7911 * $stderr.puts pipe.readlines.size
7912 * end
7913 *
7914 * Output:
7915 *
7916 * 1111
7917 *
7918 * <b>Program Subprocess with <tt>argv0</tt></b>
7919 *
7920 * When argument +cmd+ is an array whose first element is a 2-element string array
7921 * and whose remaining elements (if any) are strings:
7922 *
7923 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7924 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7925 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7926 *
7927 * Example (sets <tt>$0</tt> to 'foo'):
7928 *
7929 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7930 *
7931 * <b>Some Special Examples</b>
7932 *
7933 * # Set IO encoding.
7934 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7935 * euc_jp_string = nkf_io.read
7936 * }
7937 *
7938 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7939 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7940 * ls_result_with_error = io.read
7941 * end
7942 *
7943 * # Use mixture of spawn options and IO options.
7944 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7945 * ls_result_with_error = io.read
7946 * end
7947 *
7948 * f = IO.popen("uname")
7949 * p f.readlines
7950 * f.close
7951 * puts "Parent is #{Process.pid}"
7952 * IO.popen("date") {|f| puts f.gets }
7953 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7954 * p $?
7955 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7956 * f.puts "bar"; f.close_write; puts f.gets
7957 * }
7958 *
7959 * Output (from last section):
7960 *
7961 * ["Linux\n"]
7962 * Parent is 21346
7963 * Thu Jan 15 22:41:19 JST 2009
7964 * 21346 is here, f is #<IO:fd 3>
7965 * 21352 is here, f is nil
7966 * #<Process::Status: pid 21352 exit 0>
7967 * <foo>bar;zot;
7968 *
7969 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7970 *
7971 */
7972
7973static VALUE
7974rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7975{
7976 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7977
7978 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7979 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7980 switch (argc) {
7981 case 2:
7982 pmode = argv[1];
7983 case 1:
7984 pname = argv[0];
7985 break;
7986 default:
7987 {
7988 int ex = !NIL_P(opt);
7989 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7990 }
7991 }
7992 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7993}
7994
7995VALUE
7996rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
7997{
7998 const char *modestr;
7999 VALUE tmp, execarg_obj = Qnil;
8000 int oflags;
8001 enum rb_io_mode fmode;
8002 struct rb_io_encoding convconfig;
8003
8004 tmp = rb_check_array_type(pname);
8005 if (!NIL_P(tmp)) {
8006 long len = RARRAY_LEN(tmp);
8007#if SIZEOF_LONG > SIZEOF_INT
8008 if (len > INT_MAX) {
8009 rb_raise(rb_eArgError, "too many arguments");
8010 }
8011#endif
8012 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8013 RB_GC_GUARD(tmp);
8014 }
8015 else {
8016 StringValue(pname);
8017 execarg_obj = Qnil;
8018 if (!is_popen_fork(pname))
8019 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8020 }
8021 if (!NIL_P(execarg_obj)) {
8022 if (!NIL_P(opt))
8023 opt = rb_execarg_extract_options(execarg_obj, opt);
8024 if (!NIL_P(env))
8025 rb_execarg_setenv(execarg_obj, env);
8026 }
8027 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8028 modestr = rb_io_oflags_modestr(oflags);
8029
8030 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8031}
8032
8033static VALUE
8034popen_finish(VALUE port, VALUE klass)
8035{
8036 if (NIL_P(port)) {
8037 /* child */
8038 if (rb_block_given_p()) {
8039 rb_protect(rb_yield, Qnil, NULL);
8040 rb_io_flush(rb_ractor_stdout());
8041 rb_io_flush(rb_ractor_stderr());
8042 _exit(0);
8043 }
8044 return Qnil;
8045 }
8046 RBASIC_SET_CLASS(port, klass);
8047 if (rb_block_given_p()) {
8048 return rb_ensure(rb_yield, port, pipe_close, port);
8049 }
8050 return port;
8051}
8052
8053#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8054struct popen_writer_arg {
8055 char *const *argv;
8056 struct popen_arg popen;
8057};
8058
8059static int
8060exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8061{
8062 struct popen_writer_arg *pw = arg;
8063 pw->popen.modef = FMODE_WRITABLE;
8064 popen_redirect(&pw->popen);
8065 execv(pw->argv[0], pw->argv);
8066 strlcpy(errmsg, strerror(errno), buflen);
8067 return -1;
8068}
8069#endif
8070
8071FILE *
8072ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8073{
8074#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8075# ifdef HAVE_WORKING_FORK
8076 struct popen_writer_arg pw;
8077 int *const write_pair = pw.popen.pair;
8078# else
8079 int write_pair[2];
8080# endif
8081
8082#ifdef HAVE_PIPE2
8083 int result = pipe2(write_pair, O_CLOEXEC);
8084#else
8085 int result = pipe(write_pair);
8086#endif
8087
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
8219/*
8220 * call-seq:
8221 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8222 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8223 *
8224 * Creates an IO object connected to the given file.
8225 *
8226 * This method has potential security vulnerabilities if called with untrusted input;
8227 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
8228 *
8229 * With no block given, file stream is returned:
8230 *
8231 * open('t.txt') # => #<File:t.txt>
8232 *
8233 * With a block given, calls the block with the open file stream,
8234 * then closes the stream:
8235 *
8236 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8237 *
8238 * Output:
8239 *
8240 * #<File:t.txt>
8241 *
8242 * See File.open for details.
8243 *
8244 */
8245
8246static VALUE
8247rb_f_open(int argc, VALUE *argv, VALUE _)
8248{
8249 ID to_open = 0;
8250 int redirect = FALSE;
8251
8252 if (argc >= 1) {
8253 CONST_ID(to_open, "to_open");
8254 if (rb_respond_to(argv[0], to_open)) {
8255 redirect = TRUE;
8256 }
8257 else {
8258 VALUE tmp = argv[0];
8259 FilePathValue(tmp);
8260 if (NIL_P(tmp)) {
8261 redirect = TRUE;
8262 }
8263 else {
8264 argv[0] = tmp;
8265 }
8266 }
8267 }
8268 if (redirect) {
8269 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8270
8271 if (rb_block_given_p()) {
8272 return rb_ensure(rb_yield, io, io_close, io);
8273 }
8274 return io;
8275 }
8276 return rb_io_s_open(argc, argv, rb_cFile);
8277}
8278
8279static VALUE
8280rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8281 const struct rb_io_encoding *convconfig, mode_t perm)
8282{
8283 return rb_file_open_generic(io_alloc(klass), filename,
8284 oflags, fmode, convconfig, perm);
8285}
8286
8287static VALUE
8288rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8289{
8290 int oflags;
8291 enum rb_io_mode fmode;
8292 struct rb_io_encoding convconfig;
8293 mode_t perm;
8294
8295 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8296 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8297 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8298}
8299
8300static VALUE
8301io_reopen(VALUE io, VALUE nfile)
8302{
8303 rb_io_t *fptr, *orig;
8304 int fd, fd2;
8305 rb_off_t pos = 0;
8306
8307 nfile = rb_io_get_io(nfile);
8308 GetOpenFile(io, fptr);
8309 GetOpenFile(nfile, orig);
8310
8311 if (fptr == orig) return io;
8312 if (RUBY_IO_EXTERNAL_P(fptr)) {
8313 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8314 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8315 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8316 rb_raise(rb_eArgError,
8317 "%s can't change access mode from \"%s\" to \"%s\"",
8318 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8319 rb_io_fmode_modestr(orig->mode));
8320 }
8321 }
8322 if (fptr->mode & FMODE_WRITABLE) {
8323 if (io_fflush(fptr) < 0)
8324 rb_sys_fail_on_write(fptr);
8325 }
8326 else {
8327 flush_before_seek(fptr, true);
8328 }
8329 if (orig->mode & FMODE_READABLE) {
8330 pos = io_tell(orig);
8331 }
8332 if (orig->mode & FMODE_WRITABLE) {
8333 if (io_fflush(orig) < 0)
8334 rb_sys_fail_on_write(fptr);
8335 }
8336
8337 /* copy rb_io_t structure */
8338 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8339 fptr->encs = orig->encs;
8340 fptr->pid = orig->pid;
8341 fptr->lineno = orig->lineno;
8342 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8343 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8344 fptr_copy_finalizer(fptr, orig);
8345
8346 fd = fptr->fd;
8347 fd2 = orig->fd;
8348 if (fd != fd2) {
8349 // Interrupt all usage of the old file descriptor:
8350 rb_thread_io_close_interrupt(fptr);
8351 rb_thread_io_close_wait(fptr);
8352
8353 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8354 /* need to keep FILE objects of stdin, stdout and stderr */
8355 if (rb_cloexec_dup2(fd2, fd) < 0)
8356 rb_sys_fail_path(orig->pathv);
8357 rb_update_max_fd(fd);
8358 }
8359 else {
8360 fclose(fptr->stdio_file);
8361 fptr->stdio_file = 0;
8362 fptr->fd = -1;
8363 if (rb_cloexec_dup2(fd2, fd) < 0)
8364 rb_sys_fail_path(orig->pathv);
8365 rb_update_max_fd(fd);
8366 fptr->fd = fd;
8367 }
8368
8369 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8370 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8371 rb_sys_fail_path(fptr->pathv);
8372 }
8373 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8374 rb_sys_fail_path(orig->pathv);
8375 }
8376 }
8377 }
8378
8379 if (fptr->mode & FMODE_BINMODE) {
8380 rb_io_binmode(io);
8381 }
8382
8383 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8384 return io;
8385}
8386
8387#ifdef _WIN32
8388int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8389#else
8390static int
8391rb_freopen(VALUE fname, const char *mode, FILE *fp)
8392{
8393 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8394 RB_GC_GUARD(fname);
8395 return errno;
8396 }
8397 return 0;
8398}
8399#endif
8400
8401/*
8402 * call-seq:
8403 * reopen(other_io) -> self
8404 * reopen(path, mode = 'r', **opts) -> self
8405 *
8406 * Reassociates the stream with another stream,
8407 * which may be of a different class.
8408 * This method may be used to redirect an existing stream
8409 * to a new destination.
8410 *
8411 * With argument +other_io+ given, reassociates with that stream:
8412 *
8413 * # Redirect $stdin from a file.
8414 * f = File.open('t.txt')
8415 * $stdin.reopen(f)
8416 * f.close
8417 *
8418 * # Redirect $stdout to a file.
8419 * f = File.open('t.tmp', 'w')
8420 * $stdout.reopen(f)
8421 * f.close
8422 *
8423 * With argument +path+ given, reassociates with a new stream to that file path:
8424 *
8425 * $stdin.reopen('t.txt')
8426 * $stdout.reopen('t.tmp', 'w')
8427 *
8428 * Optional keyword arguments +opts+ specify:
8429 *
8430 * - {Open Options}[rdoc-ref:IO@Open+Options].
8431 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8432 *
8433 */
8434
8435static VALUE
8436rb_io_reopen(int argc, VALUE *argv, VALUE file)
8437{
8438 VALUE fname, nmode, opt;
8439 int oflags;
8440 rb_io_t *fptr;
8441
8442 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8443 VALUE tmp = rb_io_check_io(fname);
8444 if (!NIL_P(tmp)) {
8445 return io_reopen(file, tmp);
8446 }
8447 }
8448
8449 FilePathValue(fname);
8450 rb_io_taint_check(file);
8451 fptr = RFILE(file)->fptr;
8452 if (!fptr) {
8453 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8454 }
8455
8456 if (!NIL_P(nmode) || !NIL_P(opt)) {
8457 enum rb_io_mode fmode;
8458 struct rb_io_encoding convconfig;
8459
8460 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8461 if (RUBY_IO_EXTERNAL_P(fptr) &&
8462 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8463 (fptr->mode & FMODE_READWRITE)) {
8464 rb_raise(rb_eArgError,
8465 "%s can't change access mode from \"%s\" to \"%s\"",
8466 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8467 rb_io_fmode_modestr(fmode));
8468 }
8469 fptr->mode = fmode;
8470 fptr->encs = convconfig;
8471 }
8472 else {
8473 oflags = rb_io_fmode_oflags(fptr->mode);
8474 }
8475
8476 fptr->pathv = fname;
8477 if (fptr->fd < 0) {
8478 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8479 fptr->stdio_file = 0;
8480 return file;
8481 }
8482
8483 if (fptr->mode & FMODE_WRITABLE) {
8484 if (io_fflush(fptr) < 0)
8485 rb_sys_fail_on_write(fptr);
8486 }
8487 fptr->rbuf.off = fptr->rbuf.len = 0;
8488
8489 if (fptr->stdio_file) {
8490 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8491 rb_io_oflags_modestr(oflags),
8492 fptr->stdio_file);
8493 if (e) rb_syserr_fail_path(e, fptr->pathv);
8494 fptr->fd = fileno(fptr->stdio_file);
8495 rb_fd_fix_cloexec(fptr->fd);
8496#ifdef USE_SETVBUF
8497 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8498 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8499#endif
8500 if (fptr->stdio_file == stderr) {
8501 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8502 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8503 }
8504 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8505 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8506 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8507 }
8508 }
8509 else {
8510 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8511 int err = 0;
8512 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8513 err = errno;
8514 (void)close(tmpfd);
8515 if (err) {
8516 rb_syserr_fail_path(err, fptr->pathv);
8517 }
8518 }
8519
8520 return file;
8521}
8522
8523/* :nodoc: */
8524static VALUE
8525rb_io_init_copy(VALUE dest, VALUE io)
8526{
8527 rb_io_t *fptr, *orig;
8528 int fd;
8529 VALUE write_io;
8530 rb_off_t pos;
8531
8532 io = rb_io_get_io(io);
8533 if (!OBJ_INIT_COPY(dest, io)) return dest;
8534 GetOpenFile(io, orig);
8535 MakeOpenFile(dest, fptr);
8536
8537 rb_io_flush(io);
8538
8539 /* copy rb_io_t structure */
8540 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8541 fptr->encs = orig->encs;
8542 fptr->pid = orig->pid;
8543 fptr->lineno = orig->lineno;
8544 fptr->timeout = orig->timeout;
8545
8546 ccan_list_head_init(&fptr->blocking_operations);
8547 fptr->closing_ec = NULL;
8548 fptr->wakeup_mutex = Qnil;
8549 fptr->fork_generation = GET_VM()->fork_gen;
8550
8551 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8552 fptr_copy_finalizer(fptr, orig);
8553
8554 fd = ruby_dup(orig->fd);
8555 fptr->fd = fd;
8556 pos = io_tell(orig);
8557 if (0 <= pos)
8558 io_seek(fptr, pos, SEEK_SET);
8559 if (fptr->mode & FMODE_BINMODE) {
8560 rb_io_binmode(dest);
8561 }
8562
8563 write_io = GetWriteIO(io);
8564 if (io != write_io) {
8565 write_io = rb_obj_dup(write_io);
8566 fptr->tied_io_for_writing = write_io;
8567 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8568 }
8569
8570 return dest;
8571}
8572
8573/*
8574 * call-seq:
8575 * printf(format_string, *objects) -> nil
8576 *
8577 * Formats and writes +objects+ to the stream.
8578 *
8579 * For details on +format_string+, see
8580 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8581 *
8582 */
8583
8584VALUE
8585rb_io_printf(int argc, const VALUE *argv, VALUE out)
8586{
8587 rb_io_write(out, rb_f_sprintf(argc, argv));
8588 return Qnil;
8589}
8590
8591/*
8592 * call-seq:
8593 * printf(format_string, *objects) -> nil
8594 * printf(io, format_string, *objects) -> nil
8595 *
8596 * Equivalent to:
8597 *
8598 * io.write(sprintf(format_string, *objects))
8599 *
8600 * For details on +format_string+, see
8601 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8602 *
8603 * With the single argument +format_string+, formats +objects+ into the string,
8604 * then writes the formatted string to $stdout:
8605 *
8606 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8607 *
8608 * Output (on $stdout):
8609 *
8610 * 0024 24 24.00#
8611 *
8612 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8613 * then writes the formatted string to +io+:
8614 *
8615 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8616 *
8617 * Output (on $stderr):
8618 *
8619 * 0024 24 24.00# => nil
8620 *
8621 * With no arguments, does nothing.
8622 *
8623 */
8624
8625static VALUE
8626rb_f_printf(int argc, VALUE *argv, VALUE _)
8627{
8628 VALUE out;
8629
8630 if (argc == 0) return Qnil;
8631 if (RB_TYPE_P(argv[0], T_STRING)) {
8632 out = rb_ractor_stdout();
8633 }
8634 else {
8635 out = argv[0];
8636 argv++;
8637 argc--;
8638 }
8639 rb_io_write(out, rb_f_sprintf(argc, argv));
8640
8641 return Qnil;
8642}
8643
8644static void
8645deprecated_str_setter(VALUE val, ID id, VALUE *var)
8646{
8647 rb_str_setter(val, id, &val);
8648 if (!NIL_P(val)) {
8649 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8650 }
8651 *var = val;
8652}
8653
8654static void
8655deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8656{
8657 if (!NIL_P(val)) {
8658 if (!RB_TYPE_P(val, T_STRING)) {
8659 rb_raise(rb_eTypeError, "value of %"PRIsVALUE" must be String", rb_id2str(id));
8660 }
8661 if (rb_str_equal(val, rb_default_rs)) {
8662 val = rb_default_rs;
8663 }
8664 else {
8665 val = rb_str_frozen_bare_string(val);
8666 }
8668 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8669 }
8670 *var = val;
8671}
8672
8673/*
8674 * call-seq:
8675 * print(*objects) -> nil
8676 *
8677 * Writes the given objects to the stream; returns +nil+.
8678 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8679 * (<tt>$\</tt>), if it is not +nil+.
8680 * See {Line IO}[rdoc-ref:IO@Line+IO].
8681 *
8682 * With argument +objects+ given, for each object:
8683 *
8684 * - Converts via its method +to_s+ if not a string.
8685 * - Writes to the stream.
8686 * - If not the last object, writes the output field separator
8687 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8688 *
8689 * With default separators:
8690 *
8691 * f = File.open('t.tmp', 'w+')
8692 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8693 * p $OUTPUT_RECORD_SEPARATOR
8694 * p $OUTPUT_FIELD_SEPARATOR
8695 * f.print(*objects)
8696 * f.rewind
8697 * p f.read
8698 * f.close
8699 *
8700 * Output:
8701 *
8702 * nil
8703 * nil
8704 * "00.00/10+0izerozero"
8705 *
8706 * With specified separators:
8707 *
8708 * $\ = "\n"
8709 * $, = ','
8710 * f.rewind
8711 * f.print(*objects)
8712 * f.rewind
8713 * p f.read
8714 *
8715 * Output:
8716 *
8717 * "0,0.0,0/1,0+0i,zero,zero\n"
8718 *
8719 * With no argument given, writes the content of <tt>$_</tt>
8720 * (which is usually the most recent user input):
8721 *
8722 * f = File.open('t.tmp', 'w+')
8723 * gets # Sets $_ to the most recent user input.
8724 * f.print
8725 * f.close
8726 *
8727 */
8728
8729VALUE
8730rb_io_print(int argc, const VALUE *argv, VALUE out)
8731{
8732 int i;
8733 VALUE line;
8734
8735 /* if no argument given, print `$_' */
8736 if (argc == 0) {
8737 argc = 1;
8738 line = rb_lastline_get();
8739 argv = &line;
8740 }
8741 if (argc > 1 && !NIL_P(rb_output_fs)) {
8742 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8743 }
8744 for (i=0; i<argc; i++) {
8745 if (!NIL_P(rb_output_fs) && i>0) {
8746 rb_io_write(out, rb_output_fs);
8747 }
8748 rb_io_write(out, argv[i]);
8749 }
8750 if (argc > 0 && !NIL_P(rb_output_rs)) {
8751 rb_io_write(out, rb_output_rs);
8752 }
8753
8754 return Qnil;
8755}
8756
8757/*
8758 * call-seq:
8759 * print(*objects) -> nil
8760 *
8761 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8762 * this method is the straightforward way to write to <tt>$stdout</tt>.
8763 *
8764 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8765 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8766 * <tt>$\</tt>), if it is not +nil+.
8767 *
8768 * With argument +objects+ given, for each object:
8769 *
8770 * - Converts via its method +to_s+ if not a string.
8771 * - Writes to <tt>stdout</tt>.
8772 * - If not the last object, writes the output field separator
8773 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8774 *
8775 * With default separators:
8776 *
8777 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8778 * $OUTPUT_RECORD_SEPARATOR
8779 * $OUTPUT_FIELD_SEPARATOR
8780 * print(*objects)
8781 *
8782 * Output:
8783 *
8784 * nil
8785 * nil
8786 * 00.00/10+0izerozero
8787 *
8788 * With specified separators:
8789 *
8790 * $OUTPUT_RECORD_SEPARATOR = "\n"
8791 * $OUTPUT_FIELD_SEPARATOR = ','
8792 * print(*objects)
8793 *
8794 * Output:
8795 *
8796 * 0,0.0,0/1,0+0i,zero,zero
8797 *
8798 * With no argument given, writes the content of <tt>$_</tt>
8799 * (which is usually the most recent user input):
8800 *
8801 * gets # Sets $_ to the most recent user input.
8802 * print # Prints $_.
8803 *
8804 */
8805
8806static VALUE
8807rb_f_print(int argc, const VALUE *argv, VALUE _)
8808{
8809 rb_io_print(argc, argv, rb_ractor_stdout());
8810 return Qnil;
8811}
8812
8813/*
8814 * call-seq:
8815 * putc(object) -> object
8816 *
8817 * Writes a character to the stream.
8818 * See {Character IO}[rdoc-ref:IO@Character+IO].
8819 *
8820 * If +object+ is numeric, converts to integer if necessary,
8821 * then writes the character whose code is the
8822 * least significant byte;
8823 * if +object+ is a string, writes the first character:
8824 *
8825 * $stdout.putc "A"
8826 * $stdout.putc 65
8827 *
8828 * Output:
8829 *
8830 * AA
8831 *
8832 */
8833
8834static VALUE
8835rb_io_putc(VALUE io, VALUE ch)
8836{
8837 VALUE str;
8838 if (RB_TYPE_P(ch, T_STRING)) {
8839 str = rb_str_substr(ch, 0, 1);
8840 }
8841 else {
8842 char c = NUM2CHR(ch);
8843 str = rb_str_new(&c, 1);
8844 }
8845 rb_io_write(io, str);
8846 return ch;
8847}
8848
8849#define forward(obj, id, argc, argv) \
8850 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8851#define forward_public(obj, id, argc, argv) \
8852 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8853#define forward_current(id, argc, argv) \
8854 forward_public(ARGF.current_file, id, argc, argv)
8855
8856/*
8857 * call-seq:
8858 * putc(int) -> int
8859 *
8860 * Equivalent to:
8861 *
8862 * $stdout.putc(int)
8863 *
8864 * See IO#putc for important information regarding multi-byte characters.
8865 *
8866 */
8867
8868static VALUE
8869rb_f_putc(VALUE recv, VALUE ch)
8870{
8871 VALUE r_stdout = rb_ractor_stdout();
8872 if (recv == r_stdout) {
8873 return rb_io_putc(recv, ch);
8874 }
8875 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8876}
8877
8878
8879int
8880rb_str_end_with_asciichar(VALUE str, int c)
8881{
8882 long len = RSTRING_LEN(str);
8883 const char *ptr = RSTRING_PTR(str);
8884 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8885 int n;
8886
8887 if (len == 0) return 0;
8888 if ((n = rb_enc_mbminlen(enc)) == 1) {
8889 return ptr[len - 1] == c;
8890 }
8891 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8892}
8893
8894static VALUE
8895io_puts_ary(VALUE ary, VALUE out, int recur)
8896{
8897 VALUE tmp;
8898 long i;
8899
8900 if (recur) {
8901 tmp = rb_str_new2("[...]");
8902 rb_io_puts(1, &tmp, out);
8903 return Qtrue;
8904 }
8905 ary = rb_check_array_type(ary);
8906 if (NIL_P(ary)) return Qfalse;
8907 for (i=0; i<RARRAY_LEN(ary); i++) {
8908 tmp = RARRAY_AREF(ary, i);
8909 rb_io_puts(1, &tmp, out);
8910 }
8911 return Qtrue;
8912}
8913
8914/*
8915 * call-seq:
8916 * puts(*objects) -> nil
8917 *
8918 * Writes the given +objects+ to the stream, which must be open for writing;
8919 * returns +nil+.\
8920 * Writes a newline after each that does not already end with a newline sequence.
8921 * If called without arguments, writes a newline.
8922 * See {Line IO}[rdoc-ref:IO@Line+IO].
8923 *
8924 * Note that each added newline is the character <tt>"\n"<//tt>,
8925 * not the output record separator (<tt>$\</tt>).
8926 *
8927 * Treatment for each object:
8928 *
8929 * - String: writes the string.
8930 * - Neither string nor array: writes <tt>object.to_s</tt>.
8931 * - Array: writes each element of the array; arrays may be nested.
8932 *
8933 * To keep these examples brief, we define this helper method:
8934 *
8935 * def show(*objects)
8936 * # Puts objects to file.
8937 * f = File.new('t.tmp', 'w+')
8938 * f.puts(objects)
8939 * # Return file content.
8940 * f.rewind
8941 * p f.read
8942 * f.close
8943 * end
8944 *
8945 * # Strings without newlines.
8946 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8947 * # Strings, some with newlines.
8948 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8949 *
8950 * # Neither strings nor arrays:
8951 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8952 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8953 *
8954 * # Array of strings.
8955 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8956 * # Nested arrays.
8957 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8958 *
8959 */
8960
8961VALUE
8962rb_io_puts(int argc, const VALUE *argv, VALUE out)
8963{
8964 VALUE line, args[2];
8965
8966 /* if no argument given, print newline. */
8967 if (argc == 0) {
8968 rb_io_write(out, rb_default_rs);
8969 return Qnil;
8970 }
8971 for (int i = 0; i < argc; i++) {
8972 // Convert the argument to a string:
8973 if (RB_TYPE_P(argv[i], T_STRING)) {
8974 line = argv[i];
8975 }
8976 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8977 continue;
8978 }
8979 else {
8980 line = rb_obj_as_string(argv[i]);
8981 }
8982
8983 // Write the line:
8984 int n = 0;
8985 if (RSTRING_LEN(line) == 0) {
8986 args[n++] = rb_default_rs;
8987 }
8988 else {
8989 args[n++] = line;
8990 if (!rb_str_end_with_asciichar(line, '\n')) {
8991 args[n++] = rb_default_rs;
8992 }
8993 }
8994
8995 rb_io_writev(out, n, args);
8996 }
8997
8998 return Qnil;
8999}
9000
9001/*
9002 * call-seq:
9003 * puts(*objects) -> nil
9004 *
9005 * Equivalent to
9006 *
9007 * $stdout.puts(objects)
9008 */
9009
9010static VALUE
9011rb_f_puts(int argc, VALUE *argv, VALUE recv)
9012{
9013 VALUE r_stdout = rb_ractor_stdout();
9014 if (recv == r_stdout) {
9015 return rb_io_puts(argc, argv, recv);
9016 }
9017 return forward(r_stdout, rb_intern("puts"), argc, argv);
9018}
9019
9020static VALUE
9021rb_p_write(VALUE str)
9022{
9023 VALUE args[2];
9024 args[0] = str;
9025 args[1] = rb_default_rs;
9026 VALUE r_stdout = rb_ractor_stdout();
9027 if (RB_TYPE_P(r_stdout, T_FILE) &&
9028 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9029 io_writev(2, args, r_stdout);
9030 }
9031 else {
9032 rb_io_writev(r_stdout, 2, args);
9033 }
9034 return Qnil;
9035}
9036
9037void
9038rb_p(VALUE obj) /* for debug print within C code */
9039{
9040 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9041}
9042
9043static VALUE
9044rb_p_result(int argc, const VALUE *argv)
9045{
9046 VALUE ret = Qnil;
9047
9048 if (argc == 1) {
9049 ret = argv[0];
9050 }
9051 else if (argc > 1) {
9052 ret = rb_ary_new4(argc, argv);
9053 }
9054 VALUE r_stdout = rb_ractor_stdout();
9055 if (RB_TYPE_P(r_stdout, T_FILE)) {
9056 rb_uninterruptible(rb_io_flush, r_stdout);
9057 }
9058 return ret;
9059}
9060
9061/*
9062 * call-seq:
9063 * p(object) -> obj
9064 * p(*objects) -> array of objects
9065 * p -> nil
9066 *
9067 * For each object +obj+, executes:
9068 *
9069 * $stdout.write(obj.inspect, "\n")
9070 *
9071 * With one object given, returns the object;
9072 * with multiple objects given, returns an array containing the objects;
9073 * with no object given, returns +nil+.
9074 *
9075 * Examples:
9076 *
9077 * r = Range.new(0, 4)
9078 * p r # => 0..4
9079 * p [r, r, r] # => [0..4, 0..4, 0..4]
9080 * p # => nil
9081 *
9082 * Output:
9083 *
9084 * 0..4
9085 * [0..4, 0..4, 0..4]
9086 *
9087 * Kernel#p is designed for debugging purposes.
9088 * Ruby implementations may define Kernel#p to be uninterruptible
9089 * in whole or in part.
9090 * On CRuby, Kernel#p's writing of data is uninterruptible.
9091 */
9092
9093static VALUE
9094rb_f_p(int argc, VALUE *argv, VALUE self)
9095{
9096 int i;
9097 for (i=0; i<argc; i++) {
9098 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9099 rb_uninterruptible(rb_p_write, inspected);
9100 }
9101 return rb_p_result(argc, argv);
9102}
9103
9104/*
9105 * call-seq:
9106 * display(port = $>) -> nil
9107 *
9108 * Writes +self+ on the given port:
9109 *
9110 * 1.display
9111 * "cat".display
9112 * [ 4, 5, 6 ].display
9113 * puts
9114 *
9115 * Output:
9116 *
9117 * 1cat[4, 5, 6]
9118 *
9119 */
9120
9121static VALUE
9122rb_obj_display(int argc, VALUE *argv, VALUE self)
9123{
9124 VALUE out;
9125
9126 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9127 rb_io_write(out, self);
9128
9129 return Qnil;
9130}
9131
9132static int
9133rb_stderr_to_original_p(VALUE err)
9134{
9135 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9136}
9137
9138void
9139rb_write_error2(const char *mesg, long len)
9140{
9141 VALUE out = rb_ractor_stderr();
9142 if (rb_stderr_to_original_p(out)) {
9143#ifdef _WIN32
9144 if (isatty(fileno(stderr))) {
9145 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9146 }
9147#endif
9148 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9149 /* failed to write to stderr, what can we do? */
9150 return;
9151 }
9152 }
9153 else {
9154 rb_io_write(out, rb_str_new(mesg, len));
9155 }
9156}
9157
9158void
9159rb_write_error(const char *mesg)
9160{
9161 rb_write_error2(mesg, strlen(mesg));
9162}
9163
9164void
9165rb_write_error_str(VALUE mesg)
9166{
9167 VALUE out = rb_ractor_stderr();
9168 /* a stopgap measure for the time being */
9169 if (rb_stderr_to_original_p(out)) {
9170 size_t len = (size_t)RSTRING_LEN(mesg);
9171#ifdef _WIN32
9172 if (isatty(fileno(stderr))) {
9173 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9174 }
9175#endif
9176 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9177 RB_GC_GUARD(mesg);
9178 return;
9179 }
9180 }
9181 else {
9182 /* may unlock GVL, and */
9183 rb_io_write(out, mesg);
9184 }
9185}
9186
9187int
9188rb_stderr_tty_p(void)
9189{
9190 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9191 return isatty(fileno(stderr));
9192 return 0;
9193}
9194
9195static void
9196must_respond_to(ID mid, VALUE val, ID id)
9197{
9198 if (!rb_respond_to(val, mid)) {
9199 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9200 rb_id2str(id), rb_id2str(mid),
9201 rb_obj_class(val));
9202 }
9203}
9204
9205static void
9206stdin_setter(VALUE val, ID id, VALUE *ptr)
9207{
9209}
9210
9211static VALUE
9212stdin_getter(ID id, VALUE *ptr)
9213{
9214 return rb_ractor_stdin();
9215}
9216
9217static void
9218stdout_setter(VALUE val, ID id, VALUE *ptr)
9219{
9220 must_respond_to(id_write, val, id);
9222}
9223
9224static VALUE
9225stdout_getter(ID id, VALUE *ptr)
9226{
9227 return rb_ractor_stdout();
9228}
9229
9230static void
9231stderr_setter(VALUE val, ID id, VALUE *ptr)
9232{
9233 must_respond_to(id_write, val, id);
9235}
9236
9237static VALUE
9238stderr_getter(ID id, VALUE *ptr)
9239{
9240 return rb_ractor_stderr();
9241}
9242
9243static VALUE
9244allocate_and_open_new_file(VALUE klass)
9245{
9246 VALUE self = io_alloc(klass);
9247 rb_io_make_open_file(self);
9248 return self;
9249}
9250
9251VALUE
9252rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9253{
9254 int state;
9255 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9256 if (state) {
9257 /* if we raised an exception allocating an IO object, but the caller
9258 intended to transfer ownership of this FD to us, close the fd before
9259 raising the exception. Otherwise, we would leak a FD - the caller
9260 expects GC to close the file, but we never got around to assigning
9261 it to a rb_io. */
9262 if (!(mode & FMODE_EXTERNAL)) {
9263 maygvl_close(descriptor, 0);
9264 }
9265 rb_jump_tag(state);
9266 }
9267
9268
9269 rb_io_t *io = RFILE(self)->fptr;
9270 io->self = self;
9271 io->fd = descriptor;
9272 io->mode = mode;
9273
9274 /* At this point, Ruby fully owns the descriptor, and will close it when
9275 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9276 in the rest of this method. */
9277
9278 if (NIL_P(path)) {
9279 io->pathv = Qnil;
9280 }
9281 else {
9282 StringValue(path);
9283 io->pathv = rb_str_new_frozen(path);
9284 }
9285
9286 io->timeout = timeout;
9287
9288 ccan_list_head_init(&io->blocking_operations);
9289 io->closing_ec = NULL;
9290 io->wakeup_mutex = Qnil;
9291 io->fork_generation = GET_VM()->fork_gen;
9292
9293 if (encoding) {
9294 io->encs = *encoding;
9295 }
9296
9297 rb_update_max_fd(descriptor);
9298
9299 return self;
9300}
9301
9302static VALUE
9303prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9304{
9305 VALUE path_value = Qnil;
9306 rb_encoding *e;
9307 struct rb_io_encoding convconfig;
9308
9309 if (path) {
9310 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9311 }
9312
9313 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9314 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9315 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9318#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9319 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9320 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9321 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9322#endif
9323 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9324 convconfig.ecopts = Qnil;
9325
9326 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9327 rb_io_t*io = RFILE(self)->fptr;
9328
9329 if (!io_check_tty(io)) {
9330#ifdef __CYGWIN__
9331 io->mode |= FMODE_BINMODE;
9332 setmode(fd, O_BINARY);
9333#endif
9334 }
9335
9336 return self;
9337}
9338
9339VALUE
9340rb_io_fdopen(int fd, int oflags, const char *path)
9341{
9342 VALUE klass = rb_cIO;
9343
9344 if (path && strcmp(path, "-")) klass = rb_cFile;
9345 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9346}
9347
9348static VALUE
9349prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9350{
9351 rb_io_t *fptr;
9352 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9353
9354 GetOpenFile(io, fptr);
9356#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9357 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9358 if (fmode & FMODE_READABLE) {
9360 }
9361#endif
9362 fptr->stdio_file = f;
9363
9364 return io;
9365}
9366
9367VALUE
9368rb_io_prep_stdin(void)
9369{
9370 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9371}
9372
9373VALUE
9374rb_io_prep_stdout(void)
9375{
9376 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9377}
9378
9379VALUE
9380rb_io_prep_stderr(void)
9381{
9382 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9383}
9384
9385FILE *
9387{
9388 if (!fptr->stdio_file) {
9389 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9390 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9391 }
9392 return fptr->stdio_file;
9393}
9394
9395static inline void
9396rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9397{
9398 buf->ptr = NULL;
9399 buf->off = 0;
9400 buf->len = 0;
9401 buf->capa = 0;
9402}
9403
9404static inline rb_io_t *
9405rb_io_fptr_new(void)
9406{
9407 rb_io_t *fp = ALLOC(rb_io_t);
9408 fp->self = Qnil;
9409 fp->fd = -1;
9410 fp->stdio_file = NULL;
9411 fp->mode = 0;
9412 fp->pid = 0;
9413 fp->lineno = 0;
9414 fp->pathv = Qnil;
9415 fp->finalize = 0;
9416 rb_io_buffer_init(&fp->wbuf);
9417 rb_io_buffer_init(&fp->rbuf);
9418 rb_io_buffer_init(&fp->cbuf);
9419 fp->readconv = NULL;
9420 fp->writeconv = NULL;
9422 fp->writeconv_pre_ecflags = 0;
9424 fp->writeconv_initialized = 0;
9425 fp->tied_io_for_writing = 0;
9426 fp->encs.enc = NULL;
9427 fp->encs.enc2 = NULL;
9428 fp->encs.ecflags = 0;
9429 fp->encs.ecopts = Qnil;
9430 fp->write_lock = Qnil;
9431 fp->timeout = Qnil;
9432 ccan_list_head_init(&fp->blocking_operations);
9433 fp->closing_ec = NULL;
9434 fp->wakeup_mutex = Qnil;
9435 fp->fork_generation = GET_VM()->fork_gen;
9436 return fp;
9437}
9438
9439rb_io_t *
9440rb_io_make_open_file(VALUE obj)
9441{
9442 rb_io_t *fp = 0;
9443
9444 Check_Type(obj, T_FILE);
9445 if (RFILE(obj)->fptr) {
9446 rb_io_close(obj);
9447 rb_io_fptr_finalize(RFILE(obj)->fptr);
9448 RFILE(obj)->fptr = 0;
9449 }
9450 fp = rb_io_fptr_new();
9451 fp->self = obj;
9452 RFILE(obj)->fptr = fp;
9453 return fp;
9454}
9455
9456static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9457
9458/*
9459 * call-seq:
9460 * IO.new(fd, mode = 'r', **opts) -> io
9461 *
9462 * Creates and returns a new \IO object (file stream) from a file descriptor.
9463 *
9464 * \IO.new may be useful for interaction with low-level libraries.
9465 * For higher-level interactions, it may be simpler to create
9466 * the file stream using File.open.
9467 *
9468 * Argument +fd+ must be a valid file descriptor (integer):
9469 *
9470 * path = 't.tmp'
9471 * fd = IO.sysopen(path) # => 3
9472 * IO.new(fd) # => #<IO:fd 3>
9473 *
9474 * The new \IO object does not inherit encoding
9475 * (because the integer file descriptor does not have an encoding):
9476 *
9477 * fd = IO.sysopen('t.rus', 'rb')
9478 * io = IO.new(fd)
9479 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9480 *
9481 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9482 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9483 *
9484 * IO.new(fd, 'w') # => #<IO:fd 3>
9485 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9486 *
9487 * Optional keyword arguments +opts+ specify:
9488 *
9489 * - {Open Options}[rdoc-ref:IO@Open+Options].
9490 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9491 *
9492 * Examples:
9493 *
9494 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9495 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9496 *
9497 */
9498
9499static VALUE
9500rb_io_initialize(int argc, VALUE *argv, VALUE io)
9501{
9502 VALUE fnum, vmode;
9503 VALUE opt;
9504
9505 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9506 return io_initialize(io, fnum, vmode, opt);
9507}
9508
9509static VALUE
9510io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9511{
9512 rb_io_t *fp;
9513 int fd, oflags = O_RDONLY;
9514 enum rb_io_mode fmode;
9515 struct rb_io_encoding convconfig;
9516#if defined(HAVE_FCNTL) && defined(F_GETFL)
9517 int ofmode;
9518#else
9519 struct stat st;
9520#endif
9521
9522 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9523
9524 fd = NUM2INT(fnum);
9525 if (rb_reserved_fd_p(fd)) {
9526 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9527 }
9528#if defined(HAVE_FCNTL) && defined(F_GETFL)
9529 oflags = fcntl(fd, F_GETFL);
9530 if (oflags == -1) rb_sys_fail(0);
9531#else
9532 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9533#endif
9534 rb_update_max_fd(fd);
9535#if defined(HAVE_FCNTL) && defined(F_GETFL)
9536 ofmode = rb_io_oflags_fmode(oflags);
9537 if (NIL_P(vmode)) {
9538 fmode = ofmode;
9539 }
9540 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9541 VALUE error = INT2FIX(EINVAL);
9543 }
9544#endif
9545 VALUE path = Qnil;
9546
9547 if (!NIL_P(opt)) {
9548 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9549 fmode |= FMODE_EXTERNAL;
9550 }
9551
9552 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9553 if (!NIL_P(path)) {
9554 StringValue(path);
9555 path = rb_str_new_frozen(path);
9556 }
9557 }
9558
9559 MakeOpenFile(io, fp);
9560 fp->self = io;
9561 fp->fd = fd;
9562 fp->mode = fmode;
9563 fp->encs = convconfig;
9564 fp->pathv = path;
9565 fp->timeout = Qnil;
9566 ccan_list_head_init(&fp->blocking_operations);
9567 fp->closing_ec = NULL;
9568 fp->wakeup_mutex = Qnil;
9569 fp->fork_generation = GET_VM()->fork_gen;
9570 clear_codeconv(fp);
9571 io_check_tty(fp);
9572 if (fileno(stdin) == fd)
9573 fp->stdio_file = stdin;
9574 else if (fileno(stdout) == fd)
9575 fp->stdio_file = stdout;
9576 else if (fileno(stderr) == fd)
9577 fp->stdio_file = stderr;
9578
9579 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9580 return io;
9581}
9582
9583/*
9584 * call-seq:
9585 * set_encoding_by_bom -> encoding or nil
9586 *
9587 * If the stream begins with a BOM
9588 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9589 * consumes the BOM and sets the external encoding accordingly;
9590 * returns the result encoding if found, or +nil+ otherwise:
9591 *
9592 * File.write('t.tmp', "\u{FEFF}abc")
9593 * io = File.open('t.tmp', 'rb')
9594 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9595 * io.close
9596 *
9597 * File.write('t.tmp', 'abc')
9598 * io = File.open('t.tmp', 'rb')
9599 * io.set_encoding_by_bom # => nil
9600 * io.close
9601 *
9602 * Raises an exception if the stream is not binmode
9603 * or its encoding has already been set.
9604 *
9605 */
9606
9607static VALUE
9608rb_io_set_encoding_by_bom(VALUE io)
9609{
9610 rb_io_t *fptr;
9611
9612 GetOpenFile(io, fptr);
9613 if (!(fptr->mode & FMODE_BINMODE)) {
9614 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9615 }
9616 if (fptr->encs.enc2) {
9617 rb_raise(rb_eArgError, "encoding conversion is set");
9618 }
9619 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9620 rb_raise(rb_eArgError, "encoding is set to %s already",
9621 rb_enc_name(fptr->encs.enc));
9622 }
9623 if (!io_set_encoding_by_bom(io)) return Qnil;
9624 return rb_enc_from_encoding(fptr->encs.enc);
9625}
9626
9627/*
9628 * call-seq:
9629 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9630 *
9631 * Opens the file at the given +path+ according to the given +mode+;
9632 * creates and returns a new File object for that file.
9633 *
9634 * The new File object is buffered mode (or non-sync mode), unless
9635 * +filename+ is a tty.
9636 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9637 *
9638 * Argument +path+ must be a valid file path:
9639 *
9640 * f = File.new('/etc/fstab')
9641 * f.close
9642 * f = File.new('t.txt')
9643 * f.close
9644 *
9645 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9646 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9647 *
9648 * f = File.new('t.tmp', 'w')
9649 * f.close
9650 * f = File.new('t.tmp', File::RDONLY)
9651 * f.close
9652 *
9653 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9654 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9655 *
9656 * f = File.new('t.tmp', File::CREAT, 0644)
9657 * f.close
9658 * f = File.new('t.tmp', File::CREAT, 0444)
9659 * f.close
9660 *
9661 * Optional keyword arguments +opts+ specify:
9662 *
9663 * - {Open Options}[rdoc-ref:IO@Open+Options].
9664 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9665 *
9666 */
9667
9668static VALUE
9669rb_file_initialize(int argc, VALUE *argv, VALUE io)
9670{
9671 if (RFILE(io)->fptr) {
9672 rb_raise(rb_eRuntimeError, "reinitializing File");
9673 }
9674 VALUE fname, vmode, vperm, opt;
9675 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9676 if (posargc < 3) { /* perm is File only */
9677 VALUE fd = rb_check_to_int(fname);
9678
9679 if (!NIL_P(fd)) {
9680 return io_initialize(io, fd, vmode, opt);
9681 }
9682 }
9683 return rb_open_file(io, fname, vmode, vperm, opt);
9684}
9685
9686/* :nodoc: */
9687static VALUE
9688rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9689{
9690 if (rb_block_given_p()) {
9691 VALUE cname = rb_obj_as_string(klass);
9692
9693 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9694 cname, cname);
9695 }
9696 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9697}
9698
9699
9700/*
9701 * call-seq:
9702 * IO.for_fd(fd, mode = 'r', **opts) -> io
9703 *
9704 * Synonym for IO.new.
9705 *
9706 */
9707
9708static VALUE
9709rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9710{
9711 VALUE io = rb_obj_alloc(klass);
9712 rb_io_initialize(argc, argv, io);
9713 return io;
9714}
9715
9716/*
9717 * call-seq:
9718 * ios.autoclose? -> true or false
9719 *
9720 * Returns +true+ if the underlying file descriptor of _ios_ will be
9721 * closed at its finalization or at calling #close, otherwise +false+.
9722 */
9723
9724static VALUE
9725rb_io_autoclose_p(VALUE io)
9726{
9727 rb_io_t *fptr = RFILE(io)->fptr;
9728 rb_io_check_closed(fptr);
9729 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9730}
9731
9732/*
9733 * call-seq:
9734 * io.autoclose = bool -> true or false
9735 *
9736 * Sets auto-close flag.
9737 *
9738 * f = File.open(File::NULL)
9739 * IO.for_fd(f.fileno).close
9740 * f.gets # raises Errno::EBADF
9741 *
9742 * f = File.open(File::NULL)
9743 * g = IO.for_fd(f.fileno)
9744 * g.autoclose = false
9745 * g.close
9746 * f.gets # won't cause Errno::EBADF
9747 */
9748
9749static VALUE
9750rb_io_set_autoclose(VALUE io, VALUE autoclose)
9751{
9752 rb_io_t *fptr;
9753 GetOpenFile(io, fptr);
9754 if (!RTEST(autoclose))
9755 fptr->mode |= FMODE_EXTERNAL;
9756 else
9757 fptr->mode &= ~FMODE_EXTERNAL;
9758 return autoclose;
9759}
9760
9761static VALUE
9762io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9763{
9764 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9765
9766 if (!RB_TEST(result)) {
9767 return Qnil;
9768 }
9769
9770 int mask = RB_NUM2INT(result);
9771
9772 if (mask & event) {
9773 if (return_io)
9774 return io;
9775 else
9776 return result;
9777 }
9778 else {
9779 return Qfalse;
9780 }
9781}
9782
9783/*
9784 * call-seq:
9785 * io.wait_readable -> truthy or falsy
9786 * io.wait_readable(timeout) -> truthy or falsy
9787 *
9788 * Waits until IO is readable and returns a truthy value, or a falsy
9789 * value when times out. Returns a truthy value immediately when
9790 * buffered data is available.
9791 */
9792
9793static VALUE
9794io_wait_readable(int argc, VALUE *argv, VALUE io)
9795{
9796 rb_io_t *fptr;
9797
9798 RB_IO_POINTER(io, fptr);
9800
9801 if (rb_io_read_pending(fptr)) return Qtrue;
9802
9803 rb_check_arity(argc, 0, 1);
9804 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9805
9806 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9807}
9808
9809/*
9810 * call-seq:
9811 * io.wait_writable -> truthy or falsy
9812 * io.wait_writable(timeout) -> truthy or falsy
9813 *
9814 * Waits until IO is writable and returns a truthy value or a falsy
9815 * value when times out.
9816 */
9817static VALUE
9818io_wait_writable(int argc, VALUE *argv, VALUE io)
9819{
9820 rb_io_t *fptr;
9821
9822 RB_IO_POINTER(io, fptr);
9824
9825 rb_check_arity(argc, 0, 1);
9826 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9827
9828 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9829}
9830
9831/*
9832 * call-seq:
9833 * io.wait_priority -> truthy or falsy
9834 * io.wait_priority(timeout) -> truthy or falsy
9835 *
9836 * Waits until IO is priority and returns a truthy value or a falsy
9837 * value when times out. Priority data is sent and received using
9838 * the Socket::MSG_OOB flag and is typically limited to streams.
9839 */
9840static VALUE
9841io_wait_priority(int argc, VALUE *argv, VALUE io)
9842{
9843 rb_io_t *fptr = NULL;
9844
9845 RB_IO_POINTER(io, fptr);
9847
9848 if (rb_io_read_pending(fptr)) return Qtrue;
9849
9850 rb_check_arity(argc, 0, 1);
9851 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9852
9853 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9854}
9855
9856static int
9857wait_mode_sym(VALUE mode)
9858{
9859 if (mode == ID2SYM(rb_intern("r"))) {
9860 return RB_WAITFD_IN;
9861 }
9862 if (mode == ID2SYM(rb_intern("read"))) {
9863 return RB_WAITFD_IN;
9864 }
9865 if (mode == ID2SYM(rb_intern("readable"))) {
9866 return RB_WAITFD_IN;
9867 }
9868 if (mode == ID2SYM(rb_intern("w"))) {
9869 return RB_WAITFD_OUT;
9870 }
9871 if (mode == ID2SYM(rb_intern("write"))) {
9872 return RB_WAITFD_OUT;
9873 }
9874 if (mode == ID2SYM(rb_intern("writable"))) {
9875 return RB_WAITFD_OUT;
9876 }
9877 if (mode == ID2SYM(rb_intern("rw"))) {
9878 return RB_WAITFD_IN|RB_WAITFD_OUT;
9879 }
9880 if (mode == ID2SYM(rb_intern("read_write"))) {
9881 return RB_WAITFD_IN|RB_WAITFD_OUT;
9882 }
9883 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9884 return RB_WAITFD_IN|RB_WAITFD_OUT;
9885 }
9886
9887 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9888}
9889
9890static inline enum rb_io_event
9891io_event_from_value(VALUE value)
9892{
9893 int events = RB_NUM2INT(value);
9894
9895 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9896
9897 return events;
9898}
9899
9900/*
9901 * call-seq:
9902 * io.wait(events, timeout) -> event mask, false or nil
9903 * io.wait(*event_symbols[, timeout]) -> self, true, or false
9904 *
9905 * Waits until the IO becomes ready for the specified events and returns the
9906 * subset of events that become ready, or a falsy value when times out.
9907 *
9908 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9909 * +IO::PRIORITY+.
9910 *
9911 * Returns an event mask (truthy value) immediately when buffered data is
9912 * available.
9913 *
9914 * The second form: if one or more event symbols (+:read+, +:write+, or
9915 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
9916 * corresponding to those symbols. In this form, +timeout+ is optional, the
9917 * order of the arguments is arbitrary, and returns +io+ if any of the
9918 * events is ready.
9919 */
9920
9921static VALUE
9922io_wait(int argc, VALUE *argv, VALUE io)
9923{
9924 VALUE timeout = Qundef;
9925 enum rb_io_event events = 0;
9926 int return_io = 0;
9927
9928 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9929 // We'd prefer to return the actual mask, but this form would return the io itself:
9930 return_io = 1;
9931
9932 // Slow/messy path:
9933 for (int i = 0; i < argc; i += 1) {
9934 if (RB_SYMBOL_P(argv[i])) {
9935 events |= wait_mode_sym(argv[i]);
9936 }
9937 else if (UNDEF_P(timeout)) {
9938 rb_time_interval(timeout = argv[i]);
9939 }
9940 else {
9941 rb_raise(rb_eArgError, "timeout given more than once");
9942 }
9943 }
9944
9945 if (UNDEF_P(timeout)) timeout = Qnil;
9946
9947 if (events == 0) {
9948 events = RUBY_IO_READABLE;
9949 }
9950 }
9951 else /* argc == 2 and neither are symbols */ {
9952 // This is the fast path:
9953 events = io_event_from_value(argv[0]);
9954 timeout = argv[1];
9955 }
9956
9957 if (events & RUBY_IO_READABLE) {
9958 rb_io_t *fptr = NULL;
9959 RB_IO_POINTER(io, fptr);
9960
9961 if (rb_io_read_pending(fptr)) {
9962 // This was the original behaviour:
9963 if (return_io) return Qtrue;
9964 // New behaviour always returns an event mask:
9965 else return RB_INT2NUM(RUBY_IO_READABLE);
9966 }
9967 }
9968
9969 return io_wait_event(io, events, timeout, return_io);
9970}
9971
9972static void
9973argf_mark_and_move(void *ptr)
9974{
9975 struct argf *p = ptr;
9976 rb_gc_mark_and_move(&p->filename);
9977 rb_gc_mark_and_move(&p->current_file);
9978 rb_gc_mark_and_move(&p->argv);
9979 rb_gc_mark_and_move(&p->inplace);
9980 rb_gc_mark_and_move(&p->encs.ecopts);
9981}
9982
9983static size_t
9984argf_memsize(const void *ptr)
9985{
9986 const struct argf *p = ptr;
9987 size_t size = sizeof(*p);
9988 return size;
9989}
9990
9991static const rb_data_type_t argf_type = {
9992 "ARGF",
9993 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
9994 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9995};
9996
9997static inline void
9998argf_init(struct argf *p, VALUE v)
9999{
10000 p->filename = Qnil;
10001 p->current_file = Qnil;
10002 p->lineno = 0;
10003 p->argv = v;
10004}
10005
10006static VALUE
10007argf_alloc(VALUE klass)
10008{
10009 struct argf *p;
10010 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10011
10012 argf_init(p, Qnil);
10013 return argf;
10014}
10015
10016#undef rb_argv
10017
10018/* :nodoc: */
10019static VALUE
10020argf_initialize(VALUE argf, VALUE argv)
10021{
10022 memset(&ARGF, 0, sizeof(ARGF));
10023 argf_init(&ARGF, argv);
10024
10025 return argf;
10026}
10027
10028/* :nodoc: */
10029static VALUE
10030argf_initialize_copy(VALUE argf, VALUE orig)
10031{
10032 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10033 ARGF = argf_of(orig);
10034 ARGF.argv = rb_obj_dup(ARGF.argv);
10035 return argf;
10036}
10037
10038/*
10039 * call-seq:
10040 * ARGF.lineno = integer -> integer
10041 *
10042 * Sets the line number of ARGF as a whole to the given Integer.
10043 *
10044 * ARGF sets the line number automatically as you read data, so normally
10045 * you will not need to set it explicitly. To access the current line number
10046 * use ARGF.lineno.
10047 *
10048 * For example:
10049 *
10050 * ARGF.lineno #=> 0
10051 * ARGF.readline #=> "This is line 1\n"
10052 * ARGF.lineno #=> 1
10053 * ARGF.lineno = 0 #=> 0
10054 * ARGF.lineno #=> 0
10055 */
10056static VALUE
10057argf_set_lineno(VALUE argf, VALUE val)
10058{
10059 ARGF.lineno = NUM2INT(val);
10060 ARGF.last_lineno = ARGF.lineno;
10061 return val;
10062}
10063
10064/*
10065 * call-seq:
10066 * ARGF.lineno -> integer
10067 *
10068 * Returns the current line number of ARGF as a whole. This value
10069 * can be set manually with ARGF.lineno=.
10070 *
10071 * For example:
10072 *
10073 * ARGF.lineno #=> 0
10074 * ARGF.readline #=> "This is line 1\n"
10075 * ARGF.lineno #=> 1
10076 */
10077static VALUE
10078argf_lineno(VALUE argf)
10079{
10080 return INT2FIX(ARGF.lineno);
10081}
10082
10083static VALUE
10084argf_forward(int argc, VALUE *argv, VALUE argf)
10085{
10086 return forward_current(rb_frame_this_func(), argc, argv);
10087}
10088
10089#define next_argv() argf_next_argv(argf)
10090#define ARGF_GENERIC_INPUT_P() \
10091 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10092#define ARGF_FORWARD(argc, argv) do {\
10093 if (ARGF_GENERIC_INPUT_P())\
10094 return argf_forward((argc), (argv), argf);\
10095} while (0)
10096#define NEXT_ARGF_FORWARD(argc, argv) do {\
10097 if (!next_argv()) return Qnil;\
10098 ARGF_FORWARD((argc), (argv));\
10099} while (0)
10100
10101static void
10102argf_close(VALUE argf)
10103{
10104 VALUE file = ARGF.current_file;
10105 if (file == rb_stdin) return;
10106 if (RB_TYPE_P(file, T_FILE)) {
10107 rb_io_set_write_io(file, Qnil);
10108 }
10109 io_close(file);
10110 ARGF.init_p = -1;
10111}
10112
10113static int
10114argf_next_argv(VALUE argf)
10115{
10116 char *fn;
10117 rb_io_t *fptr;
10118 int stdout_binmode = 0;
10119 enum rb_io_mode fmode;
10120
10121 VALUE r_stdout = rb_ractor_stdout();
10122
10123 if (RB_TYPE_P(r_stdout, T_FILE)) {
10124 GetOpenFile(r_stdout, fptr);
10125 if (fptr->mode & FMODE_BINMODE)
10126 stdout_binmode = 1;
10127 }
10128
10129 if (ARGF.init_p == 0) {
10130 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10131 ARGF.next_p = 1;
10132 }
10133 else {
10134 ARGF.next_p = -1;
10135 }
10136 ARGF.init_p = 1;
10137 }
10138 else {
10139 if (NIL_P(ARGF.argv)) {
10140 ARGF.next_p = -1;
10141 }
10142 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10143 ARGF.next_p = 1;
10144 }
10145 }
10146
10147 if (ARGF.next_p == 1) {
10148 if (ARGF.init_p == 1) argf_close(argf);
10149 retry:
10150 if (RARRAY_LEN(ARGF.argv) > 0) {
10151 VALUE filename = rb_ary_shift(ARGF.argv);
10152 FilePathValue(filename);
10153 ARGF.filename = filename;
10154 filename = rb_str_encode_ospath(filename);
10155 fn = StringValueCStr(filename);
10156 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10157 ARGF.current_file = rb_stdin;
10158 if (ARGF.inplace) {
10159 rb_warn("Can't do inplace edit for stdio; skipping");
10160 goto retry;
10161 }
10162 }
10163 else {
10164 VALUE write_io = Qnil;
10165 int fr = rb_sysopen(filename, O_RDONLY, 0);
10166
10167 if (ARGF.inplace) {
10168 struct stat st;
10169#ifndef NO_SAFE_RENAME
10170 struct stat st2;
10171#endif
10172 VALUE str;
10173 int fw;
10174
10175 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10176 rb_io_close(r_stdout);
10177 }
10178 fstat(fr, &st);
10179 str = filename;
10180 if (!NIL_P(ARGF.inplace)) {
10181 VALUE suffix = ARGF.inplace;
10182 str = rb_str_dup(str);
10183 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10184 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10185 rb_enc_get(suffix), 0, Qnil))) {
10186 rb_str_append(str, suffix);
10187 }
10188#ifdef NO_SAFE_RENAME
10189 (void)close(fr);
10190 (void)unlink(RSTRING_PTR(str));
10191 if (rename(fn, RSTRING_PTR(str)) < 0) {
10192 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10193 filename, str, strerror(errno));
10194 goto retry;
10195 }
10196 fr = rb_sysopen(str, O_RDONLY, 0);
10197#else
10198 if (rename(fn, RSTRING_PTR(str)) < 0) {
10199 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10200 filename, str, strerror(errno));
10201 close(fr);
10202 goto retry;
10203 }
10204#endif
10205 }
10206 else {
10207#ifdef NO_SAFE_RENAME
10208 rb_fatal("Can't do inplace edit without backup");
10209#else
10210 if (unlink(fn) < 0) {
10211 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10212 filename, strerror(errno));
10213 close(fr);
10214 goto retry;
10215 }
10216#endif
10217 }
10218 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10219#ifndef NO_SAFE_RENAME
10220 fstat(fw, &st2);
10221#ifdef HAVE_FCHMOD
10222 fchmod(fw, st.st_mode);
10223#else
10224 chmod(fn, st.st_mode);
10225#endif
10226 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10227 int err;
10228#ifdef HAVE_FCHOWN
10229 err = fchown(fw, st.st_uid, st.st_gid);
10230#else
10231 err = chown(fn, st.st_uid, st.st_gid);
10232#endif
10233 if (err && getuid() == 0 && st2.st_uid == 0) {
10234 const char *wkfn = RSTRING_PTR(filename);
10235 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10236 filename, str, strerror(errno));
10237 (void)close(fr);
10238 (void)close(fw);
10239 (void)unlink(wkfn);
10240 goto retry;
10241 }
10242 }
10243#endif
10244 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10245 rb_ractor_stdout_set(write_io);
10246 if (stdout_binmode) rb_io_binmode(rb_stdout);
10247 }
10248 fmode = FMODE_READABLE;
10249 if (!ARGF.binmode) {
10250 fmode |= DEFAULT_TEXTMODE;
10251 }
10252 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10253 if (!NIL_P(write_io)) {
10254 rb_io_set_write_io(ARGF.current_file, write_io);
10255 }
10256 RB_GC_GUARD(filename);
10257 }
10258 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10259 GetOpenFile(ARGF.current_file, fptr);
10260 if (ARGF.encs.enc) {
10261 fptr->encs = ARGF.encs;
10262 clear_codeconv(fptr);
10263 }
10264 else {
10265 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10266 if (!ARGF.binmode) {
10268#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10269 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10270#endif
10271 }
10272 }
10273 ARGF.next_p = 0;
10274 }
10275 else {
10276 ARGF.next_p = 1;
10277 return FALSE;
10278 }
10279 }
10280 else if (ARGF.next_p == -1) {
10281 ARGF.current_file = rb_stdin;
10282 ARGF.filename = rb_str_new2("-");
10283 if (ARGF.inplace) {
10284 rb_warn("Can't do inplace edit for stdio");
10285 rb_ractor_stdout_set(orig_stdout);
10286 }
10287 }
10288 if (ARGF.init_p == -1) ARGF.init_p = 1;
10289 return TRUE;
10290}
10291
10292static VALUE
10293argf_getline(int argc, VALUE *argv, VALUE argf)
10294{
10295 VALUE line;
10296 long lineno = ARGF.lineno;
10297
10298 retry:
10299 if (!next_argv()) return Qnil;
10300 if (ARGF_GENERIC_INPUT_P()) {
10301 line = forward_current(idGets, argc, argv);
10302 }
10303 else {
10304 if (argc == 0 && rb_rs == rb_default_rs) {
10305 line = rb_io_gets(ARGF.current_file);
10306 }
10307 else {
10308 line = rb_io_getline(argc, argv, ARGF.current_file);
10309 }
10310 if (NIL_P(line) && ARGF.next_p != -1) {
10311 argf_close(argf);
10312 ARGF.next_p = 1;
10313 goto retry;
10314 }
10315 }
10316 if (!NIL_P(line)) {
10317 ARGF.lineno = ++lineno;
10318 ARGF.last_lineno = ARGF.lineno;
10319 }
10320 return line;
10321}
10322
10323static VALUE
10324argf_lineno_getter(ID id, VALUE *var)
10325{
10326 VALUE argf = *var;
10327 return INT2FIX(ARGF.last_lineno);
10328}
10329
10330static void
10331argf_lineno_setter(VALUE val, ID id, VALUE *var)
10332{
10333 VALUE argf = *var;
10334 int n = NUM2INT(val);
10335 ARGF.last_lineno = ARGF.lineno = n;
10336}
10337
10338void
10339rb_reset_argf_lineno(long n)
10340{
10341 ARGF.last_lineno = ARGF.lineno = n;
10342}
10343
10344static VALUE argf_gets(int, VALUE *, VALUE);
10345
10346/*
10347 * call-seq:
10348 * gets(sep=$/ [, getline_args]) -> string or nil
10349 * gets(limit [, getline_args]) -> string or nil
10350 * gets(sep, limit [, getline_args]) -> string or nil
10351 *
10352 * Returns (and assigns to <code>$_</code>) the next line from the list
10353 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10354 * no files are present on the command line. Returns +nil+ at end of
10355 * file. The optional argument specifies the record separator. The
10356 * separator is included with the contents of each record. A separator
10357 * of +nil+ reads the entire contents, and a zero-length separator
10358 * reads the input one paragraph at a time, where paragraphs are
10359 * divided by two consecutive newlines. If the first argument is an
10360 * integer, or optional second argument is given, the returning string
10361 * would not be longer than the given value in bytes. If multiple
10362 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10363 * the contents one file at a time.
10364 *
10365 * ARGV << "testfile"
10366 * print while gets
10367 *
10368 * <em>produces:</em>
10369 *
10370 * This is line one
10371 * This is line two
10372 * This is line three
10373 * And so on...
10374 *
10375 * The style of programming using <code>$_</code> as an implicit
10376 * parameter is gradually losing favor in the Ruby community.
10377 */
10378
10379static VALUE
10380rb_f_gets(int argc, VALUE *argv, VALUE recv)
10381{
10382 if (recv == argf) {
10383 return argf_gets(argc, argv, argf);
10384 }
10385 return forward(argf, idGets, argc, argv);
10386}
10387
10388/*
10389 * call-seq:
10390 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10391 * ARGF.gets(limit [, getline_args]) -> string or nil
10392 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10393 *
10394 * Returns the next line from the current file in ARGF.
10395 *
10396 * By default lines are assumed to be separated by <code>$/</code>;
10397 * to use a different character as a separator, supply it as a String
10398 * for the _sep_ argument.
10399 *
10400 * The optional _limit_ argument specifies how many characters of each line
10401 * to return. By default all characters are returned.
10402 *
10403 * See IO.readlines for details about getline_args.
10404 *
10405 */
10406static VALUE
10407argf_gets(int argc, VALUE *argv, VALUE argf)
10408{
10409 VALUE line;
10410
10411 line = argf_getline(argc, argv, argf);
10412 rb_lastline_set(line);
10413
10414 return line;
10415}
10416
10417VALUE
10419{
10420 VALUE line;
10421
10422 if (rb_rs != rb_default_rs) {
10423 return rb_f_gets(0, 0, argf);
10424 }
10425
10426 retry:
10427 if (!next_argv()) return Qnil;
10428 line = rb_io_gets(ARGF.current_file);
10429 if (NIL_P(line) && ARGF.next_p != -1) {
10430 rb_io_close(ARGF.current_file);
10431 ARGF.next_p = 1;
10432 goto retry;
10433 }
10434 rb_lastline_set(line);
10435 if (!NIL_P(line)) {
10436 ARGF.lineno++;
10437 ARGF.last_lineno = ARGF.lineno;
10438 }
10439
10440 return line;
10441}
10442
10443static VALUE argf_readline(int, VALUE *, VALUE);
10444
10445/*
10446 * call-seq:
10447 * readline(sep = $/, chomp: false) -> string
10448 * readline(limit, chomp: false) -> string
10449 * readline(sep, limit, chomp: false) -> string
10450 *
10451 * Equivalent to method Kernel#gets, except that it raises an exception
10452 * if called at end-of-stream:
10453 *
10454 * $ cat t.txt | ruby -e "p readlines; readline"
10455 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10456 * in `readline': end of file reached (EOFError)
10457 *
10458 * Optional keyword argument +chomp+ specifies whether line separators
10459 * are to be omitted.
10460 */
10461
10462static VALUE
10463rb_f_readline(int argc, VALUE *argv, VALUE recv)
10464{
10465 if (recv == argf) {
10466 return argf_readline(argc, argv, argf);
10467 }
10468 return forward(argf, rb_intern("readline"), argc, argv);
10469}
10470
10471
10472/*
10473 * call-seq:
10474 * ARGF.readline(sep=$/) -> string
10475 * ARGF.readline(limit) -> string
10476 * ARGF.readline(sep, limit) -> string
10477 *
10478 * Returns the next line from the current file in ARGF.
10479 *
10480 * By default lines are assumed to be separated by <code>$/</code>;
10481 * to use a different character as a separator, supply it as a String
10482 * for the _sep_ argument.
10483 *
10484 * The optional _limit_ argument specifies how many characters of each line
10485 * to return. By default all characters are returned.
10486 *
10487 * An EOFError is raised at the end of the file.
10488 */
10489static VALUE
10490argf_readline(int argc, VALUE *argv, VALUE argf)
10491{
10492 VALUE line;
10493
10494 if (!next_argv()) rb_eof_error();
10495 ARGF_FORWARD(argc, argv);
10496 line = argf_gets(argc, argv, argf);
10497 if (NIL_P(line)) {
10498 rb_eof_error();
10499 }
10500
10501 return line;
10502}
10503
10504static VALUE argf_readlines(int, VALUE *, VALUE);
10505
10506/*
10507 * call-seq:
10508 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10509 * readlines(limit, chomp: false, **enc_opts) -> array
10510 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10511 *
10512 * Returns an array containing the lines returned by calling
10513 * Kernel#gets until the end-of-stream is reached;
10514 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10515 *
10516 * With only string argument +sep+ given,
10517 * returns the remaining lines as determined by line separator +sep+,
10518 * or +nil+ if none;
10519 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10520 *
10521 * # Default separator.
10522 * $ cat t.txt | ruby -e "p readlines"
10523 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10524 *
10525 * # Specified separator.
10526 * $ cat t.txt | ruby -e "p readlines 'li'"
10527 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10528 *
10529 * # Get-all separator.
10530 * $ cat t.txt | ruby -e "p readlines nil"
10531 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10532 *
10533 * # Get-paragraph separator.
10534 * $ cat t.txt | ruby -e "p readlines ''"
10535 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10536 *
10537 * With only integer argument +limit+ given,
10538 * limits the number of bytes in the line;
10539 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10540 *
10541 * $cat t.txt | ruby -e "p readlines 10"
10542 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10543 *
10544 * $cat t.txt | ruby -e "p readlines 11"
10545 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10546 *
10547 * $cat t.txt | ruby -e "p readlines 12"
10548 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10549 *
10550 * With arguments +sep+ and +limit+ given,
10551 * combines the two behaviors
10552 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10553 *
10554 * Optional keyword argument +chomp+ specifies whether line separators
10555 * are to be omitted:
10556 *
10557 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10558 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10559 *
10560 * Optional keyword arguments +enc_opts+ specify encoding options;
10561 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10562 *
10563 */
10564
10565static VALUE
10566rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10567{
10568 if (recv == argf) {
10569 return argf_readlines(argc, argv, argf);
10570 }
10571 return forward(argf, rb_intern("readlines"), argc, argv);
10572}
10573
10574/*
10575 * call-seq:
10576 * ARGF.readlines(sep = $/, chomp: false) -> array
10577 * ARGF.readlines(limit, chomp: false) -> array
10578 * ARGF.readlines(sep, limit, chomp: false) -> array
10579 *
10580 * ARGF.to_a(sep = $/, chomp: false) -> array
10581 * ARGF.to_a(limit, chomp: false) -> array
10582 * ARGF.to_a(sep, limit, chomp: false) -> array
10583 *
10584 * Reads each file in ARGF in its entirety, returning an Array containing
10585 * lines from the files. Lines are assumed to be separated by _sep_.
10586 *
10587 * lines = ARGF.readlines
10588 * lines[0] #=> "This is line one\n"
10589 *
10590 * See +IO.readlines+ for a full description of all options.
10591 */
10592static VALUE
10593argf_readlines(int argc, VALUE *argv, VALUE argf)
10594{
10595 long lineno = ARGF.lineno;
10596 VALUE lines, ary;
10597
10598 ary = rb_ary_new();
10599 while (next_argv()) {
10600 if (ARGF_GENERIC_INPUT_P()) {
10601 lines = forward_current(rb_intern("readlines"), argc, argv);
10602 }
10603 else {
10604 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10605 argf_close(argf);
10606 }
10607 ARGF.next_p = 1;
10608 rb_ary_concat(ary, lines);
10609 ARGF.lineno = lineno + RARRAY_LEN(ary);
10610 ARGF.last_lineno = ARGF.lineno;
10611 }
10612 ARGF.init_p = 0;
10613 return ary;
10614}
10615
10616/*
10617 * call-seq:
10618 * `command` -> string
10619 *
10620 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10621 * sets global variable <tt>$?</tt> to the process status.
10622 *
10623 * This method has potential security vulnerabilities if called with untrusted input;
10624 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
10625 *
10626 * Examples:
10627 *
10628 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10629 * $ `echo oops && exit 99` # => "oops\n"
10630 * $ $? # => #<Process::Status: pid 17088 exit 99>
10631 * $ $?.exitstatus # => 99
10632 *
10633 * The built-in syntax <tt>%x{...}</tt> uses this method.
10634 *
10635 */
10636
10637static VALUE
10638rb_f_backquote(VALUE obj, VALUE str)
10639{
10640 VALUE port;
10641 VALUE result;
10642 rb_io_t *fptr;
10643
10644 StringValue(str);
10645 rb_last_status_clear();
10646 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10647 if (NIL_P(port)) return rb_str_new(0,0);
10648
10649 GetOpenFile(port, fptr);
10650 result = read_all(fptr, remain_size(fptr), Qnil);
10651 rb_io_close(port);
10652 rb_io_fptr_cleanup_all(fptr);
10653 RB_GC_GUARD(port);
10654
10655 return result;
10656}
10657
10658#ifdef HAVE_SYS_SELECT_H
10659#include <sys/select.h>
10660#endif
10661
10662static VALUE
10663select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10664{
10665 VALUE res, list;
10666 rb_fdset_t *rp, *wp, *ep;
10667 rb_io_t *fptr;
10668 long i;
10669 int max = 0, n;
10670 int pending = 0;
10671 struct timeval timerec;
10672
10673 if (!NIL_P(read)) {
10674 Check_Type(read, T_ARRAY);
10675 for (i=0; i<RARRAY_LEN(read); i++) {
10676 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10677 rb_fd_set(fptr->fd, &fds[0]);
10678 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10679 pending++;
10680 rb_fd_set(fptr->fd, &fds[3]);
10681 }
10682 if (max < fptr->fd) max = fptr->fd;
10683 }
10684 if (pending) { /* no blocking if there's buffered data */
10685 timerec.tv_sec = timerec.tv_usec = 0;
10686 tp = &timerec;
10687 }
10688 rp = &fds[0];
10689 }
10690 else
10691 rp = 0;
10692
10693 if (!NIL_P(write)) {
10694 Check_Type(write, T_ARRAY);
10695 for (i=0; i<RARRAY_LEN(write); i++) {
10696 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10697 GetOpenFile(write_io, fptr);
10698 rb_fd_set(fptr->fd, &fds[1]);
10699 if (max < fptr->fd) max = fptr->fd;
10700 }
10701 wp = &fds[1];
10702 }
10703 else
10704 wp = 0;
10705
10706 if (!NIL_P(except)) {
10707 Check_Type(except, T_ARRAY);
10708 for (i=0; i<RARRAY_LEN(except); i++) {
10709 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10710 VALUE write_io = GetWriteIO(io);
10711 GetOpenFile(io, fptr);
10712 rb_fd_set(fptr->fd, &fds[2]);
10713 if (max < fptr->fd) max = fptr->fd;
10714 if (io != write_io) {
10715 GetOpenFile(write_io, fptr);
10716 rb_fd_set(fptr->fd, &fds[2]);
10717 if (max < fptr->fd) max = fptr->fd;
10718 }
10719 }
10720 ep = &fds[2];
10721 }
10722 else {
10723 ep = 0;
10724 }
10725
10726 max++;
10727
10728 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10729 if (n < 0) {
10730 rb_sys_fail(0);
10731 }
10732 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10733
10734 res = rb_ary_new2(3);
10735 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10736 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10737 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10738
10739 if (rp) {
10740 list = RARRAY_AREF(res, 0);
10741 for (i=0; i< RARRAY_LEN(read); i++) {
10742 VALUE obj = rb_ary_entry(read, i);
10743 VALUE io = rb_io_get_io(obj);
10744 GetOpenFile(io, fptr);
10745 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10746 rb_fd_isset(fptr->fd, &fds[3])) {
10747 rb_ary_push(list, obj);
10748 }
10749 }
10750 }
10751
10752 if (wp) {
10753 list = RARRAY_AREF(res, 1);
10754 for (i=0; i< RARRAY_LEN(write); i++) {
10755 VALUE obj = rb_ary_entry(write, i);
10756 VALUE io = rb_io_get_io(obj);
10757 VALUE write_io = GetWriteIO(io);
10758 GetOpenFile(write_io, fptr);
10759 if (rb_fd_isset(fptr->fd, &fds[1])) {
10760 rb_ary_push(list, obj);
10761 }
10762 }
10763 }
10764
10765 if (ep) {
10766 list = RARRAY_AREF(res, 2);
10767 for (i=0; i< RARRAY_LEN(except); i++) {
10768 VALUE obj = rb_ary_entry(except, i);
10769 VALUE io = rb_io_get_io(obj);
10770 VALUE write_io = GetWriteIO(io);
10771 GetOpenFile(io, fptr);
10772 if (rb_fd_isset(fptr->fd, &fds[2])) {
10773 rb_ary_push(list, obj);
10774 }
10775 else if (io != write_io) {
10776 GetOpenFile(write_io, fptr);
10777 if (rb_fd_isset(fptr->fd, &fds[2])) {
10778 rb_ary_push(list, obj);
10779 }
10780 }
10781 }
10782 }
10783
10784 return res; /* returns an empty array on interrupt */
10785}
10786
10788 VALUE read, write, except;
10789 struct timeval *timeout;
10790 rb_fdset_t fdsets[4];
10791};
10792
10793static VALUE
10794select_call(VALUE arg)
10795{
10796 struct select_args *p = (struct select_args *)arg;
10797
10798 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10799}
10800
10801static VALUE
10802select_end(VALUE arg)
10803{
10804 struct select_args *p = (struct select_args *)arg;
10805 int i;
10806
10807 for (i = 0; i < numberof(p->fdsets); ++i)
10808 rb_fd_term(&p->fdsets[i]);
10809 return Qnil;
10810}
10811
10812static VALUE sym_normal, sym_sequential, sym_random,
10813 sym_willneed, sym_dontneed, sym_noreuse;
10814
10815#ifdef HAVE_POSIX_FADVISE
10816struct io_advise_struct {
10817 int fd;
10818 int advice;
10819 rb_off_t offset;
10820 rb_off_t len;
10821};
10822
10823static VALUE
10824io_advise_internal(void *arg)
10825{
10826 struct io_advise_struct *ptr = arg;
10827 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10828}
10829
10830static VALUE
10831io_advise_sym_to_const(VALUE sym)
10832{
10833#ifdef POSIX_FADV_NORMAL
10834 if (sym == sym_normal)
10835 return INT2NUM(POSIX_FADV_NORMAL);
10836#endif
10837
10838#ifdef POSIX_FADV_RANDOM
10839 if (sym == sym_random)
10840 return INT2NUM(POSIX_FADV_RANDOM);
10841#endif
10842
10843#ifdef POSIX_FADV_SEQUENTIAL
10844 if (sym == sym_sequential)
10845 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10846#endif
10847
10848#ifdef POSIX_FADV_WILLNEED
10849 if (sym == sym_willneed)
10850 return INT2NUM(POSIX_FADV_WILLNEED);
10851#endif
10852
10853#ifdef POSIX_FADV_DONTNEED
10854 if (sym == sym_dontneed)
10855 return INT2NUM(POSIX_FADV_DONTNEED);
10856#endif
10857
10858#ifdef POSIX_FADV_NOREUSE
10859 if (sym == sym_noreuse)
10860 return INT2NUM(POSIX_FADV_NOREUSE);
10861#endif
10862
10863 return Qnil;
10864}
10865
10866static VALUE
10867do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10868{
10869 int rv;
10870 struct io_advise_struct ias;
10871 VALUE num_adv;
10872
10873 num_adv = io_advise_sym_to_const(advice);
10874
10875 /*
10876 * The platform doesn't support this hint. We don't raise exception, instead
10877 * silently ignore it. Because IO::advise is only hint.
10878 */
10879 if (NIL_P(num_adv))
10880 return Qnil;
10881
10882 ias.fd = fptr->fd;
10883 ias.advice = NUM2INT(num_adv);
10884 ias.offset = offset;
10885 ias.len = len;
10886
10887 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10888 if (rv && rv != ENOSYS) {
10889 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10890 it returns the error code. */
10891 VALUE message = rb_sprintf("%"PRIsVALUE" "
10892 "(%"PRI_OFFT_PREFIX"d, "
10893 "%"PRI_OFFT_PREFIX"d, "
10894 "%"PRIsVALUE")",
10895 fptr->pathv, offset, len, advice);
10896 rb_syserr_fail_str(rv, message);
10897 }
10898
10899 return Qnil;
10900}
10901
10902#endif /* HAVE_POSIX_FADVISE */
10903
10904static void
10905advice_arg_check(VALUE advice)
10906{
10907 if (!SYMBOL_P(advice))
10908 rb_raise(rb_eTypeError, "advice must be a Symbol");
10909
10910 if (advice != sym_normal &&
10911 advice != sym_sequential &&
10912 advice != sym_random &&
10913 advice != sym_willneed &&
10914 advice != sym_dontneed &&
10915 advice != sym_noreuse) {
10916 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10917 }
10918}
10919
10920/*
10921 * call-seq:
10922 * advise(advice, offset = 0, len = 0) -> nil
10923 *
10924 * Invokes Posix system call
10925 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10926 * which announces an intention to access data from the current file
10927 * in a particular manner.
10928 *
10929 * The arguments and results are platform-dependent.
10930 *
10931 * The relevant data is specified by:
10932 *
10933 * - +offset+: The offset of the first byte of data.
10934 * - +len+: The number of bytes to be accessed;
10935 * if +len+ is zero, or is larger than the number of bytes remaining,
10936 * all remaining bytes will be accessed.
10937 *
10938 * Argument +advice+ is one of the following symbols:
10939 *
10940 * - +:normal+: The application has no advice to give
10941 * about its access pattern for the specified data.
10942 * If no advice is given for an open file, this is the default assumption.
10943 * - +:sequential+: The application expects to access the specified data sequentially
10944 * (with lower offsets read before higher ones).
10945 * - +:random+: The specified data will be accessed in random order.
10946 * - +:noreuse+: The specified data will be accessed only once.
10947 * - +:willneed+: The specified data will be accessed in the near future.
10948 * - +:dontneed+: The specified data will not be accessed in the near future.
10949 *
10950 * Not implemented on all platforms.
10951 *
10952 */
10953static VALUE
10954rb_io_advise(int argc, VALUE *argv, VALUE io)
10955{
10956 VALUE advice, offset, len;
10957 rb_off_t off, l;
10958 rb_io_t *fptr;
10959
10960 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10961 advice_arg_check(advice);
10962
10963 io = GetWriteIO(io);
10964 GetOpenFile(io, fptr);
10965
10966 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10967 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10968
10969#ifdef HAVE_POSIX_FADVISE
10970 return do_io_advise(fptr, advice, off, l);
10971#else
10972 ((void)off, (void)l); /* Ignore all hint */
10973 return Qnil;
10974#endif
10975}
10976
10977static int
10978is_pos_inf(VALUE x)
10979{
10980 double f;
10981 if (!RB_FLOAT_TYPE_P(x))
10982 return 0;
10983 f = RFLOAT_VALUE(x);
10984 return isinf(f) && 0 < f;
10985}
10986
10987/*
10988 * call-seq:
10989 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
10990 *
10991 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
10992 * which monitors multiple file descriptors,
10993 * waiting until one or more of the file descriptors
10994 * becomes ready for some class of I/O operation.
10995 *
10996 * Not implemented on all platforms.
10997 *
10998 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
10999 * is an array of IO objects.
11000 *
11001 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11002 * interval in seconds.
11003 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11004 * +nil+ and +Float::INFINITY+ means no timeout.
11005 *
11006 * The method monitors the \IO objects given in all three arrays,
11007 * waiting for some to be ready;
11008 * returns a 3-element array whose elements are:
11009 *
11010 * - An array of the objects in +read_ios+ that are ready for reading.
11011 * - An array of the objects in +write_ios+ that are ready for writing.
11012 * - An array of the objects in +error_ios+ have pending exceptions.
11013 *
11014 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11015 *
11016 * \IO.select peeks the buffer of \IO objects for testing readability.
11017 * If the \IO buffer is not empty, \IO.select immediately notifies
11018 * readability. This "peek" only happens for \IO objects. It does not
11019 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11020 *
11021 * The best way to use \IO.select is invoking it after non-blocking
11022 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11023 * raise an exception which is extended by IO::WaitReadable or
11024 * IO::WaitWritable. The modules notify how the caller should wait
11025 * with \IO.select. If IO::WaitReadable is raised, the caller should
11026 * wait for reading. If IO::WaitWritable is raised, the caller should
11027 * wait for writing.
11028 *
11029 * So, blocking read (#readpartial) can be emulated using
11030 * #read_nonblock and \IO.select as follows:
11031 *
11032 * begin
11033 * result = io_like.read_nonblock(maxlen)
11034 * rescue IO::WaitReadable
11035 * IO.select([io_like])
11036 * retry
11037 * rescue IO::WaitWritable
11038 * IO.select(nil, [io_like])
11039 * retry
11040 * end
11041 *
11042 * Especially, the combination of non-blocking methods and \IO.select is
11043 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11044 * has #to_io method to return underlying IO object. IO.select calls
11045 * #to_io to obtain the file descriptor to wait.
11046 *
11047 * This means that readability notified by \IO.select doesn't mean
11048 * readability from OpenSSL::SSL::SSLSocket object.
11049 *
11050 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11051 * some data. \IO.select doesn't see the buffer. So \IO.select can
11052 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11053 *
11054 * However, several more complicated situations exist.
11055 *
11056 * SSL is a protocol which is sequence of records.
11057 * The record consists of multiple bytes.
11058 * So, the remote side of SSL sends a partial record, IO.select
11059 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11060 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11061 *
11062 * Also, the remote side can request SSL renegotiation which forces
11063 * the local SSL engine to write some data.
11064 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11065 * system call and it can block.
11066 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11067 * IO::WaitWritable instead of blocking.
11068 * So, the caller should wait for ready for writability as above
11069 * example.
11070 *
11071 * The combination of non-blocking methods and \IO.select is also useful
11072 * for streams such as tty, pipe socket socket when multiple processes
11073 * read from a stream.
11074 *
11075 * Finally, Linux kernel developers don't guarantee that
11076 * readability of select(2) means readability of following read(2) even
11077 * for a single process;
11078 * see {select(2)}[https://linux.die.net/man/2/select]
11079 *
11080 * Invoking \IO.select before IO#readpartial works well as usual.
11081 * However it is not the best way to use \IO.select.
11082 *
11083 * The writability notified by select(2) doesn't show
11084 * how many bytes are writable.
11085 * IO#write method blocks until given whole string is written.
11086 * So, <tt>IO#write(two or more bytes)</tt> can block after
11087 * writability is notified by \IO.select. IO#write_nonblock is required
11088 * to avoid the blocking.
11089 *
11090 * Blocking write (#write) can be emulated using #write_nonblock and
11091 * IO.select as follows: IO::WaitReadable should also be rescued for
11092 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11093 *
11094 * while 0 < string.bytesize
11095 * begin
11096 * written = io_like.write_nonblock(string)
11097 * rescue IO::WaitReadable
11098 * IO.select([io_like])
11099 * retry
11100 * rescue IO::WaitWritable
11101 * IO.select(nil, [io_like])
11102 * retry
11103 * end
11104 * string = string.byteslice(written..-1)
11105 * end
11106 *
11107 * Example:
11108 *
11109 * rp, wp = IO.pipe
11110 * mesg = "ping "
11111 * 100.times {
11112 * # IO.select follows IO#read. Not the best way to use IO.select.
11113 * rs, ws, = IO.select([rp], [wp])
11114 * if r = rs[0]
11115 * ret = r.read(5)
11116 * print ret
11117 * case ret
11118 * when /ping/
11119 * mesg = "pong\n"
11120 * when /pong/
11121 * mesg = "ping "
11122 * end
11123 * end
11124 * if w = ws[0]
11125 * w.write(mesg)
11126 * end
11127 * }
11128 *
11129 * Output:
11130 *
11131 * ping pong
11132 * ping pong
11133 * ping pong
11134 * (snipped)
11135 * ping
11136 *
11137 */
11138
11139static VALUE
11140rb_f_select(int argc, VALUE *argv, VALUE obj)
11141{
11142 VALUE scheduler = rb_fiber_scheduler_current();
11143 if (scheduler != Qnil) {
11144 // It's optionally supported.
11145 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11146 if (!UNDEF_P(result)) return result;
11147 }
11148
11149 VALUE timeout;
11150 struct select_args args;
11151 struct timeval timerec;
11152 int i;
11153
11154 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11155 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11156 args.timeout = 0;
11157 }
11158 else {
11159 timerec = rb_time_interval(timeout);
11160 args.timeout = &timerec;
11161 }
11162
11163 for (i = 0; i < numberof(args.fdsets); ++i)
11164 rb_fd_init(&args.fdsets[i]);
11165
11166 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11167}
11168
11169#ifdef IOCTL_REQ_TYPE
11170 typedef IOCTL_REQ_TYPE ioctl_req_t;
11171#else
11172 typedef int ioctl_req_t;
11173# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11174#endif
11175
11176#ifdef HAVE_IOCTL
11177struct ioctl_arg {
11178 int fd;
11179 ioctl_req_t cmd;
11180 long narg;
11181};
11182
11183static VALUE
11184nogvl_ioctl(void *ptr)
11185{
11186 struct ioctl_arg *arg = ptr;
11187
11188 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11189}
11190
11191static int
11192do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11193{
11194 int retval;
11195 struct ioctl_arg arg;
11196
11197 arg.fd = io->fd;
11198 arg.cmd = cmd;
11199 arg.narg = narg;
11200
11201 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11202
11203 return retval;
11204}
11205#endif
11206
11207#define DEFAULT_IOCTL_NARG_LEN (256)
11208
11209#if defined(__linux__) && defined(_IOC_SIZE)
11210static long
11211linux_iocparm_len(ioctl_req_t cmd)
11212{
11213 long len;
11214
11215 if ((cmd & 0xFFFF0000) == 0) {
11216 /* legacy and unstructured ioctl number. */
11217 return DEFAULT_IOCTL_NARG_LEN;
11218 }
11219
11220 len = _IOC_SIZE(cmd);
11221
11222 /* paranoia check for silly drivers which don't keep ioctl convention */
11223 if (len < DEFAULT_IOCTL_NARG_LEN)
11224 len = DEFAULT_IOCTL_NARG_LEN;
11225
11226 return len;
11227}
11228#endif
11229
11230#ifdef HAVE_IOCTL
11231static long
11232ioctl_narg_len(ioctl_req_t cmd)
11233{
11234 long len;
11235
11236#ifdef IOCPARM_MASK
11237#ifndef IOCPARM_LEN
11238#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11239#endif
11240#endif
11241#ifdef IOCPARM_LEN
11242 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11243#elif defined(__linux__) && defined(_IOC_SIZE)
11244 len = linux_iocparm_len(cmd);
11245#else
11246 /* otherwise guess at what's safe */
11247 len = DEFAULT_IOCTL_NARG_LEN;
11248#endif
11249
11250 return len;
11251}
11252#endif
11253
11254#ifdef HAVE_FCNTL
11255#ifdef __linux__
11256typedef long fcntl_arg_t;
11257#else
11258/* posix */
11259typedef int fcntl_arg_t;
11260#endif
11261
11262static long
11263fcntl_narg_len(ioctl_req_t cmd)
11264{
11265 long len;
11266
11267 switch (cmd) {
11268#ifdef F_DUPFD
11269 case F_DUPFD:
11270 len = sizeof(fcntl_arg_t);
11271 break;
11272#endif
11273#ifdef F_DUP2FD /* bsd specific */
11274 case F_DUP2FD:
11275 len = sizeof(int);
11276 break;
11277#endif
11278#ifdef F_DUPFD_CLOEXEC /* linux specific */
11279 case F_DUPFD_CLOEXEC:
11280 len = sizeof(fcntl_arg_t);
11281 break;
11282#endif
11283#ifdef F_GETFD
11284 case F_GETFD:
11285 len = 1;
11286 break;
11287#endif
11288#ifdef F_SETFD
11289 case F_SETFD:
11290 len = sizeof(fcntl_arg_t);
11291 break;
11292#endif
11293#ifdef F_GETFL
11294 case F_GETFL:
11295 len = 1;
11296 break;
11297#endif
11298#ifdef F_SETFL
11299 case F_SETFL:
11300 len = sizeof(fcntl_arg_t);
11301 break;
11302#endif
11303#ifdef F_GETOWN
11304 case F_GETOWN:
11305 len = 1;
11306 break;
11307#endif
11308#ifdef F_SETOWN
11309 case F_SETOWN:
11310 len = sizeof(fcntl_arg_t);
11311 break;
11312#endif
11313#ifdef F_GETOWN_EX /* linux specific */
11314 case F_GETOWN_EX:
11315 len = sizeof(struct f_owner_ex);
11316 break;
11317#endif
11318#ifdef F_SETOWN_EX /* linux specific */
11319 case F_SETOWN_EX:
11320 len = sizeof(struct f_owner_ex);
11321 break;
11322#endif
11323#ifdef F_GETLK
11324 case F_GETLK:
11325 len = sizeof(struct flock);
11326 break;
11327#endif
11328#ifdef F_SETLK
11329 case F_SETLK:
11330 len = sizeof(struct flock);
11331 break;
11332#endif
11333#ifdef F_SETLKW
11334 case F_SETLKW:
11335 len = sizeof(struct flock);
11336 break;
11337#endif
11338#ifdef F_READAHEAD /* bsd specific */
11339 case F_READAHEAD:
11340 len = sizeof(int);
11341 break;
11342#endif
11343#ifdef F_RDAHEAD /* Darwin specific */
11344 case F_RDAHEAD:
11345 len = sizeof(int);
11346 break;
11347#endif
11348#ifdef F_GETSIG /* linux specific */
11349 case F_GETSIG:
11350 len = 1;
11351 break;
11352#endif
11353#ifdef F_SETSIG /* linux specific */
11354 case F_SETSIG:
11355 len = sizeof(fcntl_arg_t);
11356 break;
11357#endif
11358#ifdef F_GETLEASE /* linux specific */
11359 case F_GETLEASE:
11360 len = 1;
11361 break;
11362#endif
11363#ifdef F_SETLEASE /* linux specific */
11364 case F_SETLEASE:
11365 len = sizeof(fcntl_arg_t);
11366 break;
11367#endif
11368#ifdef F_NOTIFY /* linux specific */
11369 case F_NOTIFY:
11370 len = sizeof(fcntl_arg_t);
11371 break;
11372#endif
11373
11374 default:
11375 len = 256;
11376 break;
11377 }
11378
11379 return len;
11380}
11381#else /* HAVE_FCNTL */
11382static long
11383fcntl_narg_len(ioctl_req_t cmd)
11384{
11385 return 0;
11386}
11387#endif /* HAVE_FCNTL */
11388
11389#define NARG_SENTINEL 17
11390
11391static long
11392setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11393{
11394 long narg = 0;
11395 VALUE arg = *argp;
11396
11397 if (!RTEST(arg)) {
11398 narg = 0;
11399 }
11400 else if (FIXNUM_P(arg)) {
11401 narg = FIX2LONG(arg);
11402 }
11403 else if (arg == Qtrue) {
11404 narg = 1;
11405 }
11406 else {
11407 VALUE tmp = rb_check_string_type(arg);
11408
11409 if (NIL_P(tmp)) {
11410 narg = NUM2LONG(arg);
11411 }
11412 else {
11413 char *ptr;
11414 long len, slen;
11415
11416 *argp = arg = tmp;
11417 len = narg_len(cmd);
11418 rb_str_modify(arg);
11419
11420 slen = RSTRING_LEN(arg);
11421 /* expand for data + sentinel. */
11422 if (slen < len+1) {
11423 rb_str_resize(arg, len+1);
11424 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11425 slen = len+1;
11426 }
11427 /* a little sanity check here */
11428 ptr = RSTRING_PTR(arg);
11429 ptr[slen - 1] = NARG_SENTINEL;
11430 narg = (long)(SIGNED_VALUE)ptr;
11431 }
11432 }
11433
11434 return narg;
11435}
11436
11437static VALUE
11438finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11439{
11440 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11441 if (RB_TYPE_P(arg, T_STRING)) {
11442 char *ptr;
11443 long slen;
11444 RSTRING_GETMEM(arg, ptr, slen);
11445 if (ptr[slen-1] != NARG_SENTINEL)
11446 rb_raise(rb_eArgError, "return value overflowed string");
11447 ptr[slen-1] = '\0';
11448 }
11449
11450 return INT2NUM(retval);
11451}
11452
11453#ifdef HAVE_IOCTL
11454static VALUE
11455rb_ioctl(VALUE io, VALUE req, VALUE arg)
11456{
11457 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11458 rb_io_t *fptr;
11459 long narg;
11460 int retval;
11461
11462 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11463 GetOpenFile(io, fptr);
11464 retval = do_ioctl(fptr, cmd, narg);
11465 return finish_narg(retval, arg, fptr);
11466}
11467
11468/*
11469 * call-seq:
11470 * ioctl(integer_cmd, argument) -> integer
11471 *
11472 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11473 * which issues a low-level command to an I/O device.
11474 *
11475 * Issues a low-level command to an I/O device.
11476 * The arguments and returned value are platform-dependent.
11477 * The effect of the call is platform-dependent.
11478 *
11479 * If argument +argument+ is an integer, it is passed directly;
11480 * if it is a string, it is interpreted as a binary sequence of bytes.
11481 *
11482 * Not implemented on all platforms.
11483 *
11484 */
11485
11486static VALUE
11487rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11488{
11489 VALUE req, arg;
11490
11491 rb_scan_args(argc, argv, "11", &req, &arg);
11492 return rb_ioctl(io, req, arg);
11493}
11494#else
11495#define rb_io_ioctl rb_f_notimplement
11496#endif
11497
11498#ifdef HAVE_FCNTL
11499struct fcntl_arg {
11500 int fd;
11501 int cmd;
11502 long narg;
11503};
11504
11505static VALUE
11506nogvl_fcntl(void *ptr)
11507{
11508 struct fcntl_arg *arg = ptr;
11509
11510#if defined(F_DUPFD)
11511 if (arg->cmd == F_DUPFD)
11512 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11513#endif
11514 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11515}
11516
11517static int
11518do_fcntl(struct rb_io *io, int cmd, long narg)
11519{
11520 int retval;
11521 struct fcntl_arg arg;
11522
11523 arg.fd = io->fd;
11524 arg.cmd = cmd;
11525 arg.narg = narg;
11526
11527 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11528 if (retval != -1) {
11529 switch (cmd) {
11530#if defined(F_DUPFD)
11531 case F_DUPFD:
11532#endif
11533#if defined(F_DUPFD_CLOEXEC)
11534 case F_DUPFD_CLOEXEC:
11535#endif
11536 rb_update_max_fd(retval);
11537 }
11538 }
11539
11540 return retval;
11541}
11542
11543static VALUE
11544rb_fcntl(VALUE io, VALUE req, VALUE arg)
11545{
11546 int cmd = NUM2INT(req);
11547 rb_io_t *fptr;
11548 long narg;
11549 int retval;
11550
11551 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11552 GetOpenFile(io, fptr);
11553 retval = do_fcntl(fptr, cmd, narg);
11554 return finish_narg(retval, arg, fptr);
11555}
11556
11557/*
11558 * call-seq:
11559 * fcntl(integer_cmd, argument) -> integer
11560 *
11561 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11562 * which provides a mechanism for issuing low-level commands to control or query
11563 * a file-oriented I/O stream. Arguments and results are platform
11564 * dependent.
11565 *
11566 * If +argument+ is a number, its value is passed directly;
11567 * if it is a string, it is interpreted as a binary sequence of bytes.
11568 * (Array#pack might be a useful way to build this string.)
11569 *
11570 * Not implemented on all platforms.
11571 *
11572 */
11573
11574static VALUE
11575rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11576{
11577 VALUE req, arg;
11578
11579 rb_scan_args(argc, argv, "11", &req, &arg);
11580 return rb_fcntl(io, req, arg);
11581}
11582#else
11583#define rb_io_fcntl rb_f_notimplement
11584#endif
11585
11586#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11587/*
11588 * call-seq:
11589 * syscall(integer_callno, *arguments) -> integer
11590 *
11591 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11592 * which calls a specified function.
11593 *
11594 * Calls the operating system function identified by +integer_callno+;
11595 * returns the result of the function or raises SystemCallError if it failed.
11596 * The effect of the call is platform-dependent.
11597 * The arguments and returned value are platform-dependent.
11598 *
11599 * For each of +arguments+: if it is an integer, it is passed directly;
11600 * if it is a string, it is interpreted as a binary sequence of bytes.
11601 * There may be as many as nine such arguments.
11602 *
11603 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11604 * are platform-dependent.
11605 *
11606 * Note: Method +syscall+ is essentially unsafe and unportable.
11607 * The DL (Fiddle) library is preferred for safer and a bit
11608 * more portable programming.
11609 *
11610 * Not implemented on all platforms.
11611 *
11612 */
11613
11614static VALUE
11615rb_f_syscall(int argc, VALUE *argv, VALUE _)
11616{
11617 VALUE arg[8];
11618#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11619# define SYSCALL __syscall
11620# define NUM2SYSCALLID(x) NUM2LONG(x)
11621# define RETVAL2NUM(x) LONG2NUM(x)
11622# if SIZEOF_LONG == 8
11623 long num, retval = -1;
11624# elif SIZEOF_LONG_LONG == 8
11625 long long num, retval = -1;
11626# else
11627# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11628# endif
11629#elif defined(__linux__)
11630# define SYSCALL syscall
11631# define NUM2SYSCALLID(x) NUM2LONG(x)
11632# define RETVAL2NUM(x) LONG2NUM(x)
11633 /*
11634 * Linux man page says, syscall(2) function prototype is below.
11635 *
11636 * int syscall(int number, ...);
11637 *
11638 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11639 */
11640 long num, retval = -1;
11641#else
11642# define SYSCALL syscall
11643# define NUM2SYSCALLID(x) NUM2INT(x)
11644# define RETVAL2NUM(x) INT2NUM(x)
11645 int num, retval = -1;
11646#endif
11647 int i;
11648
11649 if (RTEST(ruby_verbose)) {
11651 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11652 }
11653
11654 if (argc == 0)
11655 rb_raise(rb_eArgError, "too few arguments for syscall");
11656 if (argc > numberof(arg))
11657 rb_raise(rb_eArgError, "too many arguments for syscall");
11658 num = NUM2SYSCALLID(argv[0]); ++argv;
11659 for (i = argc - 1; i--; ) {
11660 VALUE v = rb_check_string_type(argv[i]);
11661
11662 if (!NIL_P(v)) {
11663 StringValue(v);
11664 rb_str_modify(v);
11665 arg[i] = (VALUE)StringValueCStr(v);
11666 }
11667 else {
11668 arg[i] = (VALUE)NUM2LONG(argv[i]);
11669 }
11670 }
11671
11672 switch (argc) {
11673 case 1:
11674 retval = SYSCALL(num);
11675 break;
11676 case 2:
11677 retval = SYSCALL(num, arg[0]);
11678 break;
11679 case 3:
11680 retval = SYSCALL(num, arg[0],arg[1]);
11681 break;
11682 case 4:
11683 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11684 break;
11685 case 5:
11686 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11687 break;
11688 case 6:
11689 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11690 break;
11691 case 7:
11692 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11693 break;
11694 case 8:
11695 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11696 break;
11697 }
11698
11699 if (retval == -1)
11700 rb_sys_fail(0);
11701 return RETVAL2NUM(retval);
11702#undef SYSCALL
11703#undef NUM2SYSCALLID
11704#undef RETVAL2NUM
11705}
11706#else
11707#define rb_f_syscall rb_f_notimplement
11708#endif
11709
11710static VALUE
11711io_new_instance(VALUE args)
11712{
11713 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11714}
11715
11716static rb_encoding *
11717find_encoding(VALUE v)
11718{
11719 rb_encoding *enc = rb_find_encoding(v);
11720 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11721 return enc;
11722}
11723
11724static void
11725io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11726{
11727 rb_encoding *enc, *enc2;
11728 int ecflags = fptr->encs.ecflags;
11729 VALUE ecopts, tmp;
11730
11731 if (!NIL_P(v2)) {
11732 enc2 = find_encoding(v1);
11733 tmp = rb_check_string_type(v2);
11734 if (!NIL_P(tmp)) {
11735 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11736 /* Special case - "-" => no transcoding */
11737 enc = enc2;
11738 enc2 = NULL;
11739 }
11740 else
11741 enc = find_encoding(v2);
11742 if (enc == enc2) {
11743 /* Special case - "-" => no transcoding */
11744 enc2 = NULL;
11745 }
11746 }
11747 else {
11748 enc = find_encoding(v2);
11749 if (enc == enc2) {
11750 /* Special case - "-" => no transcoding */
11751 enc2 = NULL;
11752 }
11753 }
11754 if (enc2 == rb_ascii8bit_encoding()) {
11755 /* If external is ASCII-8BIT, no transcoding */
11756 enc = enc2;
11757 enc2 = NULL;
11758 }
11759 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11760 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11761 }
11762 else {
11763 if (NIL_P(v1)) {
11764 /* Set to default encodings */
11765 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11766 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11767 ecopts = Qnil;
11768 }
11769 else {
11770 tmp = rb_check_string_type(v1);
11771 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11772 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11773 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11774 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11775 }
11776 else {
11777 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11778 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11779 ecopts = Qnil;
11780 }
11781 }
11782 }
11783 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11784 fptr->encs.enc = enc;
11785 fptr->encs.enc2 = enc2;
11786 fptr->encs.ecflags = ecflags;
11787 fptr->encs.ecopts = ecopts;
11788 clear_codeconv(fptr);
11789
11790}
11791
11793 rb_io_t *fptr;
11794 VALUE v1;
11795 VALUE v2;
11796 VALUE opt;
11797};
11798
11799static VALUE
11800io_encoding_set_v(VALUE v)
11801{
11802 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11803 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11804 return Qnil;
11805}
11806
11807static VALUE
11808pipe_pair_close(VALUE rw)
11809{
11810 VALUE *rwp = (VALUE *)rw;
11811 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11812}
11813
11814/*
11815 * call-seq:
11816 * IO.pipe(**opts) -> [read_io, write_io]
11817 * IO.pipe(enc, **opts) -> [read_io, write_io]
11818 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11819 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11820 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11821 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11822 *
11823 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11824 * connected to each other.
11825 *
11826 * If argument +enc_string+ is given, it must be a string containing one of:
11827 *
11828 * - The name of the encoding to be used as the external encoding.
11829 * - The colon-separated names of two encodings to be used as the external
11830 * and internal encodings.
11831 *
11832 * If argument +int_enc+ is given, it must be an Encoding object
11833 * or encoding name string that specifies the internal encoding to be used;
11834 * if argument +ext_enc+ is also given, it must be an Encoding object
11835 * or encoding name string that specifies the external encoding to be used.
11836 *
11837 * The string read from +read_io+ is tagged with the external encoding;
11838 * if an internal encoding is also specified, the string is converted
11839 * to, and tagged with, that encoding.
11840 *
11841 * If any encoding is specified,
11842 * optional hash arguments specify the conversion option.
11843 *
11844 * Optional keyword arguments +opts+ specify:
11845 *
11846 * - {Open Options}[rdoc-ref:IO@Open+Options].
11847 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11848 *
11849 * With no block given, returns the two endpoints in an array:
11850 *
11851 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11852 *
11853 * With a block given, calls the block with the two endpoints;
11854 * closes both endpoints and returns the value of the block:
11855 *
11856 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11857 *
11858 * Output:
11859 *
11860 * #<IO:fd 6>
11861 * #<IO:fd 7>
11862 *
11863 * Not available on all platforms.
11864 *
11865 * In the example below, the two processes close the ends of the pipe
11866 * that they are not using. This is not just a cosmetic nicety. The
11867 * read end of a pipe will not generate an end of file condition if
11868 * there are any writers with the pipe still open. In the case of the
11869 * parent process, the <tt>rd.read</tt> will never return if it
11870 * does not first issue a <tt>wr.close</tt>:
11871 *
11872 * rd, wr = IO.pipe
11873 *
11874 * if fork
11875 * wr.close
11876 * puts "Parent got: <#{rd.read}>"
11877 * rd.close
11878 * Process.wait
11879 * else
11880 * rd.close
11881 * puts 'Sending message to parent'
11882 * wr.write "Hi Dad"
11883 * wr.close
11884 * end
11885 *
11886 * <em>produces:</em>
11887 *
11888 * Sending message to parent
11889 * Parent got: <Hi Dad>
11890 *
11891 */
11892
11893static VALUE
11894rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11895{
11896 int pipes[2], state;
11897 VALUE r, w, args[3], v1, v2;
11898 VALUE opt;
11899 rb_io_t *fptr, *fptr2;
11900 struct io_encoding_set_args ies_args;
11901 enum rb_io_mode fmode = 0;
11902 VALUE ret;
11903
11904 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11905 if (rb_pipe(pipes) < 0)
11906 rb_sys_fail(0);
11907
11908 args[0] = klass;
11909 args[1] = INT2NUM(pipes[0]);
11910 args[2] = INT2FIX(O_RDONLY);
11911 r = rb_protect(io_new_instance, (VALUE)args, &state);
11912 if (state) {
11913 close(pipes[0]);
11914 close(pipes[1]);
11915 rb_jump_tag(state);
11916 }
11917 GetOpenFile(r, fptr);
11918
11919 ies_args.fptr = fptr;
11920 ies_args.v1 = v1;
11921 ies_args.v2 = v2;
11922 ies_args.opt = opt;
11923 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11924 if (state) {
11925 close(pipes[1]);
11926 io_close(r);
11927 rb_jump_tag(state);
11928 }
11929
11930 args[1] = INT2NUM(pipes[1]);
11931 args[2] = INT2FIX(O_WRONLY);
11932 w = rb_protect(io_new_instance, (VALUE)args, &state);
11933 if (state) {
11934 close(pipes[1]);
11935 if (!NIL_P(r)) rb_io_close(r);
11936 rb_jump_tag(state);
11937 }
11938 GetOpenFile(w, fptr2);
11939 rb_io_synchronized(fptr2);
11940
11941 extract_binmode(opt, &fmode);
11942
11943 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11946 }
11947
11948#if DEFAULT_TEXTMODE
11949 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11950 fptr->mode &= ~FMODE_TEXTMODE;
11951 setmode(fptr->fd, O_BINARY);
11952 }
11953#if RUBY_CRLF_ENVIRONMENT
11956 }
11957#endif
11958#endif
11959 fptr->mode |= fmode;
11960#if DEFAULT_TEXTMODE
11961 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11962 fptr2->mode &= ~FMODE_TEXTMODE;
11963 setmode(fptr2->fd, O_BINARY);
11964 }
11965#endif
11966 fptr2->mode |= fmode;
11967
11968 ret = rb_assoc_new(r, w);
11969 if (rb_block_given_p()) {
11970 VALUE rw[2];
11971 rw[0] = r;
11972 rw[1] = w;
11973 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11974 }
11975 return ret;
11976}
11977
11979 int argc;
11980 VALUE *argv;
11981 VALUE io;
11982};
11983
11984static void
11985open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
11986{
11987 VALUE path, v;
11988 VALUE vmode = Qnil, vperm = Qnil;
11989
11990 path = *argv++;
11991 argc--;
11992 FilePathValue(path);
11993 arg->io = 0;
11994 arg->argc = argc;
11995 arg->argv = argv;
11996 if (NIL_P(opt)) {
11997 vmode = INT2NUM(O_RDONLY);
11998 vperm = INT2FIX(0666);
11999 }
12000 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12001 int n;
12002
12003 v = rb_to_array_type(v);
12004 n = RARRAY_LENINT(v);
12005 rb_check_arity(n, 0, 3); /* rb_io_open */
12006 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12007 }
12008 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12009}
12010
12011static VALUE
12012io_s_foreach(VALUE v)
12013{
12014 struct getline_arg *arg = (void *)v;
12015 VALUE str;
12016
12017 if (arg->limit == 0)
12018 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12019 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12020 rb_lastline_set(str);
12021 rb_yield(str);
12022 }
12024 return Qnil;
12025}
12026
12027/*
12028 * call-seq:
12029 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12030 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12031 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12032 * IO.foreach(...) -> an_enumerator
12033 *
12034 * Calls the block with each successive line read from the stream.
12035 *
12036 * When called from class \IO (but not subclasses of \IO),
12037 * this method has potential security vulnerabilities if called with untrusted input;
12038 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12039 *
12040 * The first argument must be a string that is the path to a file.
12041 *
12042 * With only argument +path+ given, parses lines from the file at the given +path+,
12043 * as determined by the default line separator,
12044 * and calls the block with each successive line:
12045 *
12046 * File.foreach('t.txt') {|line| p line }
12047 *
12048 * Output: the same as above.
12049 *
12050 * For both forms, command and path, the remaining arguments are the same.
12051 *
12052 * With argument +sep+ given, parses lines as determined by that line separator
12053 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12054 *
12055 * File.foreach('t.txt', 'li') {|line| p line }
12056 *
12057 * Output:
12058 *
12059 * "First li"
12060 * "ne\nSecond li"
12061 * "ne\n\nThird li"
12062 * "ne\nFourth li"
12063 * "ne\n"
12064 *
12065 * Each paragraph:
12066 *
12067 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12068 *
12069 * Output:
12070 *
12071 * "First line\nSecond line\n\n"
12072 * "Third line\nFourth line\n"
12073 *
12074 * With argument +limit+ given, parses lines as determined by the default
12075 * line separator and the given line-length limit
12076 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12077 *
12078 * File.foreach('t.txt', 7) {|line| p line }
12079 *
12080 * Output:
12081 *
12082 * "First l"
12083 * "ine\n"
12084 * "Second "
12085 * "line\n"
12086 * "\n"
12087 * "Third l"
12088 * "ine\n"
12089 * "Fourth l"
12090 * "line\n"
12091 *
12092 * With arguments +sep+ and +limit+ given,
12093 * combines the two behaviors
12094 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12095 *
12096 * Optional keyword arguments +opts+ specify:
12097 *
12098 * - {Open Options}[rdoc-ref:IO@Open+Options].
12099 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12100 * - {Line Options}[rdoc-ref:IO@Line+IO].
12101 *
12102 * Returns an Enumerator if no block is given.
12103 *
12104 */
12105
12106static VALUE
12107rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12108{
12109 VALUE opt;
12110 int orig_argc = argc;
12111 struct foreach_arg arg;
12112 struct getline_arg garg;
12113
12114 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12115 RETURN_ENUMERATOR(self, orig_argc, argv);
12116 extract_getline_args(argc-1, argv+1, &garg);
12117 open_key_args(self, argc, argv, opt, &arg);
12118 if (NIL_P(arg.io)) return Qnil;
12119 extract_getline_opts(opt, &garg);
12120 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12121 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12122}
12123
12124static VALUE
12125io_s_readlines(VALUE v)
12126{
12127 struct getline_arg *arg = (void *)v;
12128 return io_readlines(arg, arg->io);
12129}
12130
12131/*
12132 * call-seq:
12133 * IO.readlines(path, sep = $/, **opts) -> array
12134 * IO.readlines(path, limit, **opts) -> array
12135 * IO.readlines(path, sep, limit, **opts) -> array
12136 *
12137 * Returns an array of all lines read from the stream.
12138 *
12139 * When called from class \IO (but not subclasses of \IO),
12140 * this method has potential security vulnerabilities if called with untrusted input;
12141 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12142 *
12143 * The first argument must be a string that is the path to a file.
12144 *
12145 * With only argument +path+ given, parses lines from the file at the given +path+,
12146 * as determined by the default line separator,
12147 * and returns those lines in an array:
12148 *
12149 * IO.readlines('t.txt')
12150 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12151 *
12152 * With argument +sep+ given, parses lines as determined by that line separator
12153 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12154 *
12155 * # Ordinary separator.
12156 * IO.readlines('t.txt', 'li')
12157 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12158 * # Get-paragraphs separator.
12159 * IO.readlines('t.txt', '')
12160 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12161 * # Get-all separator.
12162 * IO.readlines('t.txt', nil)
12163 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12164 *
12165 * With argument +limit+ given, parses lines as determined by the default
12166 * line separator and the given line-length limit
12167 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12168 *
12169 * IO.readlines('t.txt', 7)
12170 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12171 *
12172 * With arguments +sep+ and +limit+ given,
12173 * combines the two behaviors
12174 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12175 *
12176 * Optional keyword arguments +opts+ specify:
12177 *
12178 * - {Open Options}[rdoc-ref:IO@Open+Options].
12179 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12180 * - {Line Options}[rdoc-ref:IO@Line+IO].
12181 *
12182 */
12183
12184static VALUE
12185rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12186{
12187 VALUE opt;
12188 struct foreach_arg arg;
12189 struct getline_arg garg;
12190
12191 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12192 extract_getline_args(argc-1, argv+1, &garg);
12193 open_key_args(io, argc, argv, opt, &arg);
12194 if (NIL_P(arg.io)) return Qnil;
12195 extract_getline_opts(opt, &garg);
12196 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12197 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12198}
12199
12200static VALUE
12201io_s_read(VALUE v)
12202{
12203 struct foreach_arg *arg = (void *)v;
12204 return io_read(arg->argc, arg->argv, arg->io);
12205}
12206
12207struct seek_arg {
12208 VALUE io;
12209 VALUE offset;
12210 int mode;
12211};
12212
12213static VALUE
12214seek_before_access(VALUE argp)
12215{
12216 struct seek_arg *arg = (struct seek_arg *)argp;
12217 rb_io_binmode(arg->io);
12218 return rb_io_seek(arg->io, arg->offset, arg->mode);
12219}
12220
12221/*
12222 * call-seq:
12223 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12224 *
12225 * Opens the stream, reads and returns some or all of its content,
12226 * and closes the stream; returns +nil+ if no bytes were read.
12227 *
12228 * When called from class \IO (but not subclasses of \IO),
12229 * this method has potential security vulnerabilities if called with untrusted input;
12230 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12231 *
12232 * The first argument must be a string that is the path to a file.
12233 *
12234 * With only argument +path+ given, reads in text mode and returns the entire content
12235 * of the file at the given path:
12236 *
12237 * IO.read('t.txt')
12238 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12239 *
12240 * On Windows, text mode can terminate reading and leave bytes in the file
12241 * unread when encountering certain special bytes. Consider using
12242 * IO.binread if all bytes in the file should be read.
12243 *
12244 * With argument +length+, returns +length+ bytes if available:
12245 *
12246 * IO.read('t.txt', 7) # => "First l"
12247 * IO.read('t.txt', 700)
12248 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12249 *
12250 * With arguments +length+ and +offset+, returns +length+ bytes
12251 * if available, beginning at the given +offset+:
12252 *
12253 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12254 * IO.read('t.txt', 10, 200) # => nil
12255 *
12256 * Optional keyword arguments +opts+ specify:
12257 *
12258 * - {Open Options}[rdoc-ref:IO@Open+Options].
12259 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12260 *
12261 */
12262
12263static VALUE
12264rb_io_s_read(int argc, VALUE *argv, VALUE io)
12265{
12266 VALUE opt, offset;
12267 long off;
12268 struct foreach_arg arg;
12269
12270 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12271 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12272 rb_raise(rb_eArgError, "negative offset %ld given", off);
12273 }
12274 open_key_args(io, argc, argv, opt, &arg);
12275 if (NIL_P(arg.io)) return Qnil;
12276 if (!NIL_P(offset)) {
12277 struct seek_arg sarg;
12278 int state = 0;
12279 sarg.io = arg.io;
12280 sarg.offset = offset;
12281 sarg.mode = SEEK_SET;
12282 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12283 if (state) {
12284 rb_io_close(arg.io);
12285 rb_jump_tag(state);
12286 }
12287 if (arg.argc == 2) arg.argc = 1;
12288 }
12289 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12290}
12291
12292/*
12293 * call-seq:
12294 * IO.binread(path, length = nil, offset = 0) -> string or nil
12295 *
12296 * Behaves like IO.read, except that the stream is opened in binary mode
12297 * with ASCII-8BIT encoding.
12298 *
12299 * When called from class \IO (but not subclasses of \IO),
12300 * this method has potential security vulnerabilities if called with untrusted input;
12301 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12302 *
12303 */
12304
12305static VALUE
12306rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12307{
12308 VALUE offset;
12309 struct foreach_arg arg;
12310 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12311 enum {
12312 oflags = O_RDONLY
12313#ifdef O_BINARY
12314 |O_BINARY
12315#endif
12316 };
12317 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12318
12319 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12320 FilePathValue(argv[0]);
12321 convconfig.enc = rb_ascii8bit_encoding();
12322 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12323 if (NIL_P(arg.io)) return Qnil;
12324 arg.argv = argv+1;
12325 arg.argc = (argc > 1) ? 1 : 0;
12326 if (!NIL_P(offset)) {
12327 struct seek_arg sarg;
12328 int state = 0;
12329 sarg.io = arg.io;
12330 sarg.offset = offset;
12331 sarg.mode = SEEK_SET;
12332 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12333 if (state) {
12334 rb_io_close(arg.io);
12335 rb_jump_tag(state);
12336 }
12337 }
12338 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12339}
12340
12341static VALUE
12342io_s_write0(VALUE v)
12343{
12344 struct write_arg *arg = (void *)v;
12345 return io_write(arg->io,arg->str,arg->nosync);
12346}
12347
12348static VALUE
12349io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12350{
12351 VALUE string, offset, opt;
12352 struct foreach_arg arg;
12353 struct write_arg warg;
12354
12355 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12356
12357 if (NIL_P(opt)) opt = rb_hash_new();
12358 else opt = rb_hash_dup(opt);
12359
12360
12361 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12362 int mode = O_WRONLY|O_CREAT;
12363#ifdef O_BINARY
12364 if (binary) mode |= O_BINARY;
12365#endif
12366 if (NIL_P(offset)) mode |= O_TRUNC;
12367 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12368 }
12369 open_key_args(klass, argc, argv, opt, &arg);
12370
12371#ifndef O_BINARY
12372 if (binary) rb_io_binmode_m(arg.io);
12373#endif
12374
12375 if (NIL_P(arg.io)) return Qnil;
12376 if (!NIL_P(offset)) {
12377 struct seek_arg sarg;
12378 int state = 0;
12379 sarg.io = arg.io;
12380 sarg.offset = offset;
12381 sarg.mode = SEEK_SET;
12382 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12383 if (state) {
12384 rb_io_close(arg.io);
12385 rb_jump_tag(state);
12386 }
12387 }
12388
12389 warg.io = arg.io;
12390 warg.str = string;
12391 warg.nosync = 0;
12392
12393 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12394}
12395
12396/*
12397 * call-seq:
12398 * IO.write(path, data, offset = 0, **opts) -> integer
12399 *
12400 * Opens the stream, writes the given +data+ to it,
12401 * and closes the stream; returns the number of bytes written.
12402 *
12403 * When called from class \IO (but not subclasses of \IO),
12404 * this method has potential security vulnerabilities if called with untrusted input;
12405 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12406 *
12407 * The first argument must be a string that is the path to a file.
12408 *
12409 * With only argument +path+ given, writes the given +data+ to the file at that path:
12410 *
12411 * IO.write('t.tmp', 'abc') # => 3
12412 * File.read('t.tmp') # => "abc"
12413 *
12414 * If +offset+ is zero (the default), the file is overwritten:
12415 *
12416 * IO.write('t.tmp', 'A') # => 1
12417 * File.read('t.tmp') # => "A"
12418 *
12419 * If +offset+ in within the file content, the file is partly overwritten:
12420 *
12421 * IO.write('t.tmp', 'abcdef') # => 3
12422 * File.read('t.tmp') # => "abcdef"
12423 * # Offset within content.
12424 * IO.write('t.tmp', '012', 2) # => 3
12425 * File.read('t.tmp') # => "ab012f"
12426 *
12427 * If +offset+ is outside the file content,
12428 * the file is padded with null characters <tt>"\u0000"</tt>:
12429 *
12430 * IO.write('t.tmp', 'xyz', 10) # => 3
12431 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12432 *
12433 * Optional keyword arguments +opts+ specify:
12434 *
12435 * - {Open Options}[rdoc-ref:IO@Open+Options].
12436 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12437 *
12438 */
12439
12440static VALUE
12441rb_io_s_write(int argc, VALUE *argv, VALUE io)
12442{
12443 return io_s_write(argc, argv, io, 0);
12444}
12445
12446/*
12447 * call-seq:
12448 * IO.binwrite(path, string, offset = 0) -> integer
12449 *
12450 * Behaves like IO.write, except that the stream is opened in binary mode
12451 * with ASCII-8BIT encoding.
12452 *
12453 * When called from class \IO (but not subclasses of \IO),
12454 * this method has potential security vulnerabilities if called with untrusted input;
12455 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12456 *
12457 */
12458
12459static VALUE
12460rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12461{
12462 return io_s_write(argc, argv, io, 1);
12463}
12464
12466 VALUE src;
12467 VALUE dst;
12468 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12469 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12470
12471 rb_io_t *src_fptr;
12472 rb_io_t *dst_fptr;
12473 unsigned close_src : 1;
12474 unsigned close_dst : 1;
12475 int error_no;
12476 rb_off_t total;
12477 const char *syserr;
12478 const char *notimp;
12479 VALUE th;
12480 struct stat src_stat;
12481 struct stat dst_stat;
12482#ifdef HAVE_FCOPYFILE
12483 copyfile_state_t copyfile_state;
12484#endif
12485};
12486
12487static void *
12488exec_interrupts(void *arg)
12489{
12490 VALUE th = (VALUE)arg;
12491 rb_thread_execute_interrupts(th);
12492 return NULL;
12493}
12494
12495/*
12496 * returns TRUE if the preceding system call was interrupted
12497 * so we can continue. If the thread was interrupted, we
12498 * reacquire the GVL to execute interrupts before continuing.
12499 */
12500static int
12501maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12502{
12503 switch (errno) {
12504 case EINTR:
12505#if defined(ERESTART)
12506 case ERESTART:
12507#endif
12508 if (rb_thread_interrupted(stp->th)) {
12509 if (has_gvl)
12510 rb_thread_execute_interrupts(stp->th);
12511 else
12512 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12513 }
12514 return TRUE;
12515 }
12516 return FALSE;
12517}
12518
12520 VALUE scheduler;
12521
12522 rb_io_t *fptr;
12523 short events;
12524
12525 VALUE result;
12526};
12527
12528static void *
12529fiber_scheduler_wait_for(void * _arguments)
12530{
12531 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12532
12533 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12534
12535 return NULL;
12536}
12537
12538#if USE_POLL
12539# define IOWAIT_SYSCALL "poll"
12540STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12541STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12542static int
12543nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12544{
12546 if (scheduler != Qnil) {
12547 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12548 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12549 return RTEST(args.result);
12550 }
12551
12552 int fd = fptr->fd;
12553 if (fd == -1) return 0;
12554
12555 struct pollfd fds;
12556
12557 fds.fd = fd;
12558 fds.events = events;
12559
12560 int timeout_milliseconds = -1;
12561
12562 if (timeout) {
12563 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12564 }
12565
12566 return poll(&fds, 1, timeout_milliseconds);
12567}
12568#else /* !USE_POLL */
12569# define IOWAIT_SYSCALL "select"
12570static int
12571nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12572{
12574 if (scheduler != Qnil) {
12575 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12576 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12577 return RTEST(args.result);
12578 }
12579
12580 int fd = fptr->fd;
12581
12582 if (fd == -1) {
12583 errno = EBADF;
12584 return -1;
12585 }
12586
12587 rb_fdset_t fds;
12588 int ret;
12589
12590 rb_fd_init(&fds);
12591 rb_fd_set(fd, &fds);
12592
12593 switch (events) {
12594 case RB_WAITFD_IN:
12595 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12596 break;
12597 case RB_WAITFD_OUT:
12598 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12599 break;
12600 default:
12601 VM_UNREACHABLE(nogvl_wait_for);
12602 }
12603
12604 rb_fd_term(&fds);
12605
12606 // On timeout, this returns 0.
12607 return ret;
12608}
12609#endif /* !USE_POLL */
12610
12611static int
12612maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12613{
12614 int ret;
12615
12616 do {
12617 if (has_gvl) {
12619 }
12620 else {
12621 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12622 }
12623 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12624
12625 if (ret < 0) {
12626 stp->syserr = IOWAIT_SYSCALL;
12627 stp->error_no = errno;
12628 return ret;
12629 }
12630 return 0;
12631}
12632
12633static int
12634nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12635{
12636 int ret;
12637
12638 do {
12639 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12640 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12641
12642 if (ret < 0) {
12643 stp->syserr = IOWAIT_SYSCALL;
12644 stp->error_no = errno;
12645 return ret;
12646 }
12647 return 0;
12648}
12649
12650#ifdef USE_COPY_FILE_RANGE
12651
12652static ssize_t
12653simple_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)
12654{
12655#ifdef HAVE_COPY_FILE_RANGE
12656 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12657#else
12658 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12659#endif
12660}
12661
12662static int
12663nogvl_copy_file_range(struct copy_stream_struct *stp)
12664{
12665 ssize_t ss;
12666 rb_off_t src_size;
12667 rb_off_t copy_length, src_offset, *src_offset_ptr;
12668
12669 if (!S_ISREG(stp->src_stat.st_mode))
12670 return 0;
12671
12672 src_size = stp->src_stat.st_size;
12673 src_offset = stp->src_offset;
12674 if (src_offset >= (rb_off_t)0) {
12675 src_offset_ptr = &src_offset;
12676 }
12677 else {
12678 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12679 }
12680
12681 copy_length = stp->copy_length;
12682 if (copy_length < (rb_off_t)0) {
12683 if (src_offset < (rb_off_t)0) {
12684 rb_off_t current_offset;
12685 errno = 0;
12686 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12687 if (current_offset < (rb_off_t)0 && errno) {
12688 stp->syserr = "lseek";
12689 stp->error_no = errno;
12690 return (int)current_offset;
12691 }
12692 copy_length = src_size - current_offset;
12693 }
12694 else {
12695 copy_length = src_size - src_offset;
12696 }
12697 }
12698
12699 retry_copy_file_range:
12700# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12701 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12702 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12703# else
12704 ss = (ssize_t)copy_length;
12705# endif
12706 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12707 if (0 < ss) {
12708 stp->total += ss;
12709 copy_length -= ss;
12710 if (0 < copy_length) {
12711 goto retry_copy_file_range;
12712 }
12713 }
12714 if (ss < 0) {
12715 if (maygvl_copy_stream_continue_p(0, stp)) {
12716 goto retry_copy_file_range;
12717 }
12718 switch (errno) {
12719 case EINVAL:
12720 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12721 docker container) */
12722#ifdef ENOSYS
12723 case ENOSYS:
12724#endif
12725#ifdef EXDEV
12726 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12727#endif
12728 return 0;
12729 case EAGAIN:
12730#if EWOULDBLOCK != EAGAIN
12731 case EWOULDBLOCK:
12732#endif
12733 {
12734 int ret = nogvl_copy_stream_wait_write(stp);
12735 if (ret < 0) return ret;
12736 }
12737 goto retry_copy_file_range;
12738 case EBADF:
12739 {
12740 int e = errno;
12741 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12742
12743 if (flags != -1 && flags & O_APPEND) {
12744 return 0;
12745 }
12746 errno = e;
12747 }
12748 }
12749 stp->syserr = "copy_file_range";
12750 stp->error_no = errno;
12751 return (int)ss;
12752 }
12753 return 1;
12754}
12755#endif
12756
12757#ifdef HAVE_FCOPYFILE
12758static int
12759nogvl_fcopyfile(struct copy_stream_struct *stp)
12760{
12761 rb_off_t cur, ss = 0;
12762 const rb_off_t src_offset = stp->src_offset;
12763 int ret;
12764
12765 if (stp->copy_length >= (rb_off_t)0) {
12766 /* copy_length can't be specified in fcopyfile(3) */
12767 return 0;
12768 }
12769
12770 if (!S_ISREG(stp->src_stat.st_mode))
12771 return 0;
12772
12773 if (!S_ISREG(stp->dst_stat.st_mode))
12774 return 0;
12775 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12776 return 0;
12777 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12778 /* fcopyfile(3) appends src IO to dst IO and then truncates
12779 * dst IO to src IO's original size. */
12780 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12781 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12782 if (end > (rb_off_t)0) return 0;
12783 }
12784
12785 if (src_offset > (rb_off_t)0) {
12786 rb_off_t r;
12787
12788 /* get current offset */
12789 errno = 0;
12790 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12791 if (cur < (rb_off_t)0 && errno) {
12792 stp->error_no = errno;
12793 return 1;
12794 }
12795
12796 errno = 0;
12797 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12798 if (r < (rb_off_t)0 && errno) {
12799 stp->error_no = errno;
12800 return 1;
12801 }
12802 }
12803
12804 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12805 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12806 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12807
12808 if (ret == 0) { /* success */
12809 stp->total = ss;
12810 if (src_offset > (rb_off_t)0) {
12811 rb_off_t r;
12812 errno = 0;
12813 /* reset offset */
12814 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12815 if (r < (rb_off_t)0 && errno) {
12816 stp->error_no = errno;
12817 return 1;
12818 }
12819 }
12820 }
12821 else {
12822 switch (errno) {
12823 case ENOTSUP:
12824 case EPERM:
12825 case EINVAL:
12826 return 0;
12827 }
12828 stp->syserr = "fcopyfile";
12829 stp->error_no = errno;
12830 return (int)ret;
12831 }
12832 return 1;
12833}
12834#endif
12835
12836#ifdef HAVE_SENDFILE
12837
12838# ifdef __linux__
12839# define USE_SENDFILE
12840
12841# ifdef HAVE_SYS_SENDFILE_H
12842# include <sys/sendfile.h>
12843# endif
12844
12845static ssize_t
12846simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12847{
12848 return sendfile(out_fd, in_fd, offset, (size_t)count);
12849}
12850
12851# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12852/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12853 * without cpuset -l 0.
12854 */
12855# define USE_SENDFILE
12856
12857static ssize_t
12858simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12859{
12860 int r;
12861 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12862 rb_off_t sbytes;
12863# ifdef __APPLE__
12864 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12865 sbytes = count;
12866# else
12867 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12868# endif
12869 if (r != 0 && sbytes == 0) return r;
12870 if (offset) {
12871 *offset += sbytes;
12872 }
12873 else {
12874 lseek(in_fd, sbytes, SEEK_CUR);
12875 }
12876 return (ssize_t)sbytes;
12877}
12878
12879# endif
12880
12881#endif
12882
12883#ifdef USE_SENDFILE
12884static int
12885nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12886{
12887 ssize_t ss;
12888 rb_off_t src_size;
12889 rb_off_t copy_length;
12890 rb_off_t src_offset;
12891 int use_pread;
12892
12893 if (!S_ISREG(stp->src_stat.st_mode))
12894 return 0;
12895
12896 src_size = stp->src_stat.st_size;
12897#ifndef __linux__
12898 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12899 return 0;
12900#endif
12901
12902 src_offset = stp->src_offset;
12903 use_pread = src_offset >= (rb_off_t)0;
12904
12905 copy_length = stp->copy_length;
12906 if (copy_length < (rb_off_t)0) {
12907 if (use_pread)
12908 copy_length = src_size - src_offset;
12909 else {
12910 rb_off_t cur;
12911 errno = 0;
12912 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12913 if (cur < (rb_off_t)0 && errno) {
12914 stp->syserr = "lseek";
12915 stp->error_no = errno;
12916 return (int)cur;
12917 }
12918 copy_length = src_size - cur;
12919 }
12920 }
12921
12922 retry_sendfile:
12923# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12924 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12925 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12926# else
12927 ss = (ssize_t)copy_length;
12928# endif
12929 if (use_pread) {
12930 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12931 }
12932 else {
12933 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12934 }
12935 if (0 < ss) {
12936 stp->total += ss;
12937 copy_length -= ss;
12938 if (0 < copy_length) {
12939 goto retry_sendfile;
12940 }
12941 }
12942 if (ss < 0) {
12943 if (maygvl_copy_stream_continue_p(0, stp))
12944 goto retry_sendfile;
12945 switch (errno) {
12946 case EINVAL:
12947#ifdef ENOSYS
12948 case ENOSYS:
12949#endif
12950#ifdef EOPNOTSUP
12951 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12952 see also: [Feature #16965] */
12953 case EOPNOTSUP:
12954#endif
12955 return 0;
12956 case EAGAIN:
12957#if EWOULDBLOCK != EAGAIN
12958 case EWOULDBLOCK:
12959#endif
12960 {
12961 int ret;
12962#ifndef __linux__
12963 /*
12964 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12965 * select() reports regular files to always be "ready", so
12966 * there is no need to select() on it.
12967 * Other OSes may have the same limitation for sendfile() which
12968 * allow us to bypass maygvl_copy_stream_wait_read()...
12969 */
12970 ret = maygvl_copy_stream_wait_read(0, stp);
12971 if (ret < 0) return ret;
12972#endif
12973 ret = nogvl_copy_stream_wait_write(stp);
12974 if (ret < 0) return ret;
12975 }
12976 goto retry_sendfile;
12977 }
12978 stp->syserr = "sendfile";
12979 stp->error_no = errno;
12980 return (int)ss;
12981 }
12982 return 1;
12983}
12984#endif
12985
12986static ssize_t
12987maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
12988{
12989 if (has_gvl)
12990 return rb_io_read_memory(fptr, buf, count);
12991 else
12992 return read(fptr->fd, buf, count);
12993}
12994
12995static ssize_t
12996maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
12997{
12998 ssize_t ss;
12999 retry_read:
13000 if (offset < (rb_off_t)0) {
13001 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13002 }
13003 else {
13004 ss = pread(stp->src_fptr->fd, buf, len, offset);
13005 }
13006 if (ss == 0) {
13007 return 0;
13008 }
13009 if (ss < 0) {
13010 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13011 goto retry_read;
13012 switch (errno) {
13013 case EAGAIN:
13014#if EWOULDBLOCK != EAGAIN
13015 case EWOULDBLOCK:
13016#endif
13017 {
13018 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13019 if (ret < 0) return ret;
13020 }
13021 goto retry_read;
13022#ifdef ENOSYS
13023 case ENOSYS:
13024 stp->notimp = "pread";
13025 return ss;
13026#endif
13027 }
13028 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13029 stp->error_no = errno;
13030 }
13031 return ss;
13032}
13033
13034static int
13035nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13036{
13037 ssize_t ss;
13038 int off = 0;
13039 while (len) {
13040 ss = write(stp->dst_fptr->fd, buf+off, len);
13041 if (ss < 0) {
13042 if (maygvl_copy_stream_continue_p(0, stp))
13043 continue;
13044 if (io_again_p(errno)) {
13045 int ret = nogvl_copy_stream_wait_write(stp);
13046 if (ret < 0) return ret;
13047 continue;
13048 }
13049 stp->syserr = "write";
13050 stp->error_no = errno;
13051 return (int)ss;
13052 }
13053 off += (int)ss;
13054 len -= (int)ss;
13055 stp->total += ss;
13056 }
13057 return 0;
13058}
13059
13060static void
13061nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13062{
13063 char buf[1024*16];
13064 size_t len;
13065 ssize_t ss;
13066 int ret;
13067 rb_off_t copy_length;
13068 rb_off_t src_offset;
13069 int use_eof;
13070 int use_pread;
13071
13072 copy_length = stp->copy_length;
13073 use_eof = copy_length < (rb_off_t)0;
13074 src_offset = stp->src_offset;
13075 use_pread = src_offset >= (rb_off_t)0;
13076
13077 if (use_pread && stp->close_src) {
13078 rb_off_t r;
13079 errno = 0;
13080 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13081 if (r < (rb_off_t)0 && errno) {
13082 stp->syserr = "lseek";
13083 stp->error_no = errno;
13084 return;
13085 }
13086 src_offset = (rb_off_t)-1;
13087 use_pread = 0;
13088 }
13089
13090 while (use_eof || 0 < copy_length) {
13091 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13092 len = (size_t)copy_length;
13093 }
13094 else {
13095 len = sizeof(buf);
13096 }
13097 if (use_pread) {
13098 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13099 if (0 < ss)
13100 src_offset += ss;
13101 }
13102 else {
13103 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13104 }
13105 if (ss <= 0) /* EOF or error */
13106 return;
13107
13108 ret = nogvl_copy_stream_write(stp, buf, ss);
13109 if (ret < 0)
13110 return;
13111
13112 if (!use_eof)
13113 copy_length -= ss;
13114 }
13115}
13116
13117static void *
13118nogvl_copy_stream_func(void *arg)
13119{
13120 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13121#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13122 int ret;
13123#endif
13124
13125#ifdef USE_COPY_FILE_RANGE
13126 ret = nogvl_copy_file_range(stp);
13127 if (ret != 0)
13128 goto finish; /* error or success */
13129#endif
13130
13131#ifdef HAVE_FCOPYFILE
13132 ret = nogvl_fcopyfile(stp);
13133 if (ret != 0)
13134 goto finish; /* error or success */
13135#endif
13136
13137#ifdef USE_SENDFILE
13138 ret = nogvl_copy_stream_sendfile(stp);
13139 if (ret != 0)
13140 goto finish; /* error or success */
13141#endif
13142
13143 nogvl_copy_stream_read_write(stp);
13144
13145#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13146 finish:
13147#endif
13148 return 0;
13149}
13150
13151static VALUE
13152copy_stream_fallback_body(VALUE arg)
13153{
13154 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13155 const int buflen = 16*1024;
13156 VALUE n;
13157 VALUE buf = rb_str_buf_new(buflen);
13158 rb_off_t rest = stp->copy_length;
13159 rb_off_t off = stp->src_offset;
13160 ID read_method = id_readpartial;
13161
13162 if (!stp->src_fptr) {
13163 if (!rb_respond_to(stp->src, read_method)) {
13164 read_method = id_read;
13165 }
13166 }
13167
13168 while (1) {
13169 long numwrote;
13170 long l;
13171 rb_str_make_independent(buf);
13172 if (stp->copy_length < (rb_off_t)0) {
13173 l = buflen;
13174 }
13175 else {
13176 if (rest == 0) {
13177 rb_str_resize(buf, 0);
13178 break;
13179 }
13180 l = buflen < rest ? buflen : (long)rest;
13181 }
13182 if (!stp->src_fptr) {
13183 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13184
13185 if (read_method == id_read && NIL_P(rc))
13186 break;
13187 }
13188 else {
13189 ssize_t ss;
13190 rb_str_resize(buf, buflen);
13191 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13192 rb_str_resize(buf, ss > 0 ? ss : 0);
13193 if (ss < 0)
13194 return Qnil;
13195 if (ss == 0)
13196 rb_eof_error();
13197 if (off >= (rb_off_t)0)
13198 off += ss;
13199 }
13200 n = rb_io_write(stp->dst, buf);
13201 numwrote = NUM2LONG(n);
13202 stp->total += numwrote;
13203 rest -= numwrote;
13204 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13205 break;
13206 }
13207 }
13208
13209 return Qnil;
13210}
13211
13212static VALUE
13213copy_stream_fallback(struct copy_stream_struct *stp)
13214{
13215 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13216 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13217 }
13218 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13219 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13220 rb_eEOFError, (VALUE)0);
13221 return Qnil;
13222}
13223
13224static VALUE
13225copy_stream_body(VALUE arg)
13226{
13227 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13228 VALUE src_io = stp->src, dst_io = stp->dst;
13229 const int common_oflags = 0
13230#ifdef O_NOCTTY
13231 | O_NOCTTY
13232#endif
13233 ;
13234
13235 stp->th = rb_thread_current();
13236
13237 stp->total = 0;
13238
13239 if (src_io == argf ||
13240 !(RB_TYPE_P(src_io, T_FILE) ||
13241 RB_TYPE_P(src_io, T_STRING) ||
13242 rb_respond_to(src_io, rb_intern("to_path")))) {
13243 stp->src_fptr = NULL;
13244 }
13245 else {
13246 int stat_ret;
13247 VALUE tmp_io = rb_io_check_io(src_io);
13248 if (!NIL_P(tmp_io)) {
13249 src_io = tmp_io;
13250 }
13251 else if (!RB_TYPE_P(src_io, T_FILE)) {
13252 VALUE args[2];
13253 FilePathValue(src_io);
13254 args[0] = src_io;
13255 args[1] = INT2NUM(O_RDONLY|common_oflags);
13256 src_io = rb_class_new_instance(2, args, rb_cFile);
13257 stp->src = src_io;
13258 stp->close_src = 1;
13259 }
13260 RB_IO_POINTER(src_io, stp->src_fptr);
13261 rb_io_check_byte_readable(stp->src_fptr);
13262
13263 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13264 if (stat_ret < 0) {
13265 stp->syserr = "fstat";
13266 stp->error_no = errno;
13267 return Qnil;
13268 }
13269 }
13270
13271 if (dst_io == argf ||
13272 !(RB_TYPE_P(dst_io, T_FILE) ||
13273 RB_TYPE_P(dst_io, T_STRING) ||
13274 rb_respond_to(dst_io, rb_intern("to_path")))) {
13275 stp->dst_fptr = NULL;
13276 }
13277 else {
13278 int stat_ret;
13279 VALUE tmp_io = rb_io_check_io(dst_io);
13280 if (!NIL_P(tmp_io)) {
13281 dst_io = GetWriteIO(tmp_io);
13282 }
13283 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13284 VALUE args[3];
13285 FilePathValue(dst_io);
13286 args[0] = dst_io;
13287 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13288 args[2] = INT2FIX(0666);
13289 dst_io = rb_class_new_instance(3, args, rb_cFile);
13290 stp->dst = dst_io;
13291 stp->close_dst = 1;
13292 }
13293 else {
13294 dst_io = GetWriteIO(dst_io);
13295 stp->dst = dst_io;
13296 }
13297 RB_IO_POINTER(dst_io, stp->dst_fptr);
13298 rb_io_check_writable(stp->dst_fptr);
13299
13300 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13301 if (stat_ret < 0) {
13302 stp->syserr = "fstat";
13303 stp->error_no = errno;
13304 return Qnil;
13305 }
13306 }
13307
13308#ifdef O_BINARY
13309 if (stp->src_fptr)
13310 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13311#endif
13312 if (stp->dst_fptr)
13313 io_ascii8bit_binmode(stp->dst_fptr);
13314
13315 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13316 size_t len = stp->src_fptr->rbuf.len;
13317 VALUE str;
13318 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13319 len = (size_t)stp->copy_length;
13320 }
13321 str = rb_str_buf_new(len);
13322 rb_str_resize(str,len);
13323 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13324 if (stp->dst_fptr) { /* IO or filename */
13325 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13326 rb_sys_fail_on_write(stp->dst_fptr);
13327 }
13328 else /* others such as StringIO */
13329 rb_io_write(dst_io, str);
13330 rb_str_resize(str, 0);
13331 stp->total += len;
13332 if (stp->copy_length >= (rb_off_t)0)
13333 stp->copy_length -= len;
13334 }
13335
13336 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13337 rb_raise(rb_eIOError, "flush failed");
13338 }
13339
13340 if (stp->copy_length == 0)
13341 return Qnil;
13342
13343 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13344 return copy_stream_fallback(stp);
13345 }
13346
13347 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13348 return Qnil;
13349}
13350
13351static VALUE
13352copy_stream_finalize(VALUE arg)
13353{
13354 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13355
13356#ifdef HAVE_FCOPYFILE
13357 if (stp->copyfile_state) {
13358 copyfile_state_free(stp->copyfile_state);
13359 }
13360#endif
13361
13362 if (stp->close_src) {
13363 rb_io_close_m(stp->src);
13364 }
13365 if (stp->close_dst) {
13366 rb_io_close_m(stp->dst);
13367 }
13368 if (stp->syserr) {
13369 rb_syserr_fail(stp->error_no, stp->syserr);
13370 }
13371 if (stp->notimp) {
13372 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13373 }
13374 return Qnil;
13375}
13376
13377/*
13378 * call-seq:
13379 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13380 *
13381 * Copies from the given +src+ to the given +dst+,
13382 * returning the number of bytes copied.
13383 *
13384 * - The given +src+ must be one of the following:
13385 *
13386 * - The path to a readable file, from which source data is to be read.
13387 * - An \IO-like object, opened for reading and capable of responding
13388 * to method +:readpartial+ or method +:read+.
13389 *
13390 * - The given +dst+ must be one of the following:
13391 *
13392 * - The path to a writable file, to which data is to be written.
13393 * - An \IO-like object, opened for writing and capable of responding
13394 * to method +:write+.
13395 *
13396 * The examples here use file <tt>t.txt</tt> as source:
13397 *
13398 * File.read('t.txt')
13399 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13400 * File.read('t.txt').size # => 47
13401 *
13402 * If only arguments +src+ and +dst+ are given,
13403 * the entire source stream is copied:
13404 *
13405 * # Paths.
13406 * IO.copy_stream('t.txt', 't.tmp') # => 47
13407 *
13408 * # IOs (recall that a File is also an IO).
13409 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13410 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13411 * IO.copy_stream(src_io, dst_io) # => 47
13412 * src_io.close
13413 * dst_io.close
13414 *
13415 * With argument +src_length+ a non-negative integer,
13416 * no more than that many bytes are copied:
13417 *
13418 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13419 * File.read('t.tmp') # => "First line"
13420 *
13421 * With argument +src_offset+ also given,
13422 * the source stream is read beginning at that offset:
13423 *
13424 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13425 * IO.read('t.tmp') # => "Second line"
13426 *
13427 */
13428static VALUE
13429rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13430{
13431 VALUE src, dst, length, src_offset;
13432 struct copy_stream_struct st;
13433
13434 MEMZERO(&st, struct copy_stream_struct, 1);
13435
13436 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13437
13438 st.src = src;
13439 st.dst = dst;
13440
13441 st.src_fptr = NULL;
13442 st.dst_fptr = NULL;
13443
13444 if (NIL_P(length))
13445 st.copy_length = (rb_off_t)-1;
13446 else
13447 st.copy_length = NUM2OFFT(length);
13448
13449 if (NIL_P(src_offset))
13450 st.src_offset = (rb_off_t)-1;
13451 else
13452 st.src_offset = NUM2OFFT(src_offset);
13453
13454 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13455
13456 return OFFT2NUM(st.total);
13457}
13458
13459/*
13460 * call-seq:
13461 * external_encoding -> encoding or nil
13462 *
13463 * Returns the Encoding object that represents the encoding of the stream,
13464 * or +nil+ if the stream is in write mode and no encoding is specified.
13465 *
13466 * See {Encodings}[rdoc-ref:File@Encodings].
13467 *
13468 */
13469
13470static VALUE
13471rb_io_external_encoding(VALUE io)
13472{
13473 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13474
13475 if (fptr->encs.enc2) {
13476 return rb_enc_from_encoding(fptr->encs.enc2);
13477 }
13478 if (fptr->mode & FMODE_WRITABLE) {
13479 if (fptr->encs.enc)
13480 return rb_enc_from_encoding(fptr->encs.enc);
13481 return Qnil;
13482 }
13483 return rb_enc_from_encoding(io_read_encoding(fptr));
13484}
13485
13486/*
13487 * call-seq:
13488 * internal_encoding -> encoding or nil
13489 *
13490 * Returns the Encoding object that represents the encoding of the internal string,
13491 * if conversion is specified,
13492 * or +nil+ otherwise.
13493 *
13494 * See {Encodings}[rdoc-ref:File@Encodings].
13495 *
13496 */
13497
13498static VALUE
13499rb_io_internal_encoding(VALUE io)
13500{
13501 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13502
13503 if (!fptr->encs.enc2) return Qnil;
13504 return rb_enc_from_encoding(io_read_encoding(fptr));
13505}
13506
13507/*
13508 * call-seq:
13509 * set_encoding(ext_enc) -> self
13510 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13511 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13512 *
13513 * See {Encodings}[rdoc-ref:File@Encodings].
13514 *
13515 * Argument +ext_enc+, if given, must be an Encoding object
13516 * or a String with the encoding name;
13517 * it is assigned as the encoding for the stream.
13518 *
13519 * Argument +int_enc+, if given, must be an Encoding object
13520 * or a String with the encoding name;
13521 * it is assigned as the encoding for the internal string.
13522 *
13523 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13524 * containing two colon-separated encoding names;
13525 * corresponding Encoding objects are assigned as the external
13526 * and internal encodings for the stream.
13527 *
13528 * If the external encoding of a string is binary/ASCII-8BIT,
13529 * the internal encoding of the string is set to nil, since no
13530 * transcoding is needed.
13531 *
13532 * Optional keyword arguments +enc_opts+ specify
13533 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13534 *
13535 */
13536
13537static VALUE
13538rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13539{
13540 rb_io_t *fptr;
13541 VALUE v1, v2, opt;
13542
13543 if (!RB_TYPE_P(io, T_FILE)) {
13544 return forward(io, id_set_encoding, argc, argv);
13545 }
13546
13547 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13548 GetOpenFile(io, fptr);
13549 io_encoding_set(fptr, v1, v2, opt);
13550 return io;
13551}
13552
13553void
13554rb_stdio_set_default_encoding(void)
13555{
13556 VALUE val = Qnil;
13557
13558#ifdef _WIN32
13559 if (isatty(fileno(stdin))) {
13560 rb_encoding *external = rb_locale_encoding();
13561 rb_encoding *internal = rb_default_internal_encoding();
13562 if (!internal) internal = rb_default_external_encoding();
13563 io_encoding_set(RFILE(rb_stdin)->fptr,
13564 rb_enc_from_encoding(external),
13565 rb_enc_from_encoding(internal),
13566 Qnil);
13567 }
13568 else
13569#endif
13570 rb_io_set_encoding(1, &val, rb_stdin);
13571 rb_io_set_encoding(1, &val, rb_stdout);
13572 rb_io_set_encoding(1, &val, rb_stderr);
13573}
13574
13575static inline int
13576global_argf_p(VALUE arg)
13577{
13578 return arg == argf;
13579}
13580
13581typedef VALUE (*argf_encoding_func)(VALUE io);
13582
13583static VALUE
13584argf_encoding(VALUE argf, argf_encoding_func func)
13585{
13586 if (!RTEST(ARGF.current_file)) {
13587 return rb_enc_default_external();
13588 }
13589 return func(rb_io_check_io(ARGF.current_file));
13590}
13591
13592/*
13593 * call-seq:
13594 * ARGF.external_encoding -> encoding
13595 *
13596 * Returns the external encoding for files read from ARGF as an Encoding
13597 * object. The external encoding is the encoding of the text as stored in a
13598 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13599 * represent this text within Ruby.
13600 *
13601 * To set the external encoding use ARGF.set_encoding.
13602 *
13603 * For example:
13604 *
13605 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13606 *
13607 */
13608static VALUE
13609argf_external_encoding(VALUE argf)
13610{
13611 return argf_encoding(argf, rb_io_external_encoding);
13612}
13613
13614/*
13615 * call-seq:
13616 * ARGF.internal_encoding -> encoding
13617 *
13618 * Returns the internal encoding for strings read from ARGF as an
13619 * Encoding object.
13620 *
13621 * If ARGF.set_encoding has been called with two encoding names, the second
13622 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13623 * value is returned. Failing that, if a default external encoding was
13624 * specified on the command-line, that value is used. If the encoding is
13625 * unknown, +nil+ is returned.
13626 */
13627static VALUE
13628argf_internal_encoding(VALUE argf)
13629{
13630 return argf_encoding(argf, rb_io_internal_encoding);
13631}
13632
13633/*
13634 * call-seq:
13635 * ARGF.set_encoding(ext_enc) -> ARGF
13636 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13637 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13638 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13639 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13640 *
13641 * If single argument is specified, strings read from ARGF are tagged with
13642 * the encoding specified.
13643 *
13644 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13645 * the read string is converted from the first encoding (external encoding)
13646 * to the second encoding (internal encoding), then tagged with the second
13647 * encoding.
13648 *
13649 * If two arguments are specified, they must be encoding objects or encoding
13650 * names. Again, the first specifies the external encoding; the second
13651 * specifies the internal encoding.
13652 *
13653 * If the external encoding and the internal encoding are specified, the
13654 * optional Hash argument can be used to adjust the conversion process. The
13655 * structure of this hash is explained in the String#encode documentation.
13656 *
13657 * For example:
13658 *
13659 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13660 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13661 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13662 * # to UTF-8.
13663 */
13664static VALUE
13665argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13666{
13667 rb_io_t *fptr;
13668
13669 if (!next_argv()) {
13670 rb_raise(rb_eArgError, "no stream to set encoding");
13671 }
13672 rb_io_set_encoding(argc, argv, ARGF.current_file);
13673 GetOpenFile(ARGF.current_file, fptr);
13674 ARGF.encs = fptr->encs;
13675 return argf;
13676}
13677
13678/*
13679 * call-seq:
13680 * ARGF.tell -> Integer
13681 * ARGF.pos -> Integer
13682 *
13683 * Returns the current offset (in bytes) of the current file in ARGF.
13684 *
13685 * ARGF.pos #=> 0
13686 * ARGF.gets #=> "This is line one\n"
13687 * ARGF.pos #=> 17
13688 *
13689 */
13690static VALUE
13691argf_tell(VALUE argf)
13692{
13693 if (!next_argv()) {
13694 rb_raise(rb_eArgError, "no stream to tell");
13695 }
13696 ARGF_FORWARD(0, 0);
13697 return rb_io_tell(ARGF.current_file);
13698}
13699
13700/*
13701 * call-seq:
13702 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13703 *
13704 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13705 * the value of _whence_. See IO#seek for further details.
13706 */
13707static VALUE
13708argf_seek_m(int argc, VALUE *argv, VALUE argf)
13709{
13710 if (!next_argv()) {
13711 rb_raise(rb_eArgError, "no stream to seek");
13712 }
13713 ARGF_FORWARD(argc, argv);
13714 return rb_io_seek_m(argc, argv, ARGF.current_file);
13715}
13716
13717/*
13718 * call-seq:
13719 * ARGF.pos = position -> Integer
13720 *
13721 * Seeks to the position given by _position_ (in bytes) in ARGF.
13722 *
13723 * For example:
13724 *
13725 * ARGF.pos = 17
13726 * ARGF.gets #=> "This is line two\n"
13727 */
13728static VALUE
13729argf_set_pos(VALUE argf, VALUE offset)
13730{
13731 if (!next_argv()) {
13732 rb_raise(rb_eArgError, "no stream to set position");
13733 }
13734 ARGF_FORWARD(1, &offset);
13735 return rb_io_set_pos(ARGF.current_file, offset);
13736}
13737
13738/*
13739 * call-seq:
13740 * ARGF.rewind -> 0
13741 *
13742 * Positions the current file to the beginning of input, resetting
13743 * ARGF.lineno to zero.
13744 *
13745 * ARGF.readline #=> "This is line one\n"
13746 * ARGF.rewind #=> 0
13747 * ARGF.lineno #=> 0
13748 * ARGF.readline #=> "This is line one\n"
13749 */
13750static VALUE
13751argf_rewind(VALUE argf)
13752{
13753 VALUE ret;
13754 int old_lineno;
13755
13756 if (!next_argv()) {
13757 rb_raise(rb_eArgError, "no stream to rewind");
13758 }
13759 ARGF_FORWARD(0, 0);
13760 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13761 ret = rb_io_rewind(ARGF.current_file);
13762 if (!global_argf_p(argf)) {
13763 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13764 }
13765 return ret;
13766}
13767
13768/*
13769 * call-seq:
13770 * ARGF.fileno -> integer
13771 * ARGF.to_i -> integer
13772 *
13773 * Returns an integer representing the numeric file descriptor for
13774 * the current file. Raises an ArgumentError if there isn't a current file.
13775 *
13776 * ARGF.fileno #=> 3
13777 */
13778static VALUE
13779argf_fileno(VALUE argf)
13780{
13781 if (!next_argv()) {
13782 rb_raise(rb_eArgError, "no stream");
13783 }
13784 ARGF_FORWARD(0, 0);
13785 return rb_io_fileno(ARGF.current_file);
13786}
13787
13788/*
13789 * call-seq:
13790 * ARGF.to_io -> IO
13791 *
13792 * Returns an IO object representing the current file. This will be a
13793 * File object unless the current file is a stream such as STDIN.
13794 *
13795 * For example:
13796 *
13797 * ARGF.to_io #=> #<File:glark.txt>
13798 * ARGF.to_io #=> #<IO:<STDIN>>
13799 */
13800static VALUE
13801argf_to_io(VALUE argf)
13802{
13803 next_argv();
13804 ARGF_FORWARD(0, 0);
13805 return ARGF.current_file;
13806}
13807
13808/*
13809 * call-seq:
13810 * ARGF.eof? -> true or false
13811 * ARGF.eof -> true or false
13812 *
13813 * Returns true if the current file in ARGF is at end of file, i.e. it has
13814 * no data to read. The stream must be opened for reading or an IOError
13815 * will be raised.
13816 *
13817 * $ echo "eof" | ruby argf.rb
13818 *
13819 * ARGF.eof? #=> false
13820 * 3.times { ARGF.readchar }
13821 * ARGF.eof? #=> false
13822 * ARGF.readchar #=> "\n"
13823 * ARGF.eof? #=> true
13824 */
13825
13826static VALUE
13827argf_eof(VALUE argf)
13828{
13829 next_argv();
13830 if (RTEST(ARGF.current_file)) {
13831 if (ARGF.init_p == 0) return Qtrue;
13832 next_argv();
13833 ARGF_FORWARD(0, 0);
13834 if (rb_io_eof(ARGF.current_file)) {
13835 return Qtrue;
13836 }
13837 }
13838 return Qfalse;
13839}
13840
13841/*
13842 * call-seq:
13843 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13844 *
13845 * Reads _length_ bytes from ARGF. The files named on the command line
13846 * are concatenated and treated as a single file by this method, so when
13847 * called without arguments the contents of this pseudo file are returned in
13848 * their entirety.
13849 *
13850 * _length_ must be a non-negative integer or +nil+.
13851 *
13852 * If _length_ is a positive integer, +read+ tries to read
13853 * _length_ bytes without any conversion (binary mode).
13854 * It returns +nil+ if an EOF is encountered before anything can be read.
13855 * Fewer than _length_ bytes are returned if an EOF is encountered during
13856 * the read.
13857 * In the case of an integer _length_, the resulting string is always
13858 * in ASCII-8BIT encoding.
13859 *
13860 * If _length_ is omitted or is +nil+, it reads until EOF
13861 * and the encoding conversion is applied, if applicable.
13862 * A string is returned even if EOF is encountered before any data is read.
13863 *
13864 * If _length_ is zero, it returns an empty string (<code>""</code>).
13865 *
13866 * If the optional _outbuf_ argument is present,
13867 * it must reference a String, which will receive the data.
13868 * The _outbuf_ will contain only the received data after the method call
13869 * even if it is not empty at the beginning.
13870 *
13871 * For example:
13872 *
13873 * $ echo "small" > small.txt
13874 * $ echo "large" > large.txt
13875 * $ ./glark.rb small.txt large.txt
13876 *
13877 * ARGF.read #=> "small\nlarge"
13878 * ARGF.read(200) #=> "small\nlarge"
13879 * ARGF.read(2) #=> "sm"
13880 * ARGF.read(0) #=> ""
13881 *
13882 * Note that this method behaves like the fread() function in C.
13883 * This means it retries to invoke read(2) system calls to read data
13884 * with the specified length.
13885 * If you need the behavior like a single read(2) system call,
13886 * consider ARGF#readpartial or ARGF#read_nonblock.
13887 */
13888
13889static VALUE
13890argf_read(int argc, VALUE *argv, VALUE argf)
13891{
13892 VALUE tmp, str, length;
13893 long len = 0;
13894
13895 rb_scan_args(argc, argv, "02", &length, &str);
13896 if (!NIL_P(length)) {
13897 len = NUM2LONG(argv[0]);
13898 }
13899 if (!NIL_P(str)) {
13900 StringValue(str);
13901 rb_str_resize(str,0);
13902 argv[1] = Qnil;
13903 }
13904
13905 retry:
13906 if (!next_argv()) {
13907 return str;
13908 }
13909 if (ARGF_GENERIC_INPUT_P()) {
13910 tmp = argf_forward(argc, argv, argf);
13911 }
13912 else {
13913 tmp = io_read(argc, argv, ARGF.current_file);
13914 }
13915 if (NIL_P(str)) str = tmp;
13916 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13917 if (NIL_P(tmp) || NIL_P(length)) {
13918 if (ARGF.next_p != -1) {
13919 argf_close(argf);
13920 ARGF.next_p = 1;
13921 goto retry;
13922 }
13923 }
13924 else if (argc >= 1) {
13925 long slen = RSTRING_LEN(str);
13926 if (slen < len) {
13927 argv[0] = LONG2NUM(len - slen);
13928 goto retry;
13929 }
13930 }
13931 return str;
13932}
13933
13935 int argc;
13936 VALUE *argv;
13937 VALUE argf;
13938};
13939
13940static VALUE
13941argf_forward_call(VALUE arg)
13942{
13943 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13944 argf_forward(p->argc, p->argv, p->argf);
13945 return Qnil;
13946}
13947
13948static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13949 int nonblock);
13950
13951/*
13952 * call-seq:
13953 * ARGF.readpartial(maxlen) -> string
13954 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13955 *
13956 * Reads at most _maxlen_ bytes from the ARGF stream.
13957 *
13958 * If the optional _outbuf_ argument is present,
13959 * it must reference a String, which will receive the data.
13960 * The _outbuf_ will contain only the received data after the method call
13961 * even if it is not empty at the beginning.
13962 *
13963 * It raises EOFError on end of ARGF stream.
13964 * Since ARGF stream is a concatenation of multiple files,
13965 * internally EOF is occur for each file.
13966 * ARGF.readpartial returns empty strings for EOFs except the last one and
13967 * raises EOFError for the last one.
13968 *
13969 */
13970
13971static VALUE
13972argf_readpartial(int argc, VALUE *argv, VALUE argf)
13973{
13974 return argf_getpartial(argc, argv, argf, Qnil, 0);
13975}
13976
13977/*
13978 * call-seq:
13979 * ARGF.read_nonblock(maxlen[, options]) -> string
13980 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13981 *
13982 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13983 */
13984
13985static VALUE
13986argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13987{
13988 VALUE opts;
13989
13990 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
13991
13992 if (!NIL_P(opts))
13993 argc--;
13994
13995 return argf_getpartial(argc, argv, argf, opts, 1);
13996}
13997
13998static VALUE
13999argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14000{
14001 VALUE tmp, str, length;
14002 int no_exception;
14003
14004 rb_scan_args(argc, argv, "11", &length, &str);
14005 if (!NIL_P(str)) {
14006 StringValue(str);
14007 argv[1] = str;
14008 }
14009 no_exception = no_exception_p(opts);
14010
14011 if (!next_argv()) {
14012 if (!NIL_P(str)) {
14013 rb_str_resize(str, 0);
14014 }
14015 rb_eof_error();
14016 }
14017 if (ARGF_GENERIC_INPUT_P()) {
14018 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14019 struct argf_call_arg arg;
14020 arg.argc = argc;
14021 arg.argv = argv;
14022 arg.argf = argf;
14023 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14024 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14025 }
14026 else {
14027 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14028 }
14029 if (NIL_P(tmp)) {
14030 if (ARGF.next_p == -1) {
14031 return io_nonblock_eof(no_exception);
14032 }
14033 argf_close(argf);
14034 ARGF.next_p = 1;
14035 if (RARRAY_LEN(ARGF.argv) == 0) {
14036 return io_nonblock_eof(no_exception);
14037 }
14038 if (NIL_P(str))
14039 str = rb_str_new(NULL, 0);
14040 return str;
14041 }
14042 return tmp;
14043}
14044
14045/*
14046 * call-seq:
14047 * ARGF.getc -> String or nil
14048 *
14049 * Reads the next character from ARGF and returns it as a String. Returns
14050 * +nil+ at the end of the stream.
14051 *
14052 * ARGF treats the files named on the command line as a single file created
14053 * by concatenating their contents. After returning the last character of the
14054 * first file, it returns the first character of the second file, and so on.
14055 *
14056 * For example:
14057 *
14058 * $ echo "foo" > file
14059 * $ ruby argf.rb file
14060 *
14061 * ARGF.getc #=> "f"
14062 * ARGF.getc #=> "o"
14063 * ARGF.getc #=> "o"
14064 * ARGF.getc #=> "\n"
14065 * ARGF.getc #=> nil
14066 * ARGF.getc #=> nil
14067 */
14068static VALUE
14069argf_getc(VALUE argf)
14070{
14071 VALUE ch;
14072
14073 retry:
14074 if (!next_argv()) return Qnil;
14075 if (ARGF_GENERIC_INPUT_P()) {
14076 ch = forward_current(rb_intern("getc"), 0, 0);
14077 }
14078 else {
14079 ch = rb_io_getc(ARGF.current_file);
14080 }
14081 if (NIL_P(ch) && ARGF.next_p != -1) {
14082 argf_close(argf);
14083 ARGF.next_p = 1;
14084 goto retry;
14085 }
14086
14087 return ch;
14088}
14089
14090/*
14091 * call-seq:
14092 * ARGF.getbyte -> Integer or nil
14093 *
14094 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14095 * the end of the stream.
14096 *
14097 * For example:
14098 *
14099 * $ echo "foo" > file
14100 * $ ruby argf.rb file
14101 *
14102 * ARGF.getbyte #=> 102
14103 * ARGF.getbyte #=> 111
14104 * ARGF.getbyte #=> 111
14105 * ARGF.getbyte #=> 10
14106 * ARGF.getbyte #=> nil
14107 */
14108static VALUE
14109argf_getbyte(VALUE argf)
14110{
14111 VALUE ch;
14112
14113 retry:
14114 if (!next_argv()) return Qnil;
14115 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14116 ch = forward_current(rb_intern("getbyte"), 0, 0);
14117 }
14118 else {
14119 ch = rb_io_getbyte(ARGF.current_file);
14120 }
14121 if (NIL_P(ch) && ARGF.next_p != -1) {
14122 argf_close(argf);
14123 ARGF.next_p = 1;
14124 goto retry;
14125 }
14126
14127 return ch;
14128}
14129
14130/*
14131 * call-seq:
14132 * ARGF.readchar -> String or nil
14133 *
14134 * Reads the next character from ARGF and returns it as a String. Raises
14135 * an EOFError after the last character of the last file has been read.
14136 *
14137 * For example:
14138 *
14139 * $ echo "foo" > file
14140 * $ ruby argf.rb file
14141 *
14142 * ARGF.readchar #=> "f"
14143 * ARGF.readchar #=> "o"
14144 * ARGF.readchar #=> "o"
14145 * ARGF.readchar #=> "\n"
14146 * ARGF.readchar #=> end of file reached (EOFError)
14147 */
14148static VALUE
14149argf_readchar(VALUE argf)
14150{
14151 VALUE ch;
14152
14153 retry:
14154 if (!next_argv()) rb_eof_error();
14155 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14156 ch = forward_current(rb_intern("getc"), 0, 0);
14157 }
14158 else {
14159 ch = rb_io_getc(ARGF.current_file);
14160 }
14161 if (NIL_P(ch) && ARGF.next_p != -1) {
14162 argf_close(argf);
14163 ARGF.next_p = 1;
14164 goto retry;
14165 }
14166
14167 return ch;
14168}
14169
14170/*
14171 * call-seq:
14172 * ARGF.readbyte -> Integer
14173 *
14174 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14175 * an EOFError after the last byte of the last file has been read.
14176 *
14177 * For example:
14178 *
14179 * $ echo "foo" > file
14180 * $ ruby argf.rb file
14181 *
14182 * ARGF.readbyte #=> 102
14183 * ARGF.readbyte #=> 111
14184 * ARGF.readbyte #=> 111
14185 * ARGF.readbyte #=> 10
14186 * ARGF.readbyte #=> end of file reached (EOFError)
14187 */
14188static VALUE
14189argf_readbyte(VALUE argf)
14190{
14191 VALUE c;
14192
14193 NEXT_ARGF_FORWARD(0, 0);
14194 c = argf_getbyte(argf);
14195 if (NIL_P(c)) {
14196 rb_eof_error();
14197 }
14198 return c;
14199}
14200
14201#define FOREACH_ARGF() while (next_argv())
14202
14203static VALUE
14204argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14205{
14206 const VALUE current = ARGF.current_file;
14207 rb_yield_values2(argc, argv);
14208 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14210 }
14211 return Qnil;
14212}
14213
14214#define ARGF_block_call(mid, argc, argv, func, argf) \
14215 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14216 func, argf, rb_keyword_given_p())
14217
14218static void
14219argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14220{
14221 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14222 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14223}
14224
14225static VALUE
14226argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14227{
14228 if (!global_argf_p(argf)) {
14229 ARGF.last_lineno = ++ARGF.lineno;
14230 }
14231 return argf_block_call_i(i, argf, argc, argv, blockarg);
14232}
14233
14234static void
14235argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14236{
14237 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14238 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14239}
14240
14241/*
14242 * call-seq:
14243 * ARGF.each(sep=$/) {|line| block } -> ARGF
14244 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14245 * ARGF.each(...) -> an_enumerator
14246 *
14247 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14248 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14249 * ARGF.each_line(...) -> an_enumerator
14250 *
14251 * Returns an enumerator which iterates over each line (separated by _sep_,
14252 * which defaults to your platform's newline character) of each file in
14253 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14254 * block, otherwise an enumerator is returned.
14255 * The optional _limit_ argument is an Integer specifying the maximum
14256 * length of each line; longer lines will be split according to this limit.
14257 *
14258 * This method allows you to treat the files supplied on the command line as
14259 * a single file consisting of the concatenation of each named file. After
14260 * the last line of the first file has been returned, the first line of the
14261 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14262 * used to determine the filename of the current line and line number of the
14263 * whole input, respectively.
14264 *
14265 * For example, the following code prints out each line of each named file
14266 * prefixed with its line number, displaying the filename once per file:
14267 *
14268 * ARGF.each_line do |line|
14269 * puts ARGF.filename if ARGF.file.lineno == 1
14270 * puts "#{ARGF.file.lineno}: #{line}"
14271 * end
14272 *
14273 * While the following code prints only the first file's name at first, and
14274 * the contents with line number counted through all named files.
14275 *
14276 * ARGF.each_line do |line|
14277 * puts ARGF.filename if ARGF.lineno == 1
14278 * puts "#{ARGF.lineno}: #{line}"
14279 * end
14280 */
14281static VALUE
14282argf_each_line(int argc, VALUE *argv, VALUE argf)
14283{
14284 RETURN_ENUMERATOR(argf, argc, argv);
14285 FOREACH_ARGF() {
14286 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14287 }
14288 return argf;
14289}
14290
14291/*
14292 * call-seq:
14293 * ARGF.each_byte {|byte| block } -> ARGF
14294 * ARGF.each_byte -> an_enumerator
14295 *
14296 * Iterates over each byte of each file in +ARGV+.
14297 * A byte is returned as an Integer in the range 0..255.
14298 *
14299 * This method allows you to treat the files supplied on the command line as
14300 * a single file consisting of the concatenation of each named file. After
14301 * the last byte of the first file has been returned, the first byte of the
14302 * second file is returned. The ARGF.filename method can be used to
14303 * determine the filename of the current byte.
14304 *
14305 * If no block is given, an enumerator is returned instead.
14306 *
14307 * For example:
14308 *
14309 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14310 *
14311 */
14312static VALUE
14313argf_each_byte(VALUE argf)
14314{
14315 RETURN_ENUMERATOR(argf, 0, 0);
14316 FOREACH_ARGF() {
14317 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14318 }
14319 return argf;
14320}
14321
14322/*
14323 * call-seq:
14324 * ARGF.each_char {|char| block } -> ARGF
14325 * ARGF.each_char -> an_enumerator
14326 *
14327 * Iterates over each character of each file in ARGF.
14328 *
14329 * This method allows you to treat the files supplied on the command line as
14330 * a single file consisting of the concatenation of each named file. After
14331 * the last character of the first file has been returned, the first
14332 * character of the second file is returned. The ARGF.filename method can
14333 * be used to determine the name of the file in which the current character
14334 * appears.
14335 *
14336 * If no block is given, an enumerator is returned instead.
14337 */
14338static VALUE
14339argf_each_char(VALUE argf)
14340{
14341 RETURN_ENUMERATOR(argf, 0, 0);
14342 FOREACH_ARGF() {
14343 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14344 }
14345 return argf;
14346}
14347
14348/*
14349 * call-seq:
14350 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14351 * ARGF.each_codepoint -> an_enumerator
14352 *
14353 * Iterates over each codepoint of each file in ARGF.
14354 *
14355 * This method allows you to treat the files supplied on the command line as
14356 * a single file consisting of the concatenation of each named file. After
14357 * the last codepoint of the first file has been returned, the first
14358 * codepoint of the second file is returned. The ARGF.filename method can
14359 * be used to determine the name of the file in which the current codepoint
14360 * appears.
14361 *
14362 * If no block is given, an enumerator is returned instead.
14363 */
14364static VALUE
14365argf_each_codepoint(VALUE argf)
14366{
14367 RETURN_ENUMERATOR(argf, 0, 0);
14368 FOREACH_ARGF() {
14369 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14370 }
14371 return argf;
14372}
14373
14374/*
14375 * call-seq:
14376 * ARGF.filename -> String
14377 * ARGF.path -> String
14378 *
14379 * Returns the current filename. "-" is returned when the current file is
14380 * STDIN.
14381 *
14382 * For example:
14383 *
14384 * $ echo "foo" > foo
14385 * $ echo "bar" > bar
14386 * $ echo "glark" > glark
14387 *
14388 * $ ruby argf.rb foo bar glark
14389 *
14390 * ARGF.filename #=> "foo"
14391 * ARGF.read(5) #=> "foo\nb"
14392 * ARGF.filename #=> "bar"
14393 * ARGF.skip
14394 * ARGF.filename #=> "glark"
14395 */
14396static VALUE
14397argf_filename(VALUE argf)
14398{
14399 next_argv();
14400 return ARGF.filename;
14401}
14402
14403static VALUE
14404argf_filename_getter(ID id, VALUE *var)
14405{
14406 return argf_filename(*var);
14407}
14408
14409/*
14410 * call-seq:
14411 * ARGF.file -> IO or File object
14412 *
14413 * Returns the current file as an IO or File object.
14414 * <code>$stdin</code> is returned when the current file is STDIN.
14415 *
14416 * For example:
14417 *
14418 * $ echo "foo" > foo
14419 * $ echo "bar" > bar
14420 *
14421 * $ ruby argf.rb foo bar
14422 *
14423 * ARGF.file #=> #<File:foo>
14424 * ARGF.read(5) #=> "foo\nb"
14425 * ARGF.file #=> #<File:bar>
14426 */
14427static VALUE
14428argf_file(VALUE argf)
14429{
14430 next_argv();
14431 return ARGF.current_file;
14432}
14433
14434/*
14435 * call-seq:
14436 * ARGF.binmode -> ARGF
14437 *
14438 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14439 * be reset to non-binary mode. This option has the following effects:
14440 *
14441 * * Newline conversion is disabled.
14442 * * Encoding conversion is disabled.
14443 * * Content is treated as ASCII-8BIT.
14444 */
14445static VALUE
14446argf_binmode_m(VALUE argf)
14447{
14448 ARGF.binmode = 1;
14449 next_argv();
14450 ARGF_FORWARD(0, 0);
14451 rb_io_ascii8bit_binmode(ARGF.current_file);
14452 return argf;
14453}
14454
14455/*
14456 * call-seq:
14457 * ARGF.binmode? -> true or false
14458 *
14459 * Returns true if ARGF is being read in binary mode; false otherwise.
14460 * To enable binary mode use ARGF.binmode.
14461 *
14462 * For example:
14463 *
14464 * ARGF.binmode? #=> false
14465 * ARGF.binmode
14466 * ARGF.binmode? #=> true
14467 */
14468static VALUE
14469argf_binmode_p(VALUE argf)
14470{
14471 return RBOOL(ARGF.binmode);
14472}
14473
14474/*
14475 * call-seq:
14476 * ARGF.skip -> ARGF
14477 *
14478 * Sets the current file to the next file in ARGV. If there aren't any more
14479 * files it has no effect.
14480 *
14481 * For example:
14482 *
14483 * $ ruby argf.rb foo bar
14484 * ARGF.filename #=> "foo"
14485 * ARGF.skip
14486 * ARGF.filename #=> "bar"
14487 */
14488static VALUE
14489argf_skip(VALUE argf)
14490{
14491 if (ARGF.init_p && ARGF.next_p == 0) {
14492 argf_close(argf);
14493 ARGF.next_p = 1;
14494 }
14495 return argf;
14496}
14497
14498/*
14499 * call-seq:
14500 * ARGF.close -> ARGF
14501 *
14502 * Closes the current file and skips to the next file in ARGV. If there are
14503 * no more files to open, just closes the current file. STDIN will not be
14504 * closed.
14505 *
14506 * For example:
14507 *
14508 * $ ruby argf.rb foo bar
14509 *
14510 * ARGF.filename #=> "foo"
14511 * ARGF.close
14512 * ARGF.filename #=> "bar"
14513 * ARGF.close
14514 */
14515static VALUE
14516argf_close_m(VALUE argf)
14517{
14518 next_argv();
14519 argf_close(argf);
14520 if (ARGF.next_p != -1) {
14521 ARGF.next_p = 1;
14522 }
14523 ARGF.lineno = 0;
14524 return argf;
14525}
14526
14527/*
14528 * call-seq:
14529 * ARGF.closed? -> true or false
14530 *
14531 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14532 * ARGF.close to actually close the current file.
14533 */
14534static VALUE
14535argf_closed(VALUE argf)
14536{
14537 next_argv();
14538 ARGF_FORWARD(0, 0);
14539 return rb_io_closed_p(ARGF.current_file);
14540}
14541
14542/*
14543 * call-seq:
14544 * ARGF.to_s -> String
14545 *
14546 * Returns "ARGF".
14547 */
14548static VALUE
14549argf_to_s(VALUE argf)
14550{
14551 return rb_str_new2("ARGF");
14552}
14553
14554/*
14555 * call-seq:
14556 * ARGF.inplace_mode -> String
14557 *
14558 * Returns the file extension appended to the names of backup copies of
14559 * modified files under in-place edit mode. This value can be set using
14560 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14561 */
14562static VALUE
14563argf_inplace_mode_get(VALUE argf)
14564{
14565 if (!ARGF.inplace) return Qnil;
14566 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14567 return rb_str_dup(ARGF.inplace);
14568}
14569
14570static VALUE
14571opt_i_get(ID id, VALUE *var)
14572{
14573 return argf_inplace_mode_get(*var);
14574}
14575
14576/*
14577 * call-seq:
14578 * ARGF.inplace_mode = ext -> ARGF
14579 *
14580 * Sets the filename extension for in-place editing mode to the given String.
14581 * The backup copy of each file being edited has this value appended to its
14582 * filename.
14583 *
14584 * For example:
14585 *
14586 * $ ruby argf.rb file.txt
14587 *
14588 * ARGF.inplace_mode = '.bak'
14589 * ARGF.each_line do |line|
14590 * print line.sub("foo","bar")
14591 * end
14592 *
14593 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14594 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14595 * "bar".
14596 */
14597static VALUE
14598argf_inplace_mode_set(VALUE argf, VALUE val)
14599{
14600 if (!RTEST(val)) {
14601 ARGF.inplace = Qfalse;
14602 }
14603 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14604 ARGF.inplace = Qnil;
14605 }
14606 else {
14607 ARGF.inplace = rb_str_new_frozen(val);
14608 }
14609 return argf;
14610}
14611
14612static void
14613opt_i_set(VALUE val, ID id, VALUE *var)
14614{
14615 argf_inplace_mode_set(*var, val);
14616}
14617
14618void
14619ruby_set_inplace_mode(const char *suffix)
14620{
14621 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14622}
14623
14624/*
14625 * call-seq:
14626 * ARGF.argv -> ARGV
14627 *
14628 * Returns the +ARGV+ array, which contains the arguments passed to your
14629 * script, one per element.
14630 *
14631 * For example:
14632 *
14633 * $ ruby argf.rb -v glark.txt
14634 *
14635 * ARGF.argv #=> ["-v", "glark.txt"]
14636 *
14637 */
14638static VALUE
14639argf_argv(VALUE argf)
14640{
14641 return ARGF.argv;
14642}
14643
14644static VALUE
14645argf_argv_getter(ID id, VALUE *var)
14646{
14647 return argf_argv(*var);
14648}
14649
14650VALUE
14652{
14653 return ARGF.argv;
14654}
14655
14656/*
14657 * call-seq:
14658 * ARGF.to_write_io -> io
14659 *
14660 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14661 * enabled.
14662 */
14663static VALUE
14664argf_write_io(VALUE argf)
14665{
14666 if (!RTEST(ARGF.current_file)) {
14667 rb_raise(rb_eIOError, "not opened for writing");
14668 }
14669 return GetWriteIO(ARGF.current_file);
14670}
14671
14672/*
14673 * call-seq:
14674 * ARGF.write(*objects) -> integer
14675 *
14676 * Writes each of the given +objects+ if inplace mode.
14677 */
14678static VALUE
14679argf_write(int argc, VALUE *argv, VALUE argf)
14680{
14681 return rb_io_writev(argf_write_io(argf), argc, argv);
14682}
14683
14684void
14685rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14686{
14687 rb_readwrite_syserr_fail(waiting, errno, mesg);
14688}
14689
14690void
14691rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14692{
14693 VALUE arg, c = Qnil;
14694 arg = mesg ? rb_str_new2(mesg) : Qnil;
14695 switch (waiting) {
14696 case RB_IO_WAIT_WRITABLE:
14697 switch (n) {
14698 case EAGAIN:
14699 c = rb_eEAGAINWaitWritable;
14700 break;
14701#if EAGAIN != EWOULDBLOCK
14702 case EWOULDBLOCK:
14703 c = rb_eEWOULDBLOCKWaitWritable;
14704 break;
14705#endif
14706 case EINPROGRESS:
14707 c = rb_eEINPROGRESSWaitWritable;
14708 break;
14709 default:
14711 }
14712 break;
14713 case RB_IO_WAIT_READABLE:
14714 switch (n) {
14715 case EAGAIN:
14716 c = rb_eEAGAINWaitReadable;
14717 break;
14718#if EAGAIN != EWOULDBLOCK
14719 case EWOULDBLOCK:
14720 c = rb_eEWOULDBLOCKWaitReadable;
14721 break;
14722#endif
14723 case EINPROGRESS:
14724 c = rb_eEINPROGRESSWaitReadable;
14725 break;
14726 default:
14728 }
14729 break;
14730 default:
14731 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14732 }
14734}
14735
14736static VALUE
14737get_LAST_READ_LINE(ID _x, VALUE *_y)
14738{
14739 return rb_lastline_get();
14740}
14741
14742static void
14743set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14744{
14745 rb_lastline_set(val);
14746}
14747
14748/*
14749 * Document-class: IOError
14750 *
14751 * Raised when an IO operation fails.
14752 *
14753 * File.open("/etc/hosts") {|f| f << "example"}
14754 * #=> IOError: not opened for writing
14755 *
14756 * File.open("/etc/hosts") {|f| f.close; f.read }
14757 * #=> IOError: closed stream
14758 *
14759 * Note that some IO failures raise <code>SystemCallError</code>s
14760 * and these are not subclasses of IOError:
14761 *
14762 * File.open("does/not/exist")
14763 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14764 */
14765
14766/*
14767 * Document-class: EOFError
14768 *
14769 * Raised by some IO operations when reaching the end of file. Many IO
14770 * methods exist in two forms,
14771 *
14772 * one that returns +nil+ when the end of file is reached, the other
14773 * raises EOFError.
14774 *
14775 * EOFError is a subclass of IOError.
14776 *
14777 * file = File.open("/etc/hosts")
14778 * file.read
14779 * file.gets #=> nil
14780 * file.readline #=> EOFError: end of file reached
14781 * file.close
14782 */
14783
14784/*
14785 * Document-class: ARGF
14786 *
14787 * == \ARGF and +ARGV+
14788 *
14789 * The \ARGF object works with the array at global variable +ARGV+
14790 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14791 *
14792 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14793 *
14794 * Initially, it contains the command-line arguments and options
14795 * that are passed to the Ruby program;
14796 * the program can modify that array as it likes.
14797 *
14798 * - **ARGF** may be thought of as the <b>argument files</b> object.
14799 *
14800 * It can access file streams and/or the <tt>$stdin</tt> stream,
14801 * based on what it finds in +ARGV+.
14802 * This provides a convenient way for the command line
14803 * to specify streams for a Ruby program to read.
14804 *
14805 * == Reading
14806 *
14807 * \ARGF may read from _source_ streams,
14808 * which at any particular time are determined by the content of +ARGV+.
14809 *
14810 * === Simplest Case
14811 *
14812 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14813 * the source is <tt>$stdin</tt>:
14814 *
14815 * - \File +t.rb+:
14816 *
14817 * p ['ARGV', ARGV]
14818 * p ['ARGF.read', ARGF.read]
14819 *
14820 * - Commands and outputs
14821 * (see below for the content of files +foo.txt+ and +bar.txt+):
14822 *
14823 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14824 * ["ARGV", []]
14825 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14826 *
14827 * $ cat foo.txt bar.txt | ruby t.rb
14828 * ["ARGV", []]
14829 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14830 *
14831 * === About the Examples
14832 *
14833 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14834 *
14835 * $ cat foo.txt
14836 * Foo 0
14837 * Foo 1
14838 * $ cat bar.txt
14839 * Bar 0
14840 * Bar 1
14841 * Bar 2
14842 * Bar 3
14843 *
14844 * === Sources in +ARGV+
14845 *
14846 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14847 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14848 * the sources are found in +ARGV+.
14849 *
14850 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14851 * and is one of:
14852 *
14853 * - The string path to a file that may be opened as a stream.
14854 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14855 *
14856 * Each element that is _not_ one of these
14857 * should be removed from +ARGV+ before \ARGF accesses that source.
14858 *
14859 * In the following example:
14860 *
14861 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14862 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14863 *
14864 * Example:
14865 *
14866 * - \File +t.rb+:
14867 *
14868 * # Print arguments (and options, if any) found on command line.
14869 * p ['ARGV', ARGV]
14870 *
14871 * - Command and output:
14872 *
14873 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14874 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14875 *
14876 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14877 *
14878 * - \File +t.rb+:
14879 *
14880 * p "ARGV: #{ARGV}"
14881 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
14882 *
14883 * - Command and output:
14884 *
14885 * $ ruby t.rb foo.txt bar.txt
14886 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14887 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14888 *
14889 * Because the value at +ARGV+ is an ordinary array,
14890 * you can manipulate it to control which sources \ARGF considers:
14891 *
14892 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14893 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14894 *
14895 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14896 * when all sources have been accessed, the array is empty:
14897 *
14898 * - \File +t.rb+:
14899 *
14900 * until ARGV.empty? && ARGF.eof?
14901 * p "ARGV: #{ARGV}"
14902 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14903 * end
14904 *
14905 * - Command and output:
14906 *
14907 * $ ruby t.rb foo.txt bar.txt
14908 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14909 * "Line: Foo 0\n"
14910 * "ARGV: [\"bar.txt\"]"
14911 * "Line: Foo 1\n"
14912 * "ARGV: [\"bar.txt\"]"
14913 * "Line: Bar 0\n"
14914 * "ARGV: []"
14915 * "Line: Bar 1\n"
14916 * "ARGV: []"
14917 * "Line: Bar 2\n"
14918 * "ARGV: []"
14919 * "Line: Bar 3\n"
14920 *
14921 * ==== Filepaths in +ARGV+
14922 *
14923 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14924 *
14925 * This program prints what it reads from files at the paths specified
14926 * on the command line:
14927 *
14928 * - \File +t.rb+:
14929 *
14930 * p ['ARGV', ARGV]
14931 * # Read and print all content from the specified sources.
14932 * p ['ARGF.read', ARGF.read]
14933 *
14934 * - Command and output:
14935 *
14936 * $ ruby t.rb foo.txt bar.txt
14937 * ["ARGV", [foo.txt, bar.txt]
14938 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14939 *
14940 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14941 *
14942 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14943 *
14944 * - \File +t.rb+:
14945 *
14946 * p ['ARGV', ARGV]
14947 * p ['ARGF.read', ARGF.read]
14948 *
14949 * - Command and output:
14950 *
14951 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14952 * ["ARGV", ["-"]]
14953 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14954 *
14955 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
14956 * (exception:
14957 * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
14958 *
14959 * - Command and output:
14960 *
14961 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
14962 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14963 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14964 *
14965 * ==== Mixtures and Repetitions in +ARGV+
14966 *
14967 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
14968 * and character <tt>'-'</tt>, including repetitions.
14969 *
14970 * ==== Modifications to +ARGV+
14971 *
14972 * The running Ruby program may make any modifications to the +ARGV+ array;
14973 * the current value of +ARGV+ affects \ARGF reading.
14974 *
14975 * ==== Empty +ARGV+
14976 *
14977 * For an empty +ARGV+, an \ARGF read method either returns +nil+
14978 * or raises an exception, depending on the specific method.
14979 *
14980 * === More Read Methods
14981 *
14982 * As seen above, method ARGF#read reads the content of all sources
14983 * into a single string.
14984 * Other \ARGF methods provide other ways to access that content;
14985 * these include:
14986 *
14987 * - Byte access: #each_byte, #getbyte, #readbyte.
14988 * - Character access: #each_char, #getc, #readchar.
14989 * - Codepoint access: #each_codepoint.
14990 * - Line access: #each_line, #gets, #readline, #readlines.
14991 * - Source access: #read, #read_nonblock, #readpartial.
14992 *
14993 * === About \Enumerable
14994 *
14995 * \ARGF includes module Enumerable.
14996 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
14997 *
14998 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
14999 * _not_ from +ARGV+;
15000 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15001 * not an array of the strings from +ARGV+:
15002 *
15003 * - \File +t.rb+:
15004 *
15005 * p ['ARGV', ARGV]
15006 * p ['ARGF.entries', ARGF.entries]
15007 *
15008 * - Command and output:
15009 *
15010 * $ ruby t.rb foo.txt bar.txt
15011 * ["ARGV", ["foo.txt", "bar.txt"]]
15012 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15013 *
15014 * == Writing
15015 *
15016 * If <i>inplace mode</i> is in effect,
15017 * \ARGF may write to target streams,
15018 * which at any particular time are determined by the content of ARGV.
15019 *
15020 * Methods about inplace mode:
15021 *
15022 * - #inplace_mode
15023 * - #inplace_mode=
15024 * - #to_write_io
15025 *
15026 * Methods for writing:
15027 *
15028 * - #print
15029 * - #printf
15030 * - #putc
15031 * - #puts
15032 * - #write
15033 *
15034 */
15035
15036/*
15037 * An instance of class \IO (commonly called a _stream_)
15038 * represents an input/output stream in the underlying operating system.
15039 * Class \IO is the basis for input and output in Ruby.
15040 *
15041 * Class File is the only class in the Ruby core that is a subclass of \IO.
15042 * Some classes in the Ruby standard library are also subclasses of \IO;
15043 * these include TCPSocket and UDPSocket.
15044 *
15045 * The global constant ARGF (also accessible as <tt>$<</tt>)
15046 * provides an IO-like stream that allows access to all file paths
15047 * found in ARGV (or found in STDIN if ARGV is empty).
15048 * ARGF is not itself a subclass of \IO.
15049 *
15050 * Class StringIO provides an IO-like stream that handles a String.
15051 * StringIO is not itself a subclass of \IO.
15052 *
15053 * Important objects based on \IO include:
15054 *
15055 * - $stdin.
15056 * - $stdout.
15057 * - $stderr.
15058 * - Instances of class File.
15059 *
15060 * An instance of \IO may be created using:
15061 *
15062 * - IO.new: returns a new \IO object for the given integer file descriptor.
15063 * - IO.open: passes a new \IO object to the given block.
15064 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15065 * of a newly-launched subprocess.
15066 * - Kernel#open: Returns a new \IO object connected to a given source:
15067 * stream, file, or subprocess.
15068 *
15069 * Like a File stream, an \IO stream has:
15070 *
15071 * - A read/write mode, which may be read-only, write-only, or read/write;
15072 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
15073 * - A data mode, which may be text-only or binary;
15074 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15075 * - Internal and external encodings;
15076 * see {Encodings}[rdoc-ref:File@Encodings].
15077 *
15078 * And like other \IO streams, it has:
15079 *
15080 * - A position, which determines where in the stream the next
15081 * read or write is to occur;
15082 * see {Position}[rdoc-ref:IO@Position].
15083 * - A line number, which is a special, line-oriented, "position"
15084 * (different from the position mentioned above);
15085 * see {Line Number}[rdoc-ref:IO@Line+Number].
15086 *
15087 * == Extension <tt>io/console</tt>
15088 *
15089 * Extension <tt>io/console</tt> provides numerous methods
15090 * for interacting with the console;
15091 * requiring it adds numerous methods to class \IO.
15092 *
15093 * == Example Files
15094 *
15095 * Many examples here use these variables:
15096 *
15097 * :include: doc/examples/files.rdoc
15098 *
15099 * == Open Options
15100 *
15101 * A number of \IO methods accept optional keyword arguments
15102 * that determine how a new stream is to be opened:
15103 *
15104 * - +:mode+: Stream mode.
15105 * - +:flags+: Integer file open flags;
15106 * If +mode+ is also given, the two are bitwise-ORed.
15107 * - +:external_encoding+: External encoding for the stream.
15108 * - +:internal_encoding+: Internal encoding for the stream.
15109 * <tt>'-'</tt> is a synonym for the default internal encoding.
15110 * If the value is +nil+ no conversion occurs.
15111 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15112 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15113 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15114 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15115 * when the stream closes; otherwise it remains open.
15116 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15117 * #path method.
15118 *
15119 * Also available are the options offered in String#encode,
15120 * which may control conversion between external and internal encoding.
15121 *
15122 * == Basic \IO
15123 *
15124 * You can perform basic stream \IO with these methods,
15125 * which typically operate on multi-byte strings:
15126 *
15127 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15128 * - IO#write: Writes zero or more strings to the stream;
15129 * each given object that is not already a string is converted via +to_s+.
15130 *
15131 * === Position
15132 *
15133 * An \IO stream has a nonnegative integer _position_,
15134 * which is the byte offset at which the next read or write is to occur.
15135 * A new stream has position zero (and line number zero);
15136 * method +rewind+ resets the position (and line number) to zero.
15137 *
15138 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15139 * Encoding::Converter instances used for that \IO.
15140 *
15141 * The relevant methods:
15142 *
15143 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15144 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15145 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15146 * relative to a given position +whence+
15147 * (indicating the beginning, end, or current position).
15148 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15149 *
15150 * === Open and Closed Streams
15151 *
15152 * A new \IO stream may be open for reading, open for writing, or both.
15153 *
15154 * A stream is automatically closed when claimed by the garbage collector.
15155 *
15156 * Attempted reading or writing on a closed stream raises an exception.
15157 *
15158 * The relevant methods:
15159 *
15160 * - IO#close: Closes the stream for both reading and writing.
15161 * - IO#close_read: Closes the stream for reading.
15162 * - IO#close_write: Closes the stream for writing.
15163 * - IO#closed?: Returns whether the stream is closed.
15164 *
15165 * === End-of-Stream
15166 *
15167 * You can query whether a stream is positioned at its end:
15168 *
15169 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15170 *
15171 * You can reposition to end-of-stream by using method IO#seek:
15172 *
15173 * f = File.new('t.txt')
15174 * f.eof? # => false
15175 * f.seek(0, :END)
15176 * f.eof? # => true
15177 * f.close
15178 *
15179 * Or by reading all stream content (which is slower than using IO#seek):
15180 *
15181 * f.rewind
15182 * f.eof? # => false
15183 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15184 * f.eof? # => true
15185 *
15186 * == Line \IO
15187 *
15188 * Class \IO supports line-oriented
15189 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15190 *
15191 * === Line Input
15192 *
15193 * Class \IO supports line-oriented input for
15194 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15195 *
15196 * ==== \File Line Input
15197 *
15198 * You can read lines from a file using these methods:
15199 *
15200 * - IO.foreach: Reads each line and passes it to the given block.
15201 * - IO.readlines: Reads and returns all lines in an array.
15202 *
15203 * For each of these methods:
15204 *
15205 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15206 * - Line parsing depends on the effective <i>line separator</i>;
15207 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15208 * - The length of each returned line depends on the effective <i>line limit</i>;
15209 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15210 *
15211 * ==== Stream Line Input
15212 *
15213 * You can read lines from an \IO stream using these methods:
15214 *
15215 * - IO#each_line: Reads each remaining line, passing it to the given block.
15216 * - IO#gets: Returns the next line.
15217 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15218 * - IO#readlines: Returns all remaining lines in an array.
15219 *
15220 * For each of these methods:
15221 *
15222 * - Reading may begin mid-line,
15223 * depending on the stream's _position_;
15224 * see {Position}[rdoc-ref:IO@Position].
15225 * - Line parsing depends on the effective <i>line separator</i>;
15226 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15227 * - The length of each returned line depends on the effective <i>line limit</i>;
15228 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15229 *
15230 * ===== Line Separator
15231 *
15232 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15233 * the string that determines what is considered a line;
15234 * it is sometimes called the <i>input record separator</i>.
15235 *
15236 * The default line separator is taken from global variable <tt>$/</tt>,
15237 * whose initial value is <tt>"\n"</tt>.
15238 *
15239 * Generally, the line to be read next is all data
15240 * from the current {position}[rdoc-ref:IO@Position]
15241 * to the next line separator
15242 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15243 *
15244 * f = File.new('t.txt')
15245 * # Method gets with no sep argument returns the next line, according to $/.
15246 * f.gets # => "First line\n"
15247 * f.gets # => "Second line\n"
15248 * f.gets # => "\n"
15249 * f.gets # => "Fourth line\n"
15250 * f.gets # => "Fifth line\n"
15251 * f.close
15252 *
15253 * You can use a different line separator by passing argument +sep+:
15254 *
15255 * f = File.new('t.txt')
15256 * f.gets('l') # => "First l"
15257 * f.gets('li') # => "ine\nSecond li"
15258 * f.gets('lin') # => "ne\n\nFourth lin"
15259 * f.gets # => "e\n"
15260 * f.close
15261 *
15262 * Or by setting global variable <tt>$/</tt>:
15263 *
15264 * f = File.new('t.txt')
15265 * $/ = 'l'
15266 * f.gets # => "First l"
15267 * f.gets # => "ine\nSecond l"
15268 * f.gets # => "ine\n\nFourth l"
15269 * f.close
15270 *
15271 * ===== Special Line Separator Values
15272 *
15273 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15274 * accepts two special values for parameter +sep+:
15275 *
15276 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15277 *
15278 * f = File.new('t.txt')
15279 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15280 * f.close
15281 *
15282 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15283 * (paragraphs being separated by two consecutive line separators):
15284 *
15285 * f = File.new('t.txt')
15286 * f.gets('') # => "First line\nSecond line\n\n"
15287 * f.gets('') # => "Fourth line\nFifth line\n"
15288 * f.close
15289 *
15290 * ===== Line Limit
15291 *
15292 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15293 * uses an integer <i>line limit</i>,
15294 * which restricts the number of bytes that may be returned.
15295 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15296 * than the limit).
15297 *
15298 * The default limit value is <tt>-1</tt>;
15299 * any negative limit value means that there is no limit.
15300 *
15301 * If there is no limit, the line is determined only by +sep+.
15302 *
15303 * # Text with 1-byte characters.
15304 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15305 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15306 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15307 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15308 * # No more than one line.
15309 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15310 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15311 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15312 *
15313 * # Text with 2-byte characters, which will not be split.
15314 * File.open('t.rus') {|f| f.gets(1).size } # => 1
15315 * File.open('t.rus') {|f| f.gets(2).size } # => 1
15316 * File.open('t.rus') {|f| f.gets(3).size } # => 2
15317 * File.open('t.rus') {|f| f.gets(4).size } # => 2
15318 *
15319 * ===== Line Separator and Line Limit
15320 *
15321 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15322 *
15323 * - Returns the next line as determined by line separator +sep+.
15324 * - But returns no more bytes than are allowed by the limit +limit+.
15325 *
15326 * Example:
15327 *
15328 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15329 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15330 *
15331 * ===== Line Number
15332 *
15333 * A readable \IO stream has a non-negative integer <i>line number</i>:
15334 *
15335 * - IO#lineno: Returns the line number.
15336 * - IO#lineno=: Resets and returns the line number.
15337 *
15338 * Unless modified by a call to method IO#lineno=,
15339 * the line number is the number of lines read
15340 * by certain line-oriented methods,
15341 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15342 *
15343 * - IO.foreach: Increments the line number on each call to the block.
15344 * - IO#each_line: Increments the line number on each call to the block.
15345 * - IO#gets: Increments the line number.
15346 * - IO#readline: Increments the line number.
15347 * - IO#readlines: Increments the line number for each line read.
15348 *
15349 * A new stream is initially has line number zero (and position zero);
15350 * method +rewind+ resets the line number (and position) to zero:
15351 *
15352 * f = File.new('t.txt')
15353 * f.lineno # => 0
15354 * f.gets # => "First line\n"
15355 * f.lineno # => 1
15356 * f.rewind
15357 * f.lineno # => 0
15358 * f.close
15359 *
15360 * Reading lines from a stream usually changes its line number:
15361 *
15362 * f = File.new('t.txt', 'r')
15363 * f.lineno # => 0
15364 * f.readline # => "This is line one.\n"
15365 * f.lineno # => 1
15366 * f.readline # => "This is the second line.\n"
15367 * f.lineno # => 2
15368 * f.readline # => "Here's the third line.\n"
15369 * f.lineno # => 3
15370 * f.eof? # => true
15371 * f.close
15372 *
15373 * Iterating over lines in a stream usually changes its line number:
15374 *
15375 * File.open('t.txt') do |f|
15376 * f.each_line do |line|
15377 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15378 * end
15379 * end
15380 *
15381 * Output:
15382 *
15383 * "position=11 eof?=false lineno=1"
15384 * "position=23 eof?=false lineno=2"
15385 * "position=24 eof?=false lineno=3"
15386 * "position=36 eof?=false lineno=4"
15387 * "position=47 eof?=true lineno=5"
15388 *
15389 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15390 * the line number does not affect where the next read or write will occur:
15391 *
15392 * f = File.new('t.txt')
15393 * f.lineno = 1000
15394 * f.lineno # => 1000
15395 * f.gets # => "First line\n"
15396 * f.lineno # => 1001
15397 * f.close
15398 *
15399 * Associated with the line number is the global variable <tt>$.</tt>:
15400 *
15401 * - When a stream is opened, <tt>$.</tt> is not set;
15402 * its value is left over from previous activity in the process:
15403 *
15404 * $. = 41
15405 * f = File.new('t.txt')
15406 * $. = 41
15407 * # => 41
15408 * f.close
15409 *
15410 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15411 *
15412 * f0 = File.new('t.txt')
15413 * f1 = File.new('t.dat')
15414 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15415 * $. # => 5
15416 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15417 * $. # => 1
15418 * f0.close
15419 * f1.close
15420 *
15421 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15422 *
15423 * f = File.new('t.txt')
15424 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15425 * $. # => 5
15426 * f.rewind
15427 * f.seek(0, :SET)
15428 * $. # => 5
15429 * f.close
15430 *
15431 * === Line Output
15432 *
15433 * You can write to an \IO stream line-by-line using this method:
15434 *
15435 * - IO#puts: Writes objects to the stream.
15436 *
15437 * == Character \IO
15438 *
15439 * You can process an \IO stream character-by-character using these methods:
15440 *
15441 * - IO#getc: Reads and returns the next character from the stream.
15442 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15443 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15444 * - IO#putc: Writes a character to the stream.
15445 * - IO#each_char: Reads each remaining character in the stream,
15446 * passing the character to the given block.
15447 *
15448 * == Byte \IO
15449 *
15450 * You can process an \IO stream byte-by-byte using these methods:
15451 *
15452 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15453 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15454 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15455 * - IO#each_byte: Reads each remaining byte in the stream,
15456 * passing the byte to the given block.
15457 *
15458 * == Codepoint \IO
15459 *
15460 * You can process an \IO stream codepoint-by-codepoint:
15461 *
15462 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15463 *
15464 * == What's Here
15465 *
15466 * First, what's elsewhere. Class \IO:
15467 *
15468 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15469 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15470 * which provides dozens of additional methods.
15471 *
15472 * Here, class \IO provides methods that are useful for:
15473 *
15474 * - {Creating}[rdoc-ref:IO@Creating]
15475 * - {Reading}[rdoc-ref:IO@Reading]
15476 * - {Writing}[rdoc-ref:IO@Writing]
15477 * - {Positioning}[rdoc-ref:IO@Positioning]
15478 * - {Iterating}[rdoc-ref:IO@Iterating]
15479 * - {Settings}[rdoc-ref:IO@Settings]
15480 * - {Querying}[rdoc-ref:IO@Querying]
15481 * - {Buffering}[rdoc-ref:IO@Buffering]
15482 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15483 * - {Other}[rdoc-ref:IO@Other]
15484 *
15485 * === Creating
15486 *
15487 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15488 * integer file descriptor.
15489 * - ::open: Creates a new \IO object.
15490 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15491 * - ::popen: Creates an \IO object to interact with a subprocess.
15492 * - ::select: Selects which given \IO instances are ready for reading,
15493 * writing, or have pending exceptions.
15494 *
15495 * === Reading
15496 *
15497 * - ::binread: Returns a binary string with all or a subset of bytes
15498 * from the given file.
15499 * - ::read: Returns a string with all or a subset of bytes from the given file.
15500 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15501 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15502 * - #getc: Returns the next character read from +self+ as a string.
15503 * - #gets: Returns the line read from +self+.
15504 * - #pread: Returns all or the next _n_ bytes read from +self+,
15505 * not updating the receiver's offset.
15506 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15507 * for a given _n_.
15508 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15509 * in non-block mode.
15510 * - #readbyte: Returns the next byte read from +self+;
15511 * same as #getbyte, but raises an exception on end-of-stream.
15512 * - #readchar: Returns the next character read from +self+;
15513 * same as #getc, but raises an exception on end-of-stream.
15514 * - #readline: Returns the next line read from +self+;
15515 * same as #getline, but raises an exception of end-of-stream.
15516 * - #readlines: Returns an array of all lines read read from +self+.
15517 * - #readpartial: Returns up to the given number of bytes from +self+.
15518 *
15519 * === Writing
15520 *
15521 * - ::binwrite: Writes the given string to the file at the given filepath,
15522 * in binary mode.
15523 * - ::write: Writes the given string to +self+.
15524 * - #<<: Appends the given string to +self+.
15525 * - #print: Prints last read line or given objects to +self+.
15526 * - #printf: Writes to +self+ based on the given format string and objects.
15527 * - #putc: Writes a character to +self+.
15528 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15529 * - #pwrite: Writes the given string at the given offset,
15530 * not updating the receiver's offset.
15531 * - #write: Writes one or more given strings to +self+.
15532 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15533 *
15534 * === Positioning
15535 *
15536 * - #lineno: Returns the current line number in +self+.
15537 * - #lineno=: Sets the line number is +self+.
15538 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15539 * - #pos=: Sets the byte offset in +self+.
15540 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15541 * - #rewind: Positions +self+ to the beginning of input.
15542 * - #seek: Sets the offset for +self+ relative to given position.
15543 *
15544 * === Iterating
15545 *
15546 * - ::foreach: Yields each line of given file to the block.
15547 * - #each (aliased as #each_line): Calls the given block
15548 * with each successive line in +self+.
15549 * - #each_byte: Calls the given block with each successive byte in +self+
15550 * as an integer.
15551 * - #each_char: Calls the given block with each successive character in +self+
15552 * as a string.
15553 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15554 * as an integer.
15555 *
15556 * === Settings
15557 *
15558 * - #autoclose=: Sets whether +self+ auto-closes.
15559 * - #binmode: Sets +self+ to binary mode.
15560 * - #close: Closes +self+.
15561 * - #close_on_exec=: Sets the close-on-exec flag.
15562 * - #close_read: Closes +self+ for reading.
15563 * - #close_write: Closes +self+ for writing.
15564 * - #set_encoding: Sets the encoding for +self+.
15565 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15566 * Unicode byte-order-mark.
15567 * - #sync=: Sets the sync-mode to the given value.
15568 *
15569 * === Querying
15570 *
15571 * - #autoclose?: Returns whether +self+ auto-closes.
15572 * - #binmode?: Returns whether +self+ is in binary mode.
15573 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15574 * - #closed?: Returns whether +self+ is closed.
15575 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15576 * - #external_encoding: Returns the external encoding object for +self+.
15577 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15578 * - #internal_encoding: Returns the internal encoding object for +self+.
15579 * - #pid: Returns the process ID of a child process associated with +self+,
15580 * if +self+ was created by ::popen.
15581 * - #stat: Returns the File::Stat object containing status information for +self+.
15582 * - #sync: Returns whether +self+ is in sync-mode.
15583 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15584 *
15585 * === Buffering
15586 *
15587 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15588 * - #flush: Flushes any buffered data within +self+ to the underlying
15589 * operating system.
15590 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15591 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15592 * - #ungetc: Prepends buffer for +self+ with given string.
15593 *
15594 * === Low-Level Access
15595 *
15596 * - ::sysopen: Opens the file given by its path,
15597 * returning the integer file descriptor.
15598 * - #advise: Announces the intention to access data from +self+ in a specific way.
15599 * - #fcntl: Passes a low-level command to the file specified
15600 * by the given file descriptor.
15601 * - #ioctl: Passes a low-level command to the device specified
15602 * by the given file descriptor.
15603 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15604 * - #sysseek: Sets the offset for +self+.
15605 * - #syswrite: Writes the given string to +self+ using a low-level write.
15606 *
15607 * === Other
15608 *
15609 * - ::copy_stream: Copies data from a source to a destination,
15610 * each of which is a filepath or an \IO-like object.
15611 * - ::try_convert: Returns a new \IO object resulting from converting
15612 * the given object.
15613 * - #inspect: Returns the string representation of +self+.
15614 *
15615 */
15616
15617void
15618Init_IO(void)
15619{
15620 VALUE rb_cARGF;
15621#ifdef __CYGWIN__
15622#include <sys/cygwin.h>
15623 static struct __cygwin_perfile pf[] =
15624 {
15625 {"", O_RDONLY | O_BINARY},
15626 {"", O_WRONLY | O_BINARY},
15627 {"", O_RDWR | O_BINARY},
15628 {"", O_APPEND | O_BINARY},
15629 {NULL, 0}
15630 };
15631 cygwin_internal(CW_PERFILE, pf);
15632#endif
15633
15636
15637 id_write = rb_intern_const("write");
15638 id_read = rb_intern_const("read");
15639 id_getc = rb_intern_const("getc");
15640 id_flush = rb_intern_const("flush");
15641 id_readpartial = rb_intern_const("readpartial");
15642 id_set_encoding = rb_intern_const("set_encoding");
15643 id_fileno = rb_intern_const("fileno");
15644
15645 rb_define_global_function("syscall", rb_f_syscall, -1);
15646
15647 rb_define_global_function("open", rb_f_open, -1);
15648 rb_define_global_function("printf", rb_f_printf, -1);
15649 rb_define_global_function("print", rb_f_print, -1);
15650 rb_define_global_function("putc", rb_f_putc, 1);
15651 rb_define_global_function("puts", rb_f_puts, -1);
15652 rb_define_global_function("gets", rb_f_gets, -1);
15653 rb_define_global_function("readline", rb_f_readline, -1);
15654 rb_define_global_function("select", rb_f_select, -1);
15655
15656 rb_define_global_function("readlines", rb_f_readlines, -1);
15657
15658 rb_define_global_function("`", rb_f_backquote, 1);
15659
15660 rb_define_global_function("p", rb_f_p, -1);
15661 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15662
15663 rb_cIO = rb_define_class("IO", rb_cObject);
15665
15666 /* Can be raised by IO operations when IO#timeout= is set. */
15668
15669 /* Readable event mask for IO#wait. */
15670 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15671 /* Writable event mask for IO#wait. */
15672 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15673 /* Priority event mask for IO#wait. */
15674 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15675
15676 /* exception to wait for reading. see IO.select. */
15678 /* exception to wait for writing. see IO.select. */
15680 /* exception to wait for reading by EAGAIN. see IO.select. */
15681 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15682 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15683 /* exception to wait for writing by EAGAIN. see IO.select. */
15684 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15685 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15686#if EAGAIN == EWOULDBLOCK
15687 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15688 /* same as IO::EAGAINWaitReadable */
15689 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15690 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15691 /* same as IO::EAGAINWaitWritable */
15692 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15693#else
15694 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15695 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15696 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15697 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15698 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15699 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15700#endif
15701 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15702 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15703 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15704 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15705 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15706 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15707
15708#if 0
15709 /* This is necessary only for forcing rdoc handle File::open */
15710 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15711#endif
15712
15713 rb_define_alloc_func(rb_cIO, io_alloc);
15714 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15715 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15716 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15717 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15718 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15719 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15720 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15721 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15722 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15723 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15724 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15725 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15726 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15727 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15728 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15729
15730 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15731
15733 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15734
15735 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15736 rb_vm_register_global_object(rb_default_rs);
15737 rb_rs = rb_default_rs;
15739 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15740 rb_gvar_ractor_local("$/"); // not local but ractor safe
15741 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15742 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15743 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15744
15745 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15746 rb_gvar_ractor_local("$_");
15747
15748 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15749 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15750
15751 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15752 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15753 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15754 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15755
15756 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15757 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15758 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15759 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15760 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15761
15762 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15763 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15764
15765 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15766 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15767
15768 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15769 rb_define_alias(rb_cIO, "to_i", "fileno");
15770 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15771
15772 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15773 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15774
15775 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15776 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15777 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15778 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15779
15780 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15781 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15782
15783 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15784
15785 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15786 rb_define_method(rb_cIO, "read", io_read, -1);
15787 rb_define_method(rb_cIO, "write", io_write_m, -1);
15788 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15789 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15790 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15791 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15792 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15793 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15794 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15796 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15797 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15798 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15799 /* Set I/O position from the beginning */
15800 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15801 /* Set I/O position from the current position */
15802 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15803 /* Set I/O position from the end */
15804 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15805#ifdef SEEK_DATA
15806 /* Set I/O position to the next location containing data */
15807 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15808#endif
15809#ifdef SEEK_HOLE
15810 /* Set I/O position to the next hole */
15811 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15812#endif
15813 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15814 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15815 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15816 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15817 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15818
15819 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15820 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15821
15822 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15823 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15824 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15825 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15826
15827 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15828 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15829 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15830 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15831 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15832 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15833
15834 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15835 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15836 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15837
15838 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15839 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15840
15841 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15842
15843 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15844 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15845 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15846 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15847
15848 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15849 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15850
15851 rb_define_method(rb_cIO, "wait", io_wait, -1);
15852
15853 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15854 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15855 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15856
15857 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15858 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15859 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15860 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15861
15862 rb_gvar_ractor_local("$stdin");
15863 rb_gvar_ractor_local("$stdout");
15864 rb_gvar_ractor_local("$>");
15865 rb_gvar_ractor_local("$stderr");
15866
15868 rb_stdin = rb_io_prep_stdin();
15870 rb_stdout = rb_io_prep_stdout();
15872 rb_stderr = rb_io_prep_stderr();
15873
15874 orig_stdout = rb_stdout;
15875 orig_stderr = rb_stderr;
15876
15877 /* Holds the original stdin */
15879 /* Holds the original stdout */
15881 /* Holds the original stderr */
15883
15884#if 0
15885 /* Hack to get rdoc to regard ARGF as a class: */
15886 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15887#endif
15888
15889 rb_cARGF = rb_class_new(rb_cObject);
15890 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15891 rb_define_alloc_func(rb_cARGF, argf_alloc);
15892
15894
15895 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15896 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15897 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15898 rb_define_alias(rb_cARGF, "inspect", "to_s");
15899 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15900
15901 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15902 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15903 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15904 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15905 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15906 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15907 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15908 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15909 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15910
15911 rb_define_method(rb_cARGF, "read", argf_read, -1);
15912 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15913 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15914 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15915 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15916 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15917 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15918 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15919 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15920 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15921 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15922 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15923 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15924 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15925 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15926 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15927 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15928 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15929 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15930 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15931
15932 rb_define_method(rb_cARGF, "write", argf_write, -1);
15933 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15934 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15935 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15936 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15937
15938 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15939 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15940 rb_define_method(rb_cARGF, "file", argf_file, 0);
15941 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15942 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15943 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15944
15945 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15946 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15947
15948 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15949 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15950
15951 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15952 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15953 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15954
15955 argf = rb_class_new_instance(0, 0, rb_cARGF);
15956
15958 /*
15959 * ARGF is a stream designed for use in scripts that process files given
15960 * as command-line arguments or passed in via STDIN.
15961 *
15962 * See ARGF (the class) for more details.
15963 */
15965
15966 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15967 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15968 ARGF.filename = rb_str_new2("-");
15969
15970 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15971 rb_gvar_ractor_local("$-i");
15972
15973 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15974
15975#if defined (_WIN32) || defined(__CYGWIN__)
15976 atexit(pipe_atexit);
15977#endif
15978
15979 Init_File();
15980
15981 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
15982
15983 sym_mode = ID2SYM(rb_intern_const("mode"));
15984 sym_perm = ID2SYM(rb_intern_const("perm"));
15985 sym_flags = ID2SYM(rb_intern_const("flags"));
15986 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
15987 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
15988 sym_encoding = ID2SYM(rb_id_encoding());
15989 sym_open_args = ID2SYM(rb_intern_const("open_args"));
15990 sym_textmode = ID2SYM(rb_intern_const("textmode"));
15991 sym_binmode = ID2SYM(rb_intern_const("binmode"));
15992 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
15993 sym_normal = ID2SYM(rb_intern_const("normal"));
15994 sym_sequential = ID2SYM(rb_intern_const("sequential"));
15995 sym_random = ID2SYM(rb_intern_const("random"));
15996 sym_willneed = ID2SYM(rb_intern_const("willneed"));
15997 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
15998 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
15999 sym_SET = ID2SYM(rb_intern_const("SET"));
16000 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16001 sym_END = ID2SYM(rb_intern_const("END"));
16002#ifdef SEEK_DATA
16003 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16004#endif
16005#ifdef SEEK_HOLE
16006 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16007#endif
16008 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16009 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16010}
16011
16012#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:1779
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1572
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:952
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1603
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1708
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2931
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:3234
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:3221
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1037
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:3010
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1674
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:400
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1682
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:134
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:111
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:520
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:109
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition ctype.h:103
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:518
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition transcode.h:538
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:519
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1676
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
void rb_notimplement(void)
Definition error.c:3840
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:476
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:508
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1441
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:683
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3909
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
Definition io.c:14691
VALUE rb_eIOError
IOError exception.
Definition io.c:189
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1428
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3999
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3915
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:475
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1431
VALUE rb_eEOFError
EOFError exception.
Definition io.c:188
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14685
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2280
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1429
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1451
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:60
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3294
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:676
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2190
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2231
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:2219
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
VALUE rb_stdin
STDIN constant.
Definition io.c:201
VALUE rb_stderr
STDERR constant.
Definition io.c:201
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:265
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:583
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:687
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:191
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:192
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1343
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:3275
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:3288
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:1340
int rb_enc_str_coderange(VALUE str)
Scans the passed string to collect its code range.
Definition string.c:945
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3772
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:829
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
Definition transcode.c:2660
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
Definition transcode.c:2123
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
Definition transcode.c:1485
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
Definition transcode.h:69
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
Definition transcode.h:41
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1780
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1824
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
Definition transcode.c:1959
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
Definition transcode.c:2711
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
Definition transcode.c:2022
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
Definition transcode.c:2974
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4340
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4346
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1741
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1791
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1117
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
Definition vm_eval.c:1084
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h: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:8585
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4302
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:8730
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:9159
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:5167
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5073
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:9340
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:9139
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
Definition io.c:298
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6373
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6327
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5231
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7375
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10418
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:7258
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:367
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7265
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5747
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:207
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:2042
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:2036
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:2985
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:3795
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1497
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1680
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1531
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:999
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1516
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1994
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3563
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1145
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4265
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3385
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:3737
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2948
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3248
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3367
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:2742
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1716
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1513
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c:1848
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1469
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
Definition io.c:1604
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
Definition thread.c:1452
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:3162
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1598
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1475
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2947
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:441
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:2013
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:500
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3367
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:4026
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
Definition variable.c:846
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:162
enum rb_io_mode rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
Definition io.c:6459
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:811
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:857
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:781
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1069
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
Definition io.c:6592
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
Definition io.h: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:7075
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
Definition io.c:6741
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2899
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h: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:9386
#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:6866
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:788
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
Definition io.h: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:5669
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
Definition io.c:817
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:5855
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:886
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:2016
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:996
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
Definition io.h: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:3423
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:9252
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:834
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1048
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
Definition io.c:1666
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:796
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1515
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7362
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1454
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:1058
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:1118
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:1106
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:1094
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:2046
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition sprintf.c:209
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
Definition vm_eval.c:1406
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1372
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition off_t.h:55
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:409
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:450
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:80
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:502
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14651
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9038
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:90
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
Definition scan_args.h:59
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition scan_args.h:78
Scheduler APIs.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
Definition scheduler.c:464
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
Definition scheduler.c:972
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
Definition scheduler.c:507
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
Definition scheduler.c:724
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
Definition scheduler.c:948
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:710
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
Definition scheduler.h:71
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:754
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
Definition scheduler.c:984
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread instead of...
Definition scheduler.c:469
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
Definition scheduler.c:960
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
Definition scheduler.c:730
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
Definition thread.c:4515
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
@ RUBY_Qfalse
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
C99 shim for <stdbool.h>
Ruby's File and IO.
Definition rfile.h:35
Definition io.c:236
Definition win32.h:230
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:202
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
Decomposed encoding flags (e.g.
Definition io.h:134
int ecflags
Flags.
Definition io.h:144
VALUE ecopts
Flags as Ruby hash.
Definition io.h:152
rb_encoding * enc2
External encoding.
Definition io.h:138
rb_encoding * enc
Internal encoding.
Definition io.h:136
IO buffers.
Definition io.h:109
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:112
int off
Offset inside of ptr.
Definition io.h:115
int len
Length of the buffer.
Definition io.h:118
int capa
Designed capacity of the buffer.
Definition io.h:121
Ruby's IO, metadata and buffers.
Definition io.h:295
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:330
enum rb_io_mode mode
mode flags: FMODE_XXXs
Definition io.h:310
void(* finalize)(struct rb_io *, int)
finalize proc
Definition io.h:326
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:352
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:363
struct rb_io_encoding encs
Decomposed encoding flags.
Definition io.h:348
VALUE self
The IO's Ruby level counterpart.
Definition io.h:298
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:400
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:406
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:302
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
Definition io.h:390
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:345
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:376
int fd
file descriptor.
Definition io.h:306
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:337
int lineno
number of lines read
Definition io.h:318
struct ccan_list_head blocking_operations
Threads that are performing a blocking operation without the GVL using this IO.
Definition io.h:131
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:372
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:359
rb_pid_t pid
child's pid (for pipes)
Definition io.h:314
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
Definition io.h:383
VALUE pathv
pathname for file
Definition io.h:322
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
Definition value_type.h:307
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:433
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376