Ruby 3.4.8p72 (2025-12-17 revision 995b59f66677d44767ce9faac6957e5543617ff9)
io.c
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17#include "ruby/io/buffer.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <stddef.h>
22
23/* non-Linux poll may not work on all FDs */
24#if defined(HAVE_POLL)
25# if defined(__linux__)
26# define USE_POLL 1
27# endif
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29# define USE_POLL 1
30# endif
31#endif
32
33#ifndef USE_POLL
34# define USE_POLL 0
35#endif
36
37#undef free
38#define free(x) xfree(x)
39
40#if defined(DOSISH) || defined(__CYGWIN__)
41#include <io.h>
42#endif
43
44#include <sys/types.h>
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
49#endif
50
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
53#endif
54
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
56# define USE_SETVBUF
57#endif
58
59#ifdef __QNXNTO__
60#include <unix.h>
61#endif
62
63#include <sys/types.h>
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
65#include <sys/ioctl.h>
66#endif
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
68#include <fcntl.h>
69#elif defined(HAVE_SYS_FCNTL_H)
70#include <sys/fcntl.h>
71#endif
72
73#ifdef HAVE_SYS_TIME_H
74# include <sys/time.h>
75#endif
76
77#include <sys/stat.h>
78
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
81#endif
82
83#if !defined NOFILE
84# define NOFILE 64
85#endif
86
87#ifdef HAVE_UNISTD_H
88#include <unistd.h>
89#endif
90
91#ifdef HAVE_SYSCALL_H
92#include <syscall.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
95#endif
96
97#ifdef HAVE_SYS_UIO_H
98#include <sys/uio.h>
99#endif
100
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h> /* for WNOHANG on BSD */
103#endif
104
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
107
108# ifndef COPYFILE_STATE_COPIED
109/*
110 * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
111 * COPYFILE_STATE_COPIED. Since the only use of the former here
112 * requires the latter, we disable the former when the latter is undefined.
113 */
114# undef HAVE_FCOPYFILE
115# endif
116
117#endif
118
120#include "ccan/list/list.h"
121#include "dln.h"
122#include "encindex.h"
123#include "id.h"
124#include "internal.h"
125#include "internal/class.h"
126#include "internal/encoding.h"
127#include "internal/error.h"
128#include "internal/inits.h"
129#include "internal/io.h"
130#include "internal/numeric.h"
131#include "internal/object.h"
132#include "internal/process.h"
133#include "internal/thread.h"
134#include "internal/transcode.h"
135#include "internal/variable.h"
136#include "ruby/io.h"
137#include "ruby/io/buffer.h"
138#include "ruby/missing.h"
139#include "ruby/thread.h"
140#include "ruby/util.h"
141#include "ruby_atomic.h"
142#include "ruby/ractor.h"
143
144#if !USE_POLL
145# include "vm_core.h"
146#endif
147
148#include "builtin.h"
149
150#ifndef O_ACCMODE
151#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
152#endif
153
154#ifndef PIPE_BUF
155# ifdef _POSIX_PIPE_BUF
156# define PIPE_BUF _POSIX_PIPE_BUF
157# else
158# define PIPE_BUF 512 /* is this ok? */
159# endif
160#endif
161
162#ifndef EWOULDBLOCK
163# define EWOULDBLOCK EAGAIN
164#endif
165
166#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
167/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
168off_t __syscall(quad_t number, ...);
169#endif
170
171#define IO_RBUF_CAPA_MIN 8192
172#define IO_CBUF_CAPA_MIN (128*1024)
173#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174#define IO_WBUF_CAPA_MIN 8192
175
176#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
177
178/* define system APIs */
179#ifdef _WIN32
180#undef open
181#define open rb_w32_uopen
182#undef rename
183#define rename(f, t) rb_w32_urename((f), (t))
184#include "win32/file.h"
185#endif
186
193
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196static VALUE rb_eEWOULDBLOCKWaitReadable;
197static VALUE rb_eEWOULDBLOCKWaitWritable;
198static VALUE rb_eEINPROGRESSWaitWritable;
199static VALUE rb_eEINPROGRESSWaitReadable;
200
202static VALUE orig_stdout, orig_stderr;
203
204VALUE rb_output_fs;
205VALUE rb_rs;
208
209static VALUE argf;
210
211static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
212static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
213static VALUE sym_textmode, sym_binmode, sym_autoclose;
214static VALUE sym_SET, sym_CUR, sym_END;
215static VALUE sym_wait_readable, sym_wait_writable;
216#ifdef SEEK_DATA
217static VALUE sym_DATA;
218#endif
219#ifdef SEEK_HOLE
220static VALUE sym_HOLE;
221#endif
222
223static VALUE prep_io(int fd, int 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(function, argument, io->fd, 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
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
796rb_io_check_closed(rb_io_t *fptr)
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
1025{
1027}
1028
1029static rb_encoding*
1030io_read_encoding(rb_io_t *fptr)
1031{
1032 if (fptr->encs.enc) {
1033 return fptr->encs.enc;
1034 }
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
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
1069rb_io_read_check(rb_io_t *fptr)
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 } else {
1189 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1190 return ready;
1191 }
1192}
1193
1194static VALUE
1195internal_read_func(void *ptr)
1196{
1197 struct io_internal_read_struct *iis = ptr;
1198 ssize_t result;
1199
1200 if (iis->timeout && !iis->nonblock) {
1201 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1202 return -1;
1203 }
1204 }
1205
1206 retry:
1207 result = read(iis->fd, iis->buf, iis->capa);
1208
1209 if (result < 0 && !iis->nonblock) {
1210 if (io_again_p(errno)) {
1211 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1212 return -1;
1213 }
1214 else {
1215 goto retry;
1216 }
1217 }
1218 }
1219
1220 return result;
1221}
1222
1223#if defined __APPLE__
1224# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1225#else
1226# define do_write_retry(code) result = code
1227#endif
1228
1229static VALUE
1230internal_write_func(void *ptr)
1231{
1232 struct io_internal_write_struct *iis = ptr;
1233 ssize_t result;
1234
1235 if (iis->timeout && !iis->nonblock) {
1236 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1237 return -1;
1238 }
1239 }
1240
1241 retry:
1242 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1243
1244 if (result < 0 && !iis->nonblock) {
1245 int e = errno;
1246 if (io_again_p(e)) {
1247 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1248 return -1;
1249 }
1250 else {
1251 goto retry;
1252 }
1253 }
1254 }
1255
1256 return result;
1257}
1258
1259#ifdef HAVE_WRITEV
1260static VALUE
1261internal_writev_func(void *ptr)
1262{
1263 struct io_internal_writev_struct *iis = ptr;
1264 ssize_t result;
1265
1266 if (iis->timeout && !iis->nonblock) {
1267 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1268 return -1;
1269 }
1270 }
1271
1272 retry:
1273 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1274
1275 if (result < 0 && !iis->nonblock) {
1276 if (io_again_p(errno)) {
1277 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1278 return -1;
1279 }
1280 else {
1281 goto retry;
1282 }
1283 }
1284 }
1285
1286 return result;
1287}
1288#endif
1289
1290static ssize_t
1291rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1292{
1293 VALUE scheduler = rb_fiber_scheduler_current();
1294 if (scheduler != Qnil) {
1295 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1296
1297 if (!UNDEF_P(result)) {
1299 }
1300 }
1301
1302 struct io_internal_read_struct iis = {
1303 .th = rb_thread_current(),
1304 .fptr = fptr,
1305 .nonblock = 0,
1306 .fd = fptr->fd,
1307
1308 .buf = buf,
1309 .capa = count,
1310 .timeout = NULL,
1311 };
1312
1313 struct timeval timeout_storage;
1314
1315 if (fptr->timeout != Qnil) {
1316 timeout_storage = rb_time_interval(fptr->timeout);
1317 iis.timeout = &timeout_storage;
1318 }
1319
1320 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1321}
1322
1323static ssize_t
1324rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1325{
1326 VALUE scheduler = rb_fiber_scheduler_current();
1327 if (scheduler != Qnil) {
1328 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1329
1330 if (!UNDEF_P(result)) {
1332 }
1333 }
1334
1335 struct io_internal_write_struct iis = {
1336 .th = rb_thread_current(),
1337 .fptr = fptr,
1338 .nonblock = 0,
1339 .fd = fptr->fd,
1340
1341 .buf = buf,
1342 .capa = count,
1343 .timeout = NULL
1344 };
1345
1346 struct timeval timeout_storage;
1347
1348 if (fptr->timeout != Qnil) {
1349 timeout_storage = rb_time_interval(fptr->timeout);
1350 iis.timeout = &timeout_storage;
1351 }
1352
1353 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1354}
1355
1356#ifdef HAVE_WRITEV
1357static ssize_t
1358rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1359{
1360 if (!iovcnt) return 0;
1361
1362 VALUE scheduler = rb_fiber_scheduler_current();
1363 if (scheduler != Qnil) {
1364 // This path assumes at least one `iov`:
1365 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1366
1367 if (!UNDEF_P(result)) {
1369 }
1370 }
1371
1372 struct io_internal_writev_struct iis = {
1373 .th = rb_thread_current(),
1374 .fptr = fptr,
1375 .nonblock = 0,
1376 .fd = fptr->fd,
1377
1378 .iov = iov,
1379 .iovcnt = iovcnt,
1380 .timeout = NULL
1381 };
1382
1383 struct timeval timeout_storage;
1384
1385 if (fptr->timeout != Qnil) {
1386 timeout_storage = rb_time_interval(fptr->timeout);
1387 iis.timeout = &timeout_storage;
1388 }
1389
1390 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1391}
1392#endif
1393
1394static VALUE
1395io_flush_buffer_sync(void *arg)
1396{
1397 rb_io_t *fptr = arg;
1398 long l = fptr->wbuf.len;
1399 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1400
1401 if (fptr->wbuf.len <= r) {
1402 fptr->wbuf.off = 0;
1403 fptr->wbuf.len = 0;
1404 return 0;
1405 }
1406
1407 if (0 <= r) {
1408 fptr->wbuf.off += (int)r;
1409 fptr->wbuf.len -= (int)r;
1410 errno = EAGAIN;
1411 }
1412
1413 return (VALUE)-1;
1414}
1415
1416static VALUE
1417io_flush_buffer_async(VALUE arg)
1418{
1419 rb_io_t *fptr = (rb_io_t *)arg;
1420 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1421}
1422
1423static inline int
1424io_flush_buffer(rb_io_t *fptr)
1425{
1426 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1427 return (int)io_flush_buffer_async((VALUE)fptr);
1428 }
1429 else {
1430 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1431 }
1432}
1433
1434static int
1435io_fflush(rb_io_t *fptr)
1436{
1437 rb_io_check_closed(fptr);
1438
1439 if (fptr->wbuf.len == 0)
1440 return 0;
1441
1442 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1443 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1444 return -1;
1445
1446 rb_io_check_closed(fptr);
1447 }
1448
1449 return 0;
1450}
1451
1452VALUE
1453rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1454{
1455 VALUE scheduler = rb_fiber_scheduler_current();
1456
1457 if (scheduler != Qnil) {
1458 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1459 }
1460
1461 rb_io_t * fptr = NULL;
1462 RB_IO_POINTER(io, fptr);
1463
1464 struct timeval tv_storage;
1465 struct timeval *tv = NULL;
1466
1467 if (NIL_OR_UNDEF_P(timeout)) {
1468 timeout = fptr->timeout;
1469 }
1470
1471 if (timeout != Qnil) {
1472 tv_storage = rb_time_interval(timeout);
1473 tv = &tv_storage;
1474 }
1475
1476 int ready = rb_thread_wait_for_single_fd(fptr->fd, RB_NUM2INT(events), tv);
1477
1478 if (ready < 0) {
1479 rb_sys_fail(0);
1480 }
1481
1482 // Not sure if this is necessary:
1483 rb_io_check_closed(fptr);
1484
1485 if (ready) {
1486 return RB_INT2NUM(ready);
1487 }
1488 else {
1489 return Qfalse;
1490 }
1491}
1492
1493static VALUE
1494io_from_fd(int fd)
1495{
1496 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1497}
1498
1499static int
1500io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1501{
1502 VALUE scheduler = rb_fiber_scheduler_current();
1503
1504 if (scheduler != Qnil) {
1505 return RTEST(
1506 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1507 );
1508 }
1509
1510 return rb_thread_wait_for_single_fd(fd, events, timeout);
1511}
1512
1513int
1515{
1516 io_fd_check_closed(f);
1517
1518 VALUE scheduler = rb_fiber_scheduler_current();
1519
1520 switch (errno) {
1521 case EINTR:
1522#if defined(ERESTART)
1523 case ERESTART:
1524#endif
1526 return TRUE;
1527
1528 case EAGAIN:
1529#if EWOULDBLOCK != EAGAIN
1530 case EWOULDBLOCK:
1531#endif
1532 if (scheduler != Qnil) {
1533 return RTEST(
1534 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1535 );
1536 }
1537 else {
1538 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1539 }
1540 return TRUE;
1541
1542 default:
1543 return FALSE;
1544 }
1545}
1546
1547int
1549{
1550 io_fd_check_closed(f);
1551
1552 VALUE scheduler = rb_fiber_scheduler_current();
1553
1554 switch (errno) {
1555 case EINTR:
1556#if defined(ERESTART)
1557 case ERESTART:
1558#endif
1559 /*
1560 * In old Linux, several special files under /proc and /sys don't handle
1561 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1562 * Otherwise, we face nasty hang up. Sigh.
1563 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1564 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1565 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1566 * Then rb_thread_check_ints() is enough.
1567 */
1569 return TRUE;
1570
1571 case EAGAIN:
1572#if EWOULDBLOCK != EAGAIN
1573 case EWOULDBLOCK:
1574#endif
1575 if (scheduler != Qnil) {
1576 return RTEST(
1577 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1578 );
1579 }
1580 else {
1581 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1582 }
1583 return TRUE;
1584
1585 default:
1586 return FALSE;
1587 }
1588}
1589
1590int
1591rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1592{
1593 return io_wait_for_single_fd(fd, events, timeout);
1594}
1595
1596int
1598{
1599 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1600}
1601
1602int
1604{
1605 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1606}
1607
1608VALUE
1609rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1610{
1611 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1612 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1613 // instead relies on `read(-1) -> -1` which causes this code path. We then
1614 // check here whether the IO was in fact closed. Probably it's better to
1615 // check that `fptr->fd != -1` before using it in syscall.
1616 rb_io_check_closed(RFILE(io)->fptr);
1617
1618 switch (error) {
1619 // In old Linux, several special files under /proc and /sys don't handle
1620 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1621 // Otherwise, we face nasty hang up. Sigh.
1622 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1623 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1624 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1625 // Then rb_thread_check_ints() is enough.
1626 case EINTR:
1627#if defined(ERESTART)
1628 case ERESTART:
1629#endif
1630 // We might have pending interrupts since the previous syscall was interrupted:
1632
1633 // The operation was interrupted, so retry it immediately:
1634 return events;
1635
1636 case EAGAIN:
1637#if EWOULDBLOCK != EAGAIN
1638 case EWOULDBLOCK:
1639#endif
1640 // The operation would block, so wait for the specified events:
1641 return rb_io_wait(io, events, timeout);
1642
1643 default:
1644 // Non-specific error, no event is ready:
1645 return Qnil;
1646 }
1647}
1648
1649int
1651{
1652 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1653
1654 if (RTEST(result)) {
1655 return RB_NUM2INT(result);
1656 }
1657 else if (result == RUBY_Qfalse) {
1658 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1659 }
1660
1661 return 0;
1662}
1663
1664int
1666{
1667 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1668
1669 if (RTEST(result)) {
1670 return RB_NUM2INT(result);
1671 }
1672 else if (result == RUBY_Qfalse) {
1673 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1674 }
1675
1676 return 0;
1677}
1678
1679static void
1680make_writeconv(rb_io_t *fptr)
1681{
1682 if (!fptr->writeconv_initialized) {
1683 const char *senc, *denc;
1684 rb_encoding *enc;
1685 int ecflags;
1686 VALUE ecopts;
1687
1688 fptr->writeconv_initialized = 1;
1689
1691 ecopts = fptr->encs.ecopts;
1692
1693 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1694 /* no encoding conversion */
1695 fptr->writeconv_pre_ecflags = 0;
1696 fptr->writeconv_pre_ecopts = Qnil;
1697 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1698 if (!fptr->writeconv)
1699 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1701 }
1702 else {
1703 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1704 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1705 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1706 /* single conversion */
1707 fptr->writeconv_pre_ecflags = ecflags;
1708 fptr->writeconv_pre_ecopts = ecopts;
1709 fptr->writeconv = NULL;
1711 }
1712 else {
1713 /* double conversion */
1715 fptr->writeconv_pre_ecopts = ecopts;
1716 if (senc) {
1717 denc = rb_enc_name(enc);
1718 fptr->writeconv_asciicompat = rb_str_new2(senc);
1719 }
1720 else {
1721 senc = denc = "";
1722 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1723 }
1725 ecopts = fptr->encs.ecopts;
1726 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1727 if (!fptr->writeconv)
1728 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1729 }
1730 }
1731 }
1732}
1733
1734/* writing functions */
1736 rb_io_t *fptr;
1737 const char *ptr;
1738 long length;
1739};
1740
1742 VALUE io;
1743 VALUE str;
1744 int nosync;
1745};
1746
1747#ifdef HAVE_WRITEV
1748static ssize_t
1749io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1750{
1751 if (fptr->wbuf.len) {
1752 struct iovec iov[2];
1753
1754 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1755 iov[0].iov_len = fptr->wbuf.len;
1756 iov[1].iov_base = (void*)ptr;
1757 iov[1].iov_len = length;
1758
1759 ssize_t result = rb_writev_internal(fptr, iov, 2);
1760
1761 if (result < 0)
1762 return result;
1763
1764 if (result >= fptr->wbuf.len) {
1765 // We wrote more than the internal buffer:
1766 result -= fptr->wbuf.len;
1767 fptr->wbuf.off = 0;
1768 fptr->wbuf.len = 0;
1769 }
1770 else {
1771 // We only wrote less data than the internal buffer:
1772 fptr->wbuf.off += (int)result;
1773 fptr->wbuf.len -= (int)result;
1774
1775 result = 0;
1776 }
1777
1778 return result;
1779 }
1780 else {
1781 return rb_io_write_memory(fptr, ptr, length);
1782 }
1783}
1784#else
1785static ssize_t
1786io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1787{
1788 long remaining = length;
1789
1790 if (fptr->wbuf.len) {
1791 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1792 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1793 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1794 fptr->wbuf.off = 0;
1795 }
1796
1797 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1798 fptr->wbuf.len += (int)length;
1799
1800 // We copied the entire incoming data to the internal buffer:
1801 remaining = 0;
1802 }
1803
1804 // Flush the internal buffer:
1805 if (io_fflush(fptr) < 0) {
1806 return -1;
1807 }
1808
1809 // If all the data was buffered, we are done:
1810 if (remaining == 0) {
1811 return length;
1812 }
1813 }
1814
1815 // Otherwise, we should write the data directly:
1816 return rb_io_write_memory(fptr, ptr, length);
1817}
1818#endif
1819
1820static VALUE
1821io_binwrite_string(VALUE arg)
1822{
1823 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1824
1825 const char *ptr = p->ptr;
1826 size_t remaining = p->length;
1827
1828 while (remaining) {
1829 // Write as much as possible:
1830 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1831
1832 if (result == 0) {
1833 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1834 // should try again immediately.
1835 }
1836 else if (result > 0) {
1837 if ((size_t)result == remaining) break;
1838 ptr += result;
1839 remaining -= result;
1840 }
1841 // Wait for it to become writable:
1842 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1843 rb_io_check_closed(p->fptr);
1844 }
1845 else {
1846 // The error was unrelated to waiting for it to become writable, so we fail:
1847 return -1;
1848 }
1849 }
1850
1851 return p->length;
1852}
1853
1854inline static void
1855io_allocate_write_buffer(rb_io_t *fptr, int sync)
1856{
1857 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1858 fptr->wbuf.off = 0;
1859 fptr->wbuf.len = 0;
1860 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1861 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1862 }
1863
1864 if (NIL_P(fptr->write_lock)) {
1865 fptr->write_lock = rb_mutex_new();
1866 rb_mutex_allow_trap(fptr->write_lock, 1);
1867 }
1868}
1869
1870static inline int
1871io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1872{
1873 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1874 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1875 return 1;
1876
1877 // If the amount of data we want to write exceeds the internal buffer:
1878 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1879 return 1;
1880
1881 // Otherwise, we can append to the internal buffer:
1882 return 0;
1883}
1884
1885static long
1886io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1887{
1888 if (len <= 0) return len;
1889
1890 // Don't write anything if current thread has a pending interrupt:
1892
1893 io_allocate_write_buffer(fptr, !nosync);
1894
1895 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1896 struct binwrite_arg arg;
1897
1898 arg.fptr = fptr;
1899 arg.ptr = ptr;
1900 arg.length = len;
1901
1902 if (!NIL_P(fptr->write_lock)) {
1903 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1904 }
1905 else {
1906 return io_binwrite_string((VALUE)&arg);
1907 }
1908 }
1909 else {
1910 if (fptr->wbuf.off) {
1911 if (fptr->wbuf.len)
1912 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1913 fptr->wbuf.off = 0;
1914 }
1915
1916 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1917 fptr->wbuf.len += (int)len;
1918
1919 return len;
1920 }
1921}
1922
1923# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1924 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1925
1926#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1927 MODE_BTMODE(d, e, f) : \
1928 MODE_BTMODE(a, b, c))
1929
1930static VALUE
1931do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1932{
1933 if (NEED_WRITECONV(fptr)) {
1934 VALUE common_encoding = Qnil;
1935 SET_BINARY_MODE(fptr);
1936
1937 make_writeconv(fptr);
1938
1939 if (fptr->writeconv) {
1940#define fmode (fptr->mode)
1941 if (!NIL_P(fptr->writeconv_asciicompat))
1942 common_encoding = fptr->writeconv_asciicompat;
1943 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1944 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1945 rb_enc_name(rb_enc_get(str)));
1946 }
1947#undef fmode
1948 }
1949 else {
1950 if (fptr->encs.enc2)
1951 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1952 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1953 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1954 }
1955
1956 if (!NIL_P(common_encoding)) {
1957 str = rb_str_encode(str, common_encoding,
1959 *converted = 1;
1960 }
1961
1962 if (fptr->writeconv) {
1964 *converted = 1;
1965 }
1966 }
1967#if RUBY_CRLF_ENVIRONMENT
1968#define fmode (fptr->mode)
1969 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1970 if ((fptr->mode & FMODE_READABLE) &&
1972 setmode(fptr->fd, O_BINARY);
1973 }
1974 else {
1975 setmode(fptr->fd, O_TEXT);
1976 }
1977 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1978 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1979 rb_enc_name(rb_enc_get(str)));
1980 }
1981 }
1982#undef fmode
1983#endif
1984 return str;
1985}
1986
1987static long
1988io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1989{
1990 int converted = 0;
1991 VALUE tmp;
1992 long n, len;
1993 const char *ptr;
1994
1995#ifdef _WIN32
1996 if (fptr->mode & FMODE_TTY) {
1997 long len = rb_w32_write_console(str, fptr->fd);
1998 if (len > 0) return len;
1999 }
2000#endif
2001
2002 str = do_writeconv(str, fptr, &converted);
2003 if (converted)
2004 OBJ_FREEZE(str);
2005
2006 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2007 RSTRING_GETMEM(tmp, ptr, len);
2008 n = io_binwrite(ptr, len, fptr, nosync);
2009 rb_str_tmp_frozen_release(str, tmp);
2010
2011 return n;
2012}
2013
2014ssize_t
2015rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2016{
2017 rb_io_t *fptr;
2018
2019 GetOpenFile(io, fptr);
2021 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2022}
2023
2024static VALUE
2025io_write(VALUE io, VALUE str, int nosync)
2026{
2027 rb_io_t *fptr;
2028 long n;
2029 VALUE tmp;
2030
2031 io = GetWriteIO(io);
2032 str = rb_obj_as_string(str);
2033 tmp = rb_io_check_io(io);
2034
2035 if (NIL_P(tmp)) {
2036 /* port is not IO, call write method for it. */
2037 return rb_funcall(io, id_write, 1, str);
2038 }
2039
2040 io = tmp;
2041 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2042
2043 GetOpenFile(io, fptr);
2045
2046 n = io_fwrite(str, fptr, nosync);
2047 if (n < 0L) rb_sys_fail_on_write(fptr);
2048
2049 return LONG2FIX(n);
2050}
2051
2052#ifdef HAVE_WRITEV
2053struct binwritev_arg {
2054 rb_io_t *fptr;
2055 struct iovec *iov;
2056 int iovcnt;
2057 size_t total;
2058};
2059
2060static VALUE
2061io_binwritev_internal(VALUE arg)
2062{
2063 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2064
2065 size_t remaining = p->total;
2066 size_t offset = 0;
2067
2068 rb_io_t *fptr = p->fptr;
2069 struct iovec *iov = p->iov;
2070 int iovcnt = p->iovcnt;
2071
2072 while (remaining) {
2073 long result = rb_writev_internal(fptr, iov, iovcnt);
2074
2075 if (result >= 0) {
2076 offset += result;
2077 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2078 if (offset < (size_t)fptr->wbuf.len) {
2079 fptr->wbuf.off += result;
2080 fptr->wbuf.len -= result;
2081 }
2082 else {
2083 offset -= (size_t)fptr->wbuf.len;
2084 fptr->wbuf.off = 0;
2085 fptr->wbuf.len = 0;
2086 }
2087 }
2088
2089 if (offset == p->total) {
2090 return p->total;
2091 }
2092
2093 while (result >= (ssize_t)iov->iov_len) {
2094 /* iovcnt > 0 */
2095 result -= iov->iov_len;
2096 iov->iov_len = 0;
2097 iov++;
2098
2099 if (!--iovcnt) {
2100 // I don't believe this code path can ever occur.
2101 return offset;
2102 }
2103 }
2104
2105 iov->iov_base = (char *)iov->iov_base + result;
2106 iov->iov_len -= result;
2107 }
2108 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2109 rb_io_check_closed(fptr);
2110 }
2111 else {
2112 return -1;
2113 }
2114 }
2115
2116 return offset;
2117}
2118
2119static long
2120io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2121{
2122 // Don't write anything if current thread has a pending interrupt:
2124
2125 if (iovcnt == 0) return 0;
2126
2127 size_t total = 0;
2128 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2129
2130 io_allocate_write_buffer(fptr, 1);
2131
2132 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2133 // The end of the buffered data:
2134 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2135
2136 if (offset + total <= (size_t)fptr->wbuf.capa) {
2137 for (int i = 1; i < iovcnt; i++) {
2138 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2139 offset += iov[i].iov_len;
2140 }
2141
2142 fptr->wbuf.len += total;
2143
2144 return total;
2145 }
2146 else {
2147 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2148 iov[0].iov_len = fptr->wbuf.len;
2149 }
2150 }
2151 else {
2152 // The first iov is reserved for the internal buffer, and it's empty.
2153 iov++;
2154
2155 if (!--iovcnt) {
2156 // If there are no other io vectors we are done.
2157 return 0;
2158 }
2159 }
2160
2161 struct binwritev_arg arg;
2162 arg.fptr = fptr;
2163 arg.iov = iov;
2164 arg.iovcnt = iovcnt;
2165 arg.total = total;
2166
2167 if (!NIL_P(fptr->write_lock)) {
2168 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2169 }
2170 else {
2171 return io_binwritev_internal((VALUE)&arg);
2172 }
2173}
2174
2175static long
2176io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2177{
2178 int i, converted, iovcnt = argc + 1;
2179 long n;
2180 VALUE v1, v2, str, tmp, *tmp_array;
2181 struct iovec *iov;
2182
2183 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2184 tmp_array = ALLOCV_N(VALUE, v2, argc);
2185
2186 for (i = 0; i < argc; i++) {
2187 str = rb_obj_as_string(argv[i]);
2188 converted = 0;
2189 str = do_writeconv(str, fptr, &converted);
2190
2191 if (converted)
2192 OBJ_FREEZE(str);
2193
2194 tmp = rb_str_tmp_frozen_acquire(str);
2195 tmp_array[i] = tmp;
2196
2197 /* iov[0] is reserved for buffer of fptr */
2198 iov[i+1].iov_base = RSTRING_PTR(tmp);
2199 iov[i+1].iov_len = RSTRING_LEN(tmp);
2200 }
2201
2202 n = io_binwritev(iov, iovcnt, fptr);
2203 if (v1) ALLOCV_END(v1);
2204
2205 for (i = 0; i < argc; i++) {
2206 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2207 }
2208
2209 if (v2) ALLOCV_END(v2);
2210
2211 return n;
2212}
2213
2214static int
2215iovcnt_ok(int iovcnt)
2216{
2217#ifdef IOV_MAX
2218 return iovcnt < IOV_MAX;
2219#else /* GNU/Hurd has writev, but no IOV_MAX */
2220 return 1;
2221#endif
2222}
2223#endif /* HAVE_WRITEV */
2224
2225static VALUE
2226io_writev(int argc, const VALUE *argv, VALUE io)
2227{
2228 rb_io_t *fptr;
2229 long n;
2230 VALUE tmp, total = INT2FIX(0);
2231 int i, cnt = 1;
2232
2233 io = GetWriteIO(io);
2234 tmp = rb_io_check_io(io);
2235
2236 if (NIL_P(tmp)) {
2237 /* port is not IO, call write method for it. */
2238 return rb_funcallv(io, id_write, argc, argv);
2239 }
2240
2241 io = tmp;
2242
2243 GetOpenFile(io, fptr);
2245
2246 for (i = 0; i < argc; i += cnt) {
2247#ifdef HAVE_WRITEV
2248 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2249 n = io_fwritev(cnt, &argv[i], fptr);
2250 }
2251 else
2252#endif
2253 {
2254 cnt = 1;
2255 /* sync at last item */
2256 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2257 }
2258
2259 if (n < 0L)
2260 rb_sys_fail_on_write(fptr);
2261
2262 total = rb_fix_plus(LONG2FIX(n), total);
2263 }
2264
2265 return total;
2266}
2267
2268/*
2269 * call-seq:
2270 * write(*objects) -> integer
2271 *
2272 * Writes each of the given +objects+ to +self+,
2273 * which must be opened for writing
2274 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2275 * returns the total number bytes written;
2276 * each of +objects+ that is not a string is converted via method +to_s+:
2277 *
2278 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2279 * $stdout.write('foo', :bar, 2, "\n") # => 8
2280 *
2281 * Output:
2282 *
2283 * Hello, World!
2284 * foobar2
2285 *
2286 * Related: IO#read.
2287 */
2288
2289static VALUE
2290io_write_m(int argc, VALUE *argv, VALUE io)
2291{
2292 if (argc != 1) {
2293 return io_writev(argc, argv, io);
2294 }
2295 else {
2296 VALUE str = argv[0];
2297 return io_write(io, str, 0);
2298 }
2299}
2300
2301VALUE
2302rb_io_write(VALUE io, VALUE str)
2303{
2304 return rb_funcallv(io, id_write, 1, &str);
2305}
2306
2307static VALUE
2308rb_io_writev(VALUE io, int argc, const VALUE *argv)
2309{
2310 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2311 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2312 VALUE klass = CLASS_OF(io);
2313 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2315 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2316 " which accepts just one argument",
2317 klass, sep
2318 );
2319 }
2320
2321 do rb_io_write(io, *argv++); while (--argc);
2322
2323 return Qnil;
2324 }
2325
2326 return rb_funcallv(io, id_write, argc, argv);
2327}
2328
2329/*
2330 * call-seq:
2331 * self << object -> self
2332 *
2333 * Writes the given +object+ to +self+,
2334 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2335 * returns +self+;
2336 * if +object+ is not a string, it is converted via method +to_s+:
2337 *
2338 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2339 * $stdout << 'foo' << :bar << 2 << "\n"
2340 *
2341 * Output:
2342 *
2343 * Hello, World!
2344 * foobar2
2345 *
2346 */
2347
2348
2349VALUE
2351{
2352 rb_io_write(io, str);
2353 return io;
2354}
2355
2356#ifdef HAVE_FSYNC
2357static VALUE
2358nogvl_fsync(void *ptr)
2359{
2360 rb_io_t *fptr = ptr;
2361
2362#ifdef _WIN32
2363 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2364 return 0;
2365#endif
2366 return (VALUE)fsync(fptr->fd);
2367}
2368#endif
2369
2370VALUE
2371rb_io_flush_raw(VALUE io, int sync)
2372{
2373 rb_io_t *fptr;
2374
2375 if (!RB_TYPE_P(io, T_FILE)) {
2376 return rb_funcall(io, id_flush, 0);
2377 }
2378
2379 io = GetWriteIO(io);
2380 GetOpenFile(io, fptr);
2381
2382 if (fptr->mode & FMODE_WRITABLE) {
2383 if (io_fflush(fptr) < 0)
2384 rb_sys_fail_on_write(fptr);
2385 }
2386 if (fptr->mode & FMODE_READABLE) {
2387 io_unread(fptr, true);
2388 }
2389
2390 return io;
2391}
2392
2393/*
2394 * call-seq:
2395 * flush -> self
2396 *
2397 * Flushes data buffered in +self+ to the operating system
2398 * (but does not necessarily flush data buffered in the operating system):
2399 *
2400 * $stdout.print 'no newline' # Not necessarily flushed.
2401 * $stdout.flush # Flushed.
2402 *
2403 */
2404
2405VALUE
2406rb_io_flush(VALUE io)
2407{
2408 return rb_io_flush_raw(io, 1);
2409}
2410
2411/*
2412 * call-seq:
2413 * tell -> integer
2414 *
2415 * Returns the current position (in bytes) in +self+
2416 * (see {Position}[rdoc-ref:IO@Position]):
2417 *
2418 * f = File.open('t.txt')
2419 * f.tell # => 0
2420 * f.gets # => "First line\n"
2421 * f.tell # => 12
2422 * f.close
2423 *
2424 * Related: IO#pos=, IO#seek.
2425 */
2426
2427static VALUE
2428rb_io_tell(VALUE io)
2429{
2430 rb_io_t *fptr;
2431 rb_off_t pos;
2432
2433 GetOpenFile(io, fptr);
2434 pos = io_tell(fptr);
2435 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2436 pos -= fptr->rbuf.len;
2437 return OFFT2NUM(pos);
2438}
2439
2440static VALUE
2441rb_io_seek(VALUE io, VALUE offset, int whence)
2442{
2443 rb_io_t *fptr;
2444 rb_off_t pos;
2445
2446 pos = NUM2OFFT(offset);
2447 GetOpenFile(io, fptr);
2448 pos = io_seek(fptr, pos, whence);
2449 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2450
2451 return INT2FIX(0);
2452}
2453
2454static int
2455interpret_seek_whence(VALUE vwhence)
2456{
2457 if (vwhence == sym_SET)
2458 return SEEK_SET;
2459 if (vwhence == sym_CUR)
2460 return SEEK_CUR;
2461 if (vwhence == sym_END)
2462 return SEEK_END;
2463#ifdef SEEK_DATA
2464 if (vwhence == sym_DATA)
2465 return SEEK_DATA;
2466#endif
2467#ifdef SEEK_HOLE
2468 if (vwhence == sym_HOLE)
2469 return SEEK_HOLE;
2470#endif
2471 return NUM2INT(vwhence);
2472}
2473
2474/*
2475 * call-seq:
2476 * seek(offset, whence = IO::SEEK_SET) -> 0
2477 *
2478 * Seeks to the position given by integer +offset+
2479 * (see {Position}[rdoc-ref:IO@Position])
2480 * and constant +whence+, which is one of:
2481 *
2482 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2483 * Repositions the stream to its current position plus the given +offset+:
2484 *
2485 * f = File.open('t.txt')
2486 * f.tell # => 0
2487 * f.seek(20, :CUR) # => 0
2488 * f.tell # => 20
2489 * f.seek(-10, :CUR) # => 0
2490 * f.tell # => 10
2491 * f.close
2492 *
2493 * - +:END+ or <tt>IO::SEEK_END</tt>:
2494 * Repositions the stream to its end plus the given +offset+:
2495 *
2496 * f = File.open('t.txt')
2497 * f.tell # => 0
2498 * f.seek(0, :END) # => 0 # Repositions to stream end.
2499 * f.tell # => 52
2500 * f.seek(-20, :END) # => 0
2501 * f.tell # => 32
2502 * f.seek(-40, :END) # => 0
2503 * f.tell # => 12
2504 * f.close
2505 *
2506 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2507 * Repositions the stream to the given +offset+:
2508 *
2509 * f = File.open('t.txt')
2510 * f.tell # => 0
2511 * f.seek(20, :SET) # => 0
2512 * f.tell # => 20
2513 * f.seek(40, :SET) # => 0
2514 * f.tell # => 40
2515 * f.close
2516 *
2517 * Related: IO#pos=, IO#tell.
2518 *
2519 */
2520
2521static VALUE
2522rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2523{
2524 VALUE offset, ptrname;
2525 int whence = SEEK_SET;
2526
2527 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2528 whence = interpret_seek_whence(ptrname);
2529 }
2530
2531 return rb_io_seek(io, offset, whence);
2532}
2533
2534/*
2535 * call-seq:
2536 * pos = new_position -> new_position
2537 *
2538 * Seeks to the given +new_position+ (in bytes);
2539 * see {Position}[rdoc-ref:IO@Position]:
2540 *
2541 * f = File.open('t.txt')
2542 * f.tell # => 0
2543 * f.pos = 20 # => 20
2544 * f.tell # => 20
2545 * f.close
2546 *
2547 * Related: IO#seek, IO#tell.
2548 *
2549 */
2550
2551static VALUE
2552rb_io_set_pos(VALUE io, VALUE offset)
2553{
2554 rb_io_t *fptr;
2555 rb_off_t pos;
2556
2557 pos = NUM2OFFT(offset);
2558 GetOpenFile(io, fptr);
2559 pos = io_seek(fptr, pos, SEEK_SET);
2560 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2561
2562 return OFFT2NUM(pos);
2563}
2564
2565static void clear_readconv(rb_io_t *fptr);
2566
2567/*
2568 * call-seq:
2569 * rewind -> 0
2570 *
2571 * Repositions the stream to its beginning,
2572 * setting both the position and the line number to zero;
2573 * see {Position}[rdoc-ref:IO@Position]
2574 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2575 *
2576 * f = File.open('t.txt')
2577 * f.tell # => 0
2578 * f.lineno # => 0
2579 * f.gets # => "First line\n"
2580 * f.tell # => 12
2581 * f.lineno # => 1
2582 * f.rewind # => 0
2583 * f.tell # => 0
2584 * f.lineno # => 0
2585 * f.close
2586 *
2587 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2588 *
2589 */
2590
2591static VALUE
2592rb_io_rewind(VALUE io)
2593{
2594 rb_io_t *fptr;
2595
2596 GetOpenFile(io, fptr);
2597 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2598 if (io == ARGF.current_file) {
2599 ARGF.lineno -= fptr->lineno;
2600 }
2601 fptr->lineno = 0;
2602 if (fptr->readconv) {
2603 clear_readconv(fptr);
2604 }
2605
2606 return INT2FIX(0);
2607}
2608
2609static int
2610fptr_wait_readable(rb_io_t *fptr)
2611{
2612 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2613
2614 if (result)
2615 rb_io_check_closed(fptr);
2616
2617 return result;
2618}
2619
2620static int
2621io_fillbuf(rb_io_t *fptr)
2622{
2623 ssize_t r;
2624
2625 if (fptr->rbuf.ptr == NULL) {
2626 fptr->rbuf.off = 0;
2627 fptr->rbuf.len = 0;
2628 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2629 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2630#ifdef _WIN32
2631 fptr->rbuf.capa--;
2632#endif
2633 }
2634 if (fptr->rbuf.len == 0) {
2635 retry:
2636 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2637
2638 if (r < 0) {
2639 if (fptr_wait_readable(fptr))
2640 goto retry;
2641
2642 int e = errno;
2643 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2644 if (!NIL_P(fptr->pathv)) {
2645 rb_str_append(path, fptr->pathv);
2646 }
2647
2648 rb_syserr_fail_path(e, path);
2649 }
2650 if (r > 0) rb_io_check_closed(fptr);
2651 fptr->rbuf.off = 0;
2652 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2653 if (r == 0)
2654 return -1; /* EOF */
2655 }
2656 return 0;
2657}
2658
2659/*
2660 * call-seq:
2661 * eof -> true or false
2662 *
2663 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2664 * see {Position}[rdoc-ref:IO@Position]:
2665 *
2666 * f = File.open('t.txt')
2667 * f.eof # => false
2668 * f.seek(0, :END) # => 0
2669 * f.eof # => true
2670 * f.close
2671 *
2672 * Raises an exception unless the stream is opened for reading;
2673 * see {Mode}[rdoc-ref:File@Access+Modes].
2674 *
2675 * If +self+ is a stream such as pipe or socket, this method
2676 * blocks until the other end sends some data or closes it:
2677 *
2678 * r, w = IO.pipe
2679 * Thread.new { sleep 1; w.close }
2680 * r.eof? # => true # After 1-second wait.
2681 *
2682 * r, w = IO.pipe
2683 * Thread.new { sleep 1; w.puts "a" }
2684 * r.eof? # => false # After 1-second wait.
2685 *
2686 * r, w = IO.pipe
2687 * r.eof? # blocks forever
2688 *
2689 * Note that this method reads data to the input byte buffer. So
2690 * IO#sysread may not behave as you intend with IO#eof?, unless you
2691 * call IO#rewind first (which is not available for some streams).
2692 */
2693
2694VALUE
2696{
2697 rb_io_t *fptr;
2698
2699 GetOpenFile(io, fptr);
2701
2702 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2703 if (READ_DATA_PENDING(fptr)) return Qfalse;
2704 READ_CHECK(fptr);
2705#if RUBY_CRLF_ENVIRONMENT
2706 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2707 return RBOOL(eof(fptr->fd));
2708 }
2709#endif
2710 return RBOOL(io_fillbuf(fptr) < 0);
2711}
2712
2713/*
2714 * call-seq:
2715 * sync -> true or false
2716 *
2717 * Returns the current sync mode of the stream.
2718 * When sync mode is true, all output is immediately flushed to the underlying
2719 * operating system and is not buffered by Ruby internally. See also #fsync.
2720 *
2721 * f = File.open('t.tmp', 'w')
2722 * f.sync # => false
2723 * f.sync = true
2724 * f.sync # => true
2725 * f.close
2726 *
2727 */
2728
2729static VALUE
2730rb_io_sync(VALUE io)
2731{
2732 rb_io_t *fptr;
2733
2734 io = GetWriteIO(io);
2735 GetOpenFile(io, fptr);
2736 return RBOOL(fptr->mode & FMODE_SYNC);
2737}
2738
2739#ifdef HAVE_FSYNC
2740
2741/*
2742 * call-seq:
2743 * sync = boolean -> boolean
2744 *
2745 * Sets the _sync_ _mode_ for the stream to the given value;
2746 * returns the given value.
2747 *
2748 * Values for the sync mode:
2749 *
2750 * - +true+: All output is immediately flushed to the
2751 * underlying operating system and is not buffered internally.
2752 * - +false+: Output may be buffered internally.
2753 *
2754 * Example;
2755 *
2756 * f = File.open('t.tmp', 'w')
2757 * f.sync # => false
2758 * f.sync = true
2759 * f.sync # => true
2760 * f.close
2761 *
2762 * Related: IO#fsync.
2763 *
2764 */
2765
2766static VALUE
2767rb_io_set_sync(VALUE io, VALUE sync)
2768{
2769 rb_io_t *fptr;
2770
2771 io = GetWriteIO(io);
2772 GetOpenFile(io, fptr);
2773 if (RTEST(sync)) {
2774 fptr->mode |= FMODE_SYNC;
2775 }
2776 else {
2777 fptr->mode &= ~FMODE_SYNC;
2778 }
2779 return sync;
2780}
2781
2782/*
2783 * call-seq:
2784 * fsync -> 0
2785 *
2786 * Immediately writes to disk all data buffered in the stream,
2787 * via the operating system's <tt>fsync(2)</tt>.
2788
2789 * Note this difference:
2790 *
2791 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2792 * but does not guarantee that the operating system actually writes the data to disk.
2793 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2794 * and that data is written to disk.
2795 *
2796 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2797 *
2798 */
2799
2800static VALUE
2801rb_io_fsync(VALUE io)
2802{
2803 rb_io_t *fptr;
2804
2805 io = GetWriteIO(io);
2806 GetOpenFile(io, fptr);
2807
2808 if (io_fflush(fptr) < 0)
2809 rb_sys_fail_on_write(fptr);
2810
2811 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2812 rb_sys_fail_path(fptr->pathv);
2813
2814 return INT2FIX(0);
2815}
2816#else
2817# define rb_io_fsync rb_f_notimplement
2818# define rb_io_sync rb_f_notimplement
2819static VALUE
2820rb_io_set_sync(VALUE io, VALUE sync)
2821{
2824}
2825#endif
2826
2827#ifdef HAVE_FDATASYNC
2828static VALUE
2829nogvl_fdatasync(void *ptr)
2830{
2831 rb_io_t *fptr = ptr;
2832
2833#ifdef _WIN32
2834 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2835 return 0;
2836#endif
2837 return (VALUE)fdatasync(fptr->fd);
2838}
2839
2840/*
2841 * call-seq:
2842 * fdatasync -> 0
2843 *
2844 * Immediately writes to disk all data buffered in the stream,
2845 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2846 * otherwise via <tt>fsync(2)</tt>, if supported;
2847 * otherwise raises an exception.
2848 *
2849 */
2850
2851static VALUE
2852rb_io_fdatasync(VALUE io)
2853{
2854 rb_io_t *fptr;
2855
2856 io = GetWriteIO(io);
2857 GetOpenFile(io, fptr);
2858
2859 if (io_fflush(fptr) < 0)
2860 rb_sys_fail_on_write(fptr);
2861
2862 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2863 return INT2FIX(0);
2864
2865 /* fall back */
2866 return rb_io_fsync(io);
2867}
2868#else
2869#define rb_io_fdatasync rb_io_fsync
2870#endif
2871
2872/*
2873 * call-seq:
2874 * fileno -> integer
2875 *
2876 * Returns the integer file descriptor for the stream:
2877 *
2878 * $stdin.fileno # => 0
2879 * $stdout.fileno # => 1
2880 * $stderr.fileno # => 2
2881 * File.open('t.txt').fileno # => 10
2882 * f.close
2883 *
2884 */
2885
2886static VALUE
2887rb_io_fileno(VALUE io)
2888{
2889 rb_io_t *fptr = RFILE(io)->fptr;
2890 int fd;
2891
2892 rb_io_check_closed(fptr);
2893 fd = fptr->fd;
2894 return INT2FIX(fd);
2895}
2896
2897int
2899{
2900 if (RB_TYPE_P(io, T_FILE)) {
2901 rb_io_t *fptr = RFILE(io)->fptr;
2902 rb_io_check_closed(fptr);
2903 return fptr->fd;
2904 }
2905 else {
2906 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2907 if (!UNDEF_P(fileno)) {
2908 return RB_NUM2INT(fileno);
2909 }
2910 }
2911
2912 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2913
2915}
2916
2917int
2919{
2920 rb_io_t *fptr;
2921 GetOpenFile(io, fptr);
2922 return fptr->mode;
2923}
2924
2925/*
2926 * call-seq:
2927 * pid -> integer or nil
2928 *
2929 * Returns the process ID of a child process associated with the stream,
2930 * which will have been set by IO#popen, or +nil+ if the stream was not
2931 * created by IO#popen:
2932 *
2933 * pipe = IO.popen("-")
2934 * if pipe
2935 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2936 * else
2937 * $stderr.puts "In child, pid is #{$$}"
2938 * end
2939 *
2940 * Output:
2941 *
2942 * In child, pid is 26209
2943 * In parent, child pid is 26209
2944 *
2945 */
2946
2947static VALUE
2948rb_io_pid(VALUE io)
2949{
2950 rb_io_t *fptr;
2951
2952 GetOpenFile(io, fptr);
2953 if (!fptr->pid)
2954 return Qnil;
2955 return PIDT2NUM(fptr->pid);
2956}
2957
2958/*
2959 * call-seq:
2960 * path -> string or nil
2961 *
2962 * Returns the path associated with the IO, or +nil+ if there is no path
2963 * associated with the IO. It is not guaranteed that the path exists on
2964 * the filesystem.
2965 *
2966 * $stdin.path # => "<STDIN>"
2967 *
2968 * File.open("testfile") {|f| f.path} # => "testfile"
2969 */
2970
2971VALUE
2973{
2974 rb_io_t *fptr = RFILE(io)->fptr;
2975
2976 if (!fptr)
2977 return Qnil;
2978
2979 return rb_obj_dup(fptr->pathv);
2980}
2981
2982/*
2983 * call-seq:
2984 * inspect -> string
2985 *
2986 * Returns a string representation of +self+:
2987 *
2988 * f = File.open('t.txt')
2989 * f.inspect # => "#<File:t.txt>"
2990 * f.close
2991 *
2992 */
2993
2994static VALUE
2995rb_io_inspect(VALUE obj)
2996{
2997 rb_io_t *fptr;
2998 VALUE result;
2999 static const char closed[] = " (closed)";
3000
3001 fptr = RFILE(obj)->fptr;
3002 if (!fptr) return rb_any_to_s(obj);
3003 result = rb_str_new_cstr("#<");
3004 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3005 rb_str_cat2(result, ":");
3006 if (NIL_P(fptr->pathv)) {
3007 if (fptr->fd < 0) {
3008 rb_str_cat(result, closed+1, strlen(closed)-1);
3009 }
3010 else {
3011 rb_str_catf(result, "fd %d", fptr->fd);
3012 }
3013 }
3014 else {
3015 rb_str_append(result, fptr->pathv);
3016 if (fptr->fd < 0) {
3017 rb_str_cat(result, closed, strlen(closed));
3018 }
3019 }
3020 return rb_str_cat2(result, ">");
3021}
3022
3023/*
3024 * call-seq:
3025 * to_io -> self
3026 *
3027 * Returns +self+.
3028 *
3029 */
3030
3031static VALUE
3032rb_io_to_io(VALUE io)
3033{
3034 return io;
3035}
3036
3037/* reading functions */
3038static long
3039read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3040{
3041 int n;
3042
3043 n = READ_DATA_PENDING_COUNT(fptr);
3044 if (n <= 0) return 0;
3045 if (n > len) n = (int)len;
3046 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3047 fptr->rbuf.off += n;
3048 fptr->rbuf.len -= n;
3049 return n;
3050}
3051
3052static long
3053io_bufread(char *ptr, long len, rb_io_t *fptr)
3054{
3055 long offset = 0;
3056 long n = len;
3057 long c;
3058
3059 if (READ_DATA_PENDING(fptr) == 0) {
3060 while (n > 0) {
3061 again:
3062 rb_io_check_closed(fptr);
3063 c = rb_io_read_memory(fptr, ptr+offset, n);
3064 if (c == 0) break;
3065 if (c < 0) {
3066 if (fptr_wait_readable(fptr))
3067 goto again;
3068 return -1;
3069 }
3070 offset += c;
3071 if ((n -= c) <= 0) break;
3072 }
3073 return len - n;
3074 }
3075
3076 while (n > 0) {
3077 c = read_buffered_data(ptr+offset, n, fptr);
3078 if (c > 0) {
3079 offset += c;
3080 if ((n -= c) <= 0) break;
3081 }
3082 rb_io_check_closed(fptr);
3083 if (io_fillbuf(fptr) < 0) {
3084 break;
3085 }
3086 }
3087 return len - n;
3088}
3089
3090static int io_setstrbuf(VALUE *str, long len);
3091
3093 char *str_ptr;
3094 long len;
3095 rb_io_t *fptr;
3096};
3097
3098static VALUE
3099bufread_call(VALUE arg)
3100{
3101 struct bufread_arg *p = (struct bufread_arg *)arg;
3102 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3103 return Qundef;
3104}
3105
3106static long
3107io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3108{
3109 long len;
3110 struct bufread_arg arg;
3111
3112 io_setstrbuf(&str, offset + size);
3113 arg.str_ptr = RSTRING_PTR(str) + offset;
3114 arg.len = size;
3115 arg.fptr = fptr;
3116 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3117 len = arg.len;
3118 if (len < 0) rb_sys_fail_path(fptr->pathv);
3119 return len;
3120}
3121
3122static long
3123remain_size(rb_io_t *fptr)
3124{
3125 struct stat st;
3126 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3127 rb_off_t pos;
3128
3129 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3130#if defined(__HAIKU__)
3131 && (st.st_dev > 3)
3132#endif
3133 )
3134 {
3135 if (io_fflush(fptr) < 0)
3136 rb_sys_fail_on_write(fptr);
3137 pos = lseek(fptr->fd, 0, SEEK_CUR);
3138 if (st.st_size >= pos && pos >= 0) {
3139 siz += st.st_size - pos;
3140 if (siz > LONG_MAX) {
3141 rb_raise(rb_eIOError, "file too big for single read");
3142 }
3143 }
3144 }
3145 else {
3146 siz += BUFSIZ;
3147 }
3148 return (long)siz;
3149}
3150
3151static VALUE
3152io_enc_str(VALUE str, rb_io_t *fptr)
3153{
3154 rb_enc_associate(str, io_read_encoding(fptr));
3155 return str;
3156}
3157
3158static rb_encoding *io_read_encoding(rb_io_t *fptr);
3159
3160static void
3161make_readconv(rb_io_t *fptr, int size)
3162{
3163 if (!fptr->readconv) {
3164 int ecflags;
3165 VALUE ecopts;
3166 const char *sname, *dname;
3168 ecopts = fptr->encs.ecopts;
3169 if (fptr->encs.enc2) {
3170 sname = rb_enc_name(fptr->encs.enc2);
3171 dname = rb_enc_name(io_read_encoding(fptr));
3172 }
3173 else {
3174 sname = dname = "";
3175 }
3176 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3177 if (!fptr->readconv)
3178 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3179 fptr->cbuf.off = 0;
3180 fptr->cbuf.len = 0;
3181 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3182 fptr->cbuf.capa = size;
3183 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3184 }
3185}
3186
3187#define MORE_CHAR_SUSPENDED Qtrue
3188#define MORE_CHAR_FINISHED Qnil
3189static VALUE
3190fill_cbuf(rb_io_t *fptr, int ec_flags)
3191{
3192 const unsigned char *ss, *sp, *se;
3193 unsigned char *ds, *dp, *de;
3195 int putbackable;
3196 int cbuf_len0;
3197 VALUE exc;
3198
3199 ec_flags |= ECONV_PARTIAL_INPUT;
3200
3201 if (fptr->cbuf.len == fptr->cbuf.capa)
3202 return MORE_CHAR_SUSPENDED; /* cbuf full */
3203 if (fptr->cbuf.len == 0)
3204 fptr->cbuf.off = 0;
3205 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3206 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3207 fptr->cbuf.off = 0;
3208 }
3209
3210 cbuf_len0 = fptr->cbuf.len;
3211
3212 while (1) {
3213 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3214 se = sp + fptr->rbuf.len;
3215 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3216 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3217 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3218 fptr->rbuf.off += (int)(sp - ss);
3219 fptr->rbuf.len -= (int)(sp - ss);
3220 fptr->cbuf.len += (int)(dp - ds);
3221
3222 putbackable = rb_econv_putbackable(fptr->readconv);
3223 if (putbackable) {
3224 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3225 fptr->rbuf.off -= putbackable;
3226 fptr->rbuf.len += putbackable;
3227 }
3228
3229 exc = rb_econv_make_exception(fptr->readconv);
3230 if (!NIL_P(exc))
3231 return exc;
3232
3233 if (cbuf_len0 != fptr->cbuf.len)
3234 return MORE_CHAR_SUSPENDED;
3235
3236 if (res == econv_finished) {
3237 return MORE_CHAR_FINISHED;
3238 }
3239
3240 if (res == econv_source_buffer_empty) {
3241 if (fptr->rbuf.len == 0) {
3242 READ_CHECK(fptr);
3243 if (io_fillbuf(fptr) < 0) {
3244 if (!fptr->readconv) {
3245 return MORE_CHAR_FINISHED;
3246 }
3247 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3248 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3249 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3250 fptr->cbuf.len += (int)(dp - ds);
3252 break;
3253 }
3254 }
3255 }
3256 }
3257 if (cbuf_len0 != fptr->cbuf.len)
3258 return MORE_CHAR_SUSPENDED;
3259
3260 return MORE_CHAR_FINISHED;
3261}
3262
3263static VALUE
3264more_char(rb_io_t *fptr)
3265{
3266 VALUE v;
3267 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3268 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3269 rb_exc_raise(v);
3270 return v;
3271}
3272
3273static VALUE
3274io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3275{
3276 VALUE str = Qnil;
3277 if (strp) {
3278 str = *strp;
3279 if (NIL_P(str)) {
3280 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3281 }
3282 else {
3283 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3284 }
3285 rb_enc_associate(str, fptr->encs.enc);
3286 }
3287 fptr->cbuf.off += len;
3288 fptr->cbuf.len -= len;
3289 /* xxx: set coderange */
3290 if (fptr->cbuf.len == 0)
3291 fptr->cbuf.off = 0;
3292 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3293 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3294 fptr->cbuf.off = 0;
3295 }
3296 return str;
3297}
3298
3299static int
3300io_setstrbuf(VALUE *str, long len)
3301{
3302#ifdef _WIN32
3303 if (len > 0)
3304 len = (len + 1) & ~1L; /* round up for wide char */
3305#endif
3306 if (NIL_P(*str)) {
3307 *str = rb_str_new(0, len);
3308 return TRUE;
3309 }
3310 else {
3311 VALUE s = StringValue(*str);
3312 rb_str_modify(s);
3313
3314 long clen = RSTRING_LEN(s);
3315 if (clen >= len) {
3316 return FALSE;
3317 }
3318 len -= clen;
3319 }
3320 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3322 }
3323 return FALSE;
3324}
3325
3326#define MAX_REALLOC_GAP 4096
3327static void
3328io_shrink_read_string(VALUE str, long n)
3329{
3330 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3331 rb_str_resize(str, n);
3332 }
3333}
3334
3335static void
3336io_set_read_length(VALUE str, long n, int shrinkable)
3337{
3338 if (RSTRING_LEN(str) != n) {
3339 rb_str_modify(str);
3340 rb_str_set_len(str, n);
3341 if (shrinkable) io_shrink_read_string(str, n);
3342 }
3343}
3344
3345static VALUE
3346read_all(rb_io_t *fptr, long siz, VALUE str)
3347{
3348 long bytes;
3349 long n;
3350 long pos;
3351 rb_encoding *enc;
3352 int cr;
3353 int shrinkable;
3354
3355 if (NEED_READCONV(fptr)) {
3356 int first = !NIL_P(str);
3357 SET_BINARY_MODE(fptr);
3358 shrinkable = io_setstrbuf(&str,0);
3359 make_readconv(fptr, 0);
3360 while (1) {
3361 VALUE v;
3362 if (fptr->cbuf.len) {
3363 if (first) rb_str_set_len(str, first = 0);
3364 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3365 }
3366 v = fill_cbuf(fptr, 0);
3367 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3368 if (fptr->cbuf.len) {
3369 if (first) rb_str_set_len(str, first = 0);
3370 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3371 }
3372 rb_exc_raise(v);
3373 }
3374 if (v == MORE_CHAR_FINISHED) {
3375 clear_readconv(fptr);
3376 if (first) rb_str_set_len(str, first = 0);
3377 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3378 return io_enc_str(str, fptr);
3379 }
3380 }
3381 }
3382
3383 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3384 bytes = 0;
3385 pos = 0;
3386
3387 enc = io_read_encoding(fptr);
3388 cr = 0;
3389
3390 if (siz == 0) siz = BUFSIZ;
3391 shrinkable = io_setstrbuf(&str, siz);
3392 for (;;) {
3393 READ_CHECK(fptr);
3394 n = io_fread(str, bytes, siz - bytes, fptr);
3395 if (n == 0 && bytes == 0) {
3396 rb_str_set_len(str, 0);
3397 break;
3398 }
3399 bytes += n;
3400 rb_str_set_len(str, bytes);
3401 if (cr != ENC_CODERANGE_BROKEN)
3402 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3403 if (bytes < siz) break;
3404 siz += BUFSIZ;
3405
3406 size_t capa = rb_str_capacity(str);
3407 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3408 if (capa < BUFSIZ) {
3409 capa = BUFSIZ;
3410 }
3411 else if (capa > IO_MAX_BUFFER_GROWTH) {
3412 capa = IO_MAX_BUFFER_GROWTH;
3413 }
3415 }
3416 }
3417 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3418 str = io_enc_str(str, fptr);
3419 ENC_CODERANGE_SET(str, cr);
3420 return str;
3421}
3422
3423void
3425{
3426 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3427 rb_sys_fail_path(fptr->pathv);
3428 }
3429}
3430
3431static VALUE
3432io_read_memory_call(VALUE arg)
3433{
3434 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3435
3436 VALUE scheduler = rb_fiber_scheduler_current();
3437 if (scheduler != Qnil) {
3438 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3439
3440 if (!UNDEF_P(result)) {
3441 // This is actually returned as a pseudo-VALUE and later cast to a long:
3443 }
3444 }
3445
3446 if (iis->nonblock) {
3447 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3448 }
3449 else {
3450 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3451 }
3452}
3453
3454static long
3455io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3456{
3457 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3458}
3459
3460#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3461
3462static VALUE
3463io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3464{
3465 rb_io_t *fptr;
3466 VALUE length, str;
3467 long n, len;
3468 struct io_internal_read_struct iis;
3469 int shrinkable;
3470
3471 rb_scan_args(argc, argv, "11", &length, &str);
3472
3473 if ((len = NUM2LONG(length)) < 0) {
3474 rb_raise(rb_eArgError, "negative length %ld given", len);
3475 }
3476
3477 shrinkable = io_setstrbuf(&str, len);
3478
3479 GetOpenFile(io, fptr);
3481
3482 if (len == 0) {
3483 io_set_read_length(str, 0, shrinkable);
3484 return str;
3485 }
3486
3487 if (!nonblock)
3488 READ_CHECK(fptr);
3489 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3490 if (n <= 0) {
3491 again:
3492 if (nonblock) {
3493 rb_io_set_nonblock(fptr);
3494 }
3495 io_setstrbuf(&str, len);
3496 iis.th = rb_thread_current();
3497 iis.fptr = fptr;
3498 iis.nonblock = nonblock;
3499 iis.fd = fptr->fd;
3500 iis.buf = RSTRING_PTR(str);
3501 iis.capa = len;
3502 iis.timeout = NULL;
3503 n = io_read_memory_locktmp(str, &iis);
3504 if (n < 0) {
3505 int e = errno;
3506 if (!nonblock && fptr_wait_readable(fptr))
3507 goto again;
3508 if (nonblock && (io_again_p(e))) {
3509 if (no_exception)
3510 return sym_wait_readable;
3511 else
3512 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3513 e, "read would block");
3514 }
3515 rb_syserr_fail_path(e, fptr->pathv);
3516 }
3517 }
3518 io_set_read_length(str, n, shrinkable);
3519
3520 if (n == 0)
3521 return Qnil;
3522 else
3523 return str;
3524}
3525
3526/*
3527 * call-seq:
3528 * readpartial(maxlen) -> string
3529 * readpartial(maxlen, out_string) -> out_string
3530 *
3531 * Reads up to +maxlen+ bytes from the stream;
3532 * returns a string (either a new string or the given +out_string+).
3533 * Its encoding is:
3534 *
3535 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3536 * - ASCII-8BIT, otherwise.
3537 *
3538 * - Contains +maxlen+ bytes from the stream, if available.
3539 * - Otherwise contains all available bytes, if any available.
3540 * - Otherwise is an empty string.
3541 *
3542 * With the single non-negative integer argument +maxlen+ given,
3543 * returns a new string:
3544 *
3545 * f = File.new('t.txt')
3546 * f.readpartial(20) # => "First line\nSecond l"
3547 * f.readpartial(20) # => "ine\n\nFourth line\n"
3548 * f.readpartial(20) # => "Fifth line\n"
3549 * f.readpartial(20) # Raises EOFError.
3550 * f.close
3551 *
3552 * With both argument +maxlen+ and string argument +out_string+ given,
3553 * returns modified +out_string+:
3554 *
3555 * f = File.new('t.txt')
3556 * s = 'foo'
3557 * f.readpartial(20, s) # => "First line\nSecond l"
3558 * s = 'bar'
3559 * f.readpartial(0, s) # => ""
3560 * f.close
3561 *
3562 * This method is useful for a stream such as a pipe, a socket, or a tty.
3563 * It blocks only when no data is immediately available.
3564 * This means that it blocks only when _all_ of the following are true:
3565 *
3566 * - The byte buffer in the stream is empty.
3567 * - The content of the stream is empty.
3568 * - The stream is not at EOF.
3569 *
3570 * When blocked, the method waits for either more data or EOF on the stream:
3571 *
3572 * - If more data is read, the method returns the data.
3573 * - If EOF is reached, the method raises EOFError.
3574 *
3575 * When not blocked, the method responds immediately:
3576 *
3577 * - Returns data from the buffer if there is any.
3578 * - Otherwise returns data from the stream if there is any.
3579 * - Otherwise raises EOFError if the stream has reached EOF.
3580 *
3581 * Note that this method is similar to sysread. The differences are:
3582 *
3583 * - If the byte buffer is not empty, read from the byte buffer
3584 * instead of "sysread for buffered IO (IOError)".
3585 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3586 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3587 * readpartial retries the system call.
3588 *
3589 * The latter means that readpartial is non-blocking-flag insensitive.
3590 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3591 * if the fd is blocking mode.
3592 *
3593 * Examples:
3594 *
3595 * # # Returned Buffer Content Pipe Content
3596 * r, w = IO.pipe #
3597 * w << 'abc' # "" "abc".
3598 * r.readpartial(4096) # => "abc" "" ""
3599 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3600 *
3601 * # # Returned Buffer Content Pipe Content
3602 * r, w = IO.pipe #
3603 * w << 'abc' # "" "abc"
3604 * w.close # "" "abc" EOF
3605 * r.readpartial(4096) # => "abc" "" EOF
3606 * r.readpartial(4096) # raises EOFError
3607 *
3608 * # # Returned Buffer Content Pipe Content
3609 * r, w = IO.pipe #
3610 * w << "abc\ndef\n" # "" "abc\ndef\n"
3611 * r.gets # => "abc\n" "def\n" ""
3612 * w << "ghi\n" # "def\n" "ghi\n"
3613 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3614 * r.readpartial(4096) # => "ghi\n" "" ""
3615 *
3616 */
3617
3618static VALUE
3619io_readpartial(int argc, VALUE *argv, VALUE io)
3620{
3621 VALUE ret;
3622
3623 ret = io_getpartial(argc, argv, io, Qnil, 0);
3624 if (NIL_P(ret))
3625 rb_eof_error();
3626 return ret;
3627}
3628
3629static VALUE
3630io_nonblock_eof(int no_exception)
3631{
3632 if (!no_exception) {
3633 rb_eof_error();
3634 }
3635 return Qnil;
3636}
3637
3638/* :nodoc: */
3639static VALUE
3640io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3641{
3642 rb_io_t *fptr;
3643 long n, len;
3644 struct io_internal_read_struct iis;
3645 int shrinkable;
3646
3647 if ((len = NUM2LONG(length)) < 0) {
3648 rb_raise(rb_eArgError, "negative length %ld given", len);
3649 }
3650
3651 shrinkable = io_setstrbuf(&str, len);
3652 rb_bool_expected(ex, "exception", TRUE);
3653
3654 GetOpenFile(io, fptr);
3656
3657 if (len == 0) {
3658 io_set_read_length(str, 0, shrinkable);
3659 return str;
3660 }
3661
3662 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3663 if (n <= 0) {
3664 rb_fd_set_nonblock(fptr->fd);
3665 shrinkable |= io_setstrbuf(&str, len);
3666 iis.fptr = fptr;
3667 iis.nonblock = 1;
3668 iis.fd = fptr->fd;
3669 iis.buf = RSTRING_PTR(str);
3670 iis.capa = len;
3671 iis.timeout = NULL;
3672 n = io_read_memory_locktmp(str, &iis);
3673 if (n < 0) {
3674 int e = errno;
3675 if (io_again_p(e)) {
3676 if (!ex) return sym_wait_readable;
3677 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3678 e, "read would block");
3679 }
3680 rb_syserr_fail_path(e, fptr->pathv);
3681 }
3682 }
3683 io_set_read_length(str, n, shrinkable);
3684
3685 if (n == 0) {
3686 if (!ex) return Qnil;
3687 rb_eof_error();
3688 }
3689
3690 return str;
3691}
3692
3693/* :nodoc: */
3694static VALUE
3695io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3696{
3697 rb_io_t *fptr;
3698 long n;
3699
3700 if (!RB_TYPE_P(str, T_STRING))
3701 str = rb_obj_as_string(str);
3702 rb_bool_expected(ex, "exception", TRUE);
3703
3704 io = GetWriteIO(io);
3705 GetOpenFile(io, fptr);
3707
3708 if (io_fflush(fptr) < 0)
3709 rb_sys_fail_on_write(fptr);
3710
3711 rb_fd_set_nonblock(fptr->fd);
3712 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3713 RB_GC_GUARD(str);
3714
3715 if (n < 0) {
3716 int e = errno;
3717 if (io_again_p(e)) {
3718 if (!ex) {
3719 return sym_wait_writable;
3720 }
3721 else {
3722 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3723 }
3724 }
3725 rb_syserr_fail_path(e, fptr->pathv);
3726 }
3727
3728 return LONG2FIX(n);
3729}
3730
3731/*
3732 * call-seq:
3733 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3734 *
3735 * Reads bytes from the stream; the stream must be opened for reading
3736 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3737 *
3738 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3739 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3740 *
3741 * Returns a string (either a new string or the given +out_string+)
3742 * containing the bytes read.
3743 * The encoding of the string depends on both +maxLen+ and +out_string+:
3744 *
3745 * - +maxlen+ is +nil+: uses internal encoding of +self+
3746 * (regardless of whether +out_string+ was given).
3747 * - +maxlen+ not +nil+:
3748 *
3749 * - +out_string+ given: encoding of +out_string+ not modified.
3750 * - +out_string+ not given: ASCII-8BIT is used.
3751 *
3752 * <b>Without Argument +out_string+</b>
3753 *
3754 * When argument +out_string+ is omitted,
3755 * the returned value is a new string:
3756 *
3757 * f = File.new('t.txt')
3758 * f.read
3759 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3760 * f.rewind
3761 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3762 * f.read(30) # => "rth line\r\nFifth line\r\n"
3763 * f.read(30) # => nil
3764 * f.close
3765 *
3766 * If +maxlen+ is zero, returns an empty string.
3767 *
3768 * <b> With Argument +out_string+</b>
3769 *
3770 * When argument +out_string+ is given,
3771 * the returned value is +out_string+, whose content is replaced:
3772 *
3773 * f = File.new('t.txt')
3774 * s = 'foo' # => "foo"
3775 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3776 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3777 * f.rewind
3778 * s = 'bar'
3779 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3780 * s # => "First line\r\nSecond line\r\n\r\nFou"
3781 * s = 'baz'
3782 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3783 * s # => "rth line\r\nFifth line\r\n"
3784 * s = 'bat'
3785 * f.read(30, s) # => nil
3786 * s # => ""
3787 * f.close
3788 *
3789 * Note that this method behaves like the fread() function in C.
3790 * This means it retries to invoke read(2) system calls to read data
3791 * with the specified maxlen (or until EOF).
3792 *
3793 * This behavior is preserved even if the stream is in non-blocking mode.
3794 * (This method is non-blocking-flag insensitive as other methods.)
3795 *
3796 * If you need the behavior like a single read(2) system call,
3797 * consider #readpartial, #read_nonblock, and #sysread.
3798 *
3799 * Related: IO#write.
3800 */
3801
3802static VALUE
3803io_read(int argc, VALUE *argv, VALUE io)
3804{
3805 rb_io_t *fptr;
3806 long n, len;
3807 VALUE length, str;
3808 int shrinkable;
3809#if RUBY_CRLF_ENVIRONMENT
3810 int previous_mode;
3811#endif
3812
3813 rb_scan_args(argc, argv, "02", &length, &str);
3814
3815 if (NIL_P(length)) {
3816 GetOpenFile(io, fptr);
3818 return read_all(fptr, remain_size(fptr), str);
3819 }
3820 len = NUM2LONG(length);
3821 if (len < 0) {
3822 rb_raise(rb_eArgError, "negative length %ld given", len);
3823 }
3824
3825 shrinkable = io_setstrbuf(&str,len);
3826
3827 GetOpenFile(io, fptr);
3829 if (len == 0) {
3830 io_set_read_length(str, 0, shrinkable);
3831 return str;
3832 }
3833
3834 READ_CHECK(fptr);
3835#if RUBY_CRLF_ENVIRONMENT
3836 previous_mode = set_binary_mode_with_seek_cur(fptr);
3837#endif
3838 n = io_fread(str, 0, len, fptr);
3839 io_set_read_length(str, n, shrinkable);
3840#if RUBY_CRLF_ENVIRONMENT
3841 if (previous_mode == O_TEXT) {
3842 setmode(fptr->fd, O_TEXT);
3843 }
3844#endif
3845 if (n == 0) return Qnil;
3846
3847 return str;
3848}
3849
3850static void
3851rscheck(const char *rsptr, long rslen, VALUE rs)
3852{
3853 if (!rs) return;
3854 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3855 rb_raise(rb_eRuntimeError, "rs modified");
3856}
3857
3858static const char *
3859search_delim(const char *p, long len, int delim, rb_encoding *enc)
3860{
3861 if (rb_enc_mbminlen(enc) == 1) {
3862 p = memchr(p, delim, len);
3863 if (p) return p + 1;
3864 }
3865 else {
3866 const char *end = p + len;
3867 while (p < end) {
3868 int r = rb_enc_precise_mbclen(p, end, enc);
3869 if (!MBCLEN_CHARFOUND_P(r)) {
3870 p += rb_enc_mbminlen(enc);
3871 continue;
3872 }
3873 int n = MBCLEN_CHARFOUND_LEN(r);
3874 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3875 return p + n;
3876 }
3877 p += n;
3878 }
3879 }
3880 return NULL;
3881}
3882
3883static int
3884appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3885{
3886 VALUE str = *strp;
3887 long limit = *lp;
3888
3889 if (NEED_READCONV(fptr)) {
3890 SET_BINARY_MODE(fptr);
3891 make_readconv(fptr, 0);
3892 do {
3893 const char *p, *e;
3894 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3895 if (searchlen) {
3896 p = READ_CHAR_PENDING_PTR(fptr);
3897 if (0 < limit && limit < searchlen)
3898 searchlen = (int)limit;
3899 e = search_delim(p, searchlen, delim, enc);
3900 if (e) {
3901 int len = (int)(e-p);
3902 if (NIL_P(str))
3903 *strp = str = rb_str_new(p, len);
3904 else
3905 rb_str_buf_cat(str, p, len);
3906 fptr->cbuf.off += len;
3907 fptr->cbuf.len -= len;
3908 limit -= len;
3909 *lp = limit;
3910 return delim;
3911 }
3912
3913 if (NIL_P(str))
3914 *strp = str = rb_str_new(p, searchlen);
3915 else
3916 rb_str_buf_cat(str, p, searchlen);
3917 fptr->cbuf.off += searchlen;
3918 fptr->cbuf.len -= searchlen;
3919 limit -= searchlen;
3920
3921 if (limit == 0) {
3922 *lp = limit;
3923 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3924 }
3925 }
3926 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3927 clear_readconv(fptr);
3928 *lp = limit;
3929 return EOF;
3930 }
3931
3932 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3933 do {
3934 long pending = READ_DATA_PENDING_COUNT(fptr);
3935 if (pending > 0) {
3936 const char *p = READ_DATA_PENDING_PTR(fptr);
3937 const char *e;
3938 long last;
3939
3940 if (limit > 0 && pending > limit) pending = limit;
3941 e = search_delim(p, pending, delim, enc);
3942 if (e) pending = e - p;
3943 if (!NIL_P(str)) {
3944 last = RSTRING_LEN(str);
3945 rb_str_resize(str, last + pending);
3946 }
3947 else {
3948 last = 0;
3949 *strp = str = rb_str_buf_new(pending);
3950 rb_str_set_len(str, pending);
3951 }
3952 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3953 limit -= pending;
3954 *lp = limit;
3955 if (e) return delim;
3956 if (limit == 0)
3957 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3958 }
3959 READ_CHECK(fptr);
3960 } while (io_fillbuf(fptr) >= 0);
3961 *lp = limit;
3962 return EOF;
3963}
3964
3965static inline int
3966swallow(rb_io_t *fptr, int term)
3967{
3968 if (NEED_READCONV(fptr)) {
3969 rb_encoding *enc = io_read_encoding(fptr);
3970 int needconv = rb_enc_mbminlen(enc) != 1;
3971 SET_BINARY_MODE(fptr);
3972 make_readconv(fptr, 0);
3973 do {
3974 size_t cnt;
3975 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3976 const char *p = READ_CHAR_PENDING_PTR(fptr);
3977 int i;
3978 if (!needconv) {
3979 if (*p != term) return TRUE;
3980 i = (int)cnt;
3981 while (--i && *++p == term);
3982 }
3983 else {
3984 const char *e = p + cnt;
3985 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3986 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3987 i = (int)(e - p);
3988 }
3989 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3990 }
3991 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3992 return FALSE;
3993 }
3994
3995 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3996 do {
3997 size_t cnt;
3998 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3999 char buf[1024];
4000 const char *p = READ_DATA_PENDING_PTR(fptr);
4001 int i;
4002 if (cnt > sizeof buf) cnt = sizeof buf;
4003 if (*p != term) return TRUE;
4004 i = (int)cnt;
4005 while (--i && *++p == term);
4006 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4007 rb_sys_fail_path(fptr->pathv);
4008 }
4009 READ_CHECK(fptr);
4010 } while (io_fillbuf(fptr) == 0);
4011 return FALSE;
4012}
4013
4014static VALUE
4015rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4016{
4017 VALUE str = Qnil;
4018 int len = 0;
4019 long pos = 0;
4020 int cr = 0;
4021
4022 do {
4023 int pending = READ_DATA_PENDING_COUNT(fptr);
4024
4025 if (pending > 0) {
4026 const char *p = READ_DATA_PENDING_PTR(fptr);
4027 const char *e;
4028 int chomplen = 0;
4029
4030 e = memchr(p, '\n', pending);
4031 if (e) {
4032 pending = (int)(e - p + 1);
4033 if (chomp) {
4034 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4035 }
4036 }
4037 if (NIL_P(str)) {
4038 str = rb_str_new(p, pending - chomplen);
4039 fptr->rbuf.off += pending;
4040 fptr->rbuf.len -= pending;
4041 }
4042 else {
4043 rb_str_resize(str, len + pending - chomplen);
4044 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4045 fptr->rbuf.off += chomplen;
4046 fptr->rbuf.len -= chomplen;
4047 if (pending == 1 && chomplen == 1 && len > 0) {
4048 if (RSTRING_PTR(str)[len-1] == '\r') {
4049 rb_str_resize(str, --len);
4050 break;
4051 }
4052 }
4053 }
4054 len += pending - chomplen;
4055 if (cr != ENC_CODERANGE_BROKEN)
4056 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4057 if (e) break;
4058 }
4059 READ_CHECK(fptr);
4060 } while (io_fillbuf(fptr) >= 0);
4061 if (NIL_P(str)) return Qnil;
4062
4063 str = io_enc_str(str, fptr);
4064 ENC_CODERANGE_SET(str, cr);
4065 fptr->lineno++;
4066
4067 return str;
4068}
4069
4071 VALUE io;
4072 VALUE rs;
4073 long limit;
4074 unsigned int chomp: 1;
4075};
4076
4077static void
4078extract_getline_opts(VALUE opts, struct getline_arg *args)
4079{
4080 int chomp = FALSE;
4081 if (!NIL_P(opts)) {
4082 static ID kwds[1];
4083 VALUE vchomp;
4084 if (!kwds[0]) {
4085 kwds[0] = rb_intern_const("chomp");
4086 }
4087 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4088 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4089 }
4090 args->chomp = chomp;
4091}
4092
4093static void
4094extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4095{
4096 VALUE rs = rb_rs, lim = Qnil;
4097
4098 if (argc == 1) {
4099 VALUE tmp = Qnil;
4100
4101 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4102 rs = tmp;
4103 }
4104 else {
4105 lim = argv[0];
4106 }
4107 }
4108 else if (2 <= argc) {
4109 rs = argv[0], lim = argv[1];
4110 if (!NIL_P(rs))
4111 StringValue(rs);
4112 }
4113 args->rs = rs;
4114 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4115}
4116
4117static void
4118check_getline_args(VALUE *rsp, long *limit, VALUE io)
4119{
4120 rb_io_t *fptr;
4121 VALUE rs = *rsp;
4122
4123 if (!NIL_P(rs)) {
4124 rb_encoding *enc_rs, *enc_io;
4125
4126 GetOpenFile(io, fptr);
4127 enc_rs = rb_enc_get(rs);
4128 enc_io = io_read_encoding(fptr);
4129 if (enc_io != enc_rs &&
4130 (!is_ascii_string(rs) ||
4131 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4132 if (rs == rb_default_rs) {
4133 rs = rb_enc_str_new(0, 0, enc_io);
4134 rb_str_buf_cat_ascii(rs, "\n");
4135 *rsp = rs;
4136 }
4137 else {
4138 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4139 rb_enc_name(enc_io),
4140 rb_enc_name(enc_rs));
4141 }
4142 }
4143 }
4144}
4145
4146static void
4147prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4148{
4149 VALUE opts;
4150 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4151 extract_getline_args(argc, argv, args);
4152 extract_getline_opts(opts, args);
4153 check_getline_args(&args->rs, &args->limit, io);
4154}
4155
4156static VALUE
4157rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4158{
4159 VALUE str = Qnil;
4160 int nolimit = 0;
4161 rb_encoding *enc;
4162
4164 if (NIL_P(rs) && limit < 0) {
4165 str = read_all(fptr, 0, Qnil);
4166 if (RSTRING_LEN(str) == 0) return Qnil;
4167 }
4168 else if (limit == 0) {
4169 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4170 }
4171 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4172 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4173 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4174 return rb_io_getline_fast(fptr, enc, chomp);
4175 }
4176 else {
4177 int c, newline = -1;
4178 const char *rsptr = 0;
4179 long rslen = 0;
4180 int rspara = 0;
4181 int extra_limit = 16;
4182 int chomp_cr = chomp;
4183
4184 SET_BINARY_MODE(fptr);
4185 enc = io_read_encoding(fptr);
4186
4187 if (!NIL_P(rs)) {
4188 rslen = RSTRING_LEN(rs);
4189 if (rslen == 0) {
4190 rsptr = "\n\n";
4191 rslen = 2;
4192 rspara = 1;
4193 swallow(fptr, '\n');
4194 rs = 0;
4195 if (!rb_enc_asciicompat(enc)) {
4196 rs = rb_usascii_str_new(rsptr, rslen);
4197 rs = rb_str_conv_enc(rs, 0, enc);
4198 OBJ_FREEZE(rs);
4199 rsptr = RSTRING_PTR(rs);
4200 rslen = RSTRING_LEN(rs);
4201 }
4202 newline = '\n';
4203 }
4204 else if (rb_enc_mbminlen(enc) == 1) {
4205 rsptr = RSTRING_PTR(rs);
4206 newline = (unsigned char)rsptr[rslen - 1];
4207 }
4208 else {
4209 rs = rb_str_conv_enc(rs, 0, enc);
4210 rsptr = RSTRING_PTR(rs);
4211 const char *e = rsptr + rslen;
4212 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4213 int n;
4214 newline = rb_enc_codepoint_len(last, e, &n, enc);
4215 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4216 }
4217 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4218 }
4219
4220 /* MS - Optimization */
4221 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4222 const char *s, *p, *pp, *e;
4223
4224 if (c == newline) {
4225 if (RSTRING_LEN(str) < rslen) continue;
4226 s = RSTRING_PTR(str);
4227 e = RSTRING_END(str);
4228 p = e - rslen;
4229 if (!at_char_boundary(s, p, e, enc)) continue;
4230 if (!rspara) rscheck(rsptr, rslen, rs);
4231 if (memcmp(p, rsptr, rslen) == 0) {
4232 if (chomp) {
4233 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4234 rb_str_set_len(str, p - s);
4235 }
4236 break;
4237 }
4238 }
4239 if (limit == 0) {
4240 s = RSTRING_PTR(str);
4241 p = RSTRING_END(str);
4242 pp = rb_enc_prev_char(s, p, p, enc);
4243 if (extra_limit && pp &&
4244 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4245 /* relax the limit while incomplete character.
4246 * extra_limit limits the relax length */
4247 limit = 1;
4248 extra_limit--;
4249 }
4250 else {
4251 nolimit = 1;
4252 break;
4253 }
4254 }
4255 }
4256
4257 if (rspara && c != EOF)
4258 swallow(fptr, '\n');
4259 if (!NIL_P(str))
4260 str = io_enc_str(str, fptr);
4261 }
4262
4263 if (!NIL_P(str) && !nolimit) {
4264 fptr->lineno++;
4265 }
4266
4267 return str;
4268}
4269
4270static VALUE
4271rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4272{
4273 rb_io_t *fptr;
4274 int old_lineno, new_lineno;
4275 VALUE str;
4276
4277 GetOpenFile(io, fptr);
4278 old_lineno = fptr->lineno;
4279 str = rb_io_getline_0(rs, limit, chomp, fptr);
4280 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4281 if (io == ARGF.current_file) {
4282 ARGF.lineno += new_lineno - old_lineno;
4283 ARGF.last_lineno = ARGF.lineno;
4284 }
4285 else {
4286 ARGF.last_lineno = new_lineno;
4287 }
4288 }
4289
4290 return str;
4291}
4292
4293static VALUE
4294rb_io_getline(int argc, VALUE *argv, VALUE io)
4295{
4296 struct getline_arg args;
4297
4298 prepare_getline_args(argc, argv, &args, io);
4299 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4300}
4301
4302VALUE
4304{
4305 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4306}
4307
4308VALUE
4309rb_io_gets_internal(VALUE io)
4310{
4311 rb_io_t *fptr;
4312 GetOpenFile(io, fptr);
4313 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4314}
4315
4316/*
4317 * call-seq:
4318 * gets(sep = $/, chomp: false) -> string or nil
4319 * gets(limit, chomp: false) -> string or nil
4320 * gets(sep, limit, chomp: false) -> string or nil
4321 *
4322 * Reads and returns a line from the stream;
4323 * assigns the return value to <tt>$_</tt>.
4324 * See {Line IO}[rdoc-ref:IO@Line+IO].
4325 *
4326 * With no arguments given, returns the next line
4327 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4328 *
4329 * f = File.open('t.txt')
4330 * f.gets # => "First line\n"
4331 * $_ # => "First line\n"
4332 * f.gets # => "\n"
4333 * f.gets # => "Fourth line\n"
4334 * f.gets # => "Fifth line\n"
4335 * f.gets # => nil
4336 * f.close
4337 *
4338 * With only string argument +sep+ given,
4339 * returns the next line as determined by line separator +sep+,
4340 * or +nil+ if none;
4341 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4342 *
4343 * f = File.new('t.txt')
4344 * f.gets('l') # => "First l"
4345 * f.gets('li') # => "ine\nSecond li"
4346 * f.gets('lin') # => "ne\n\nFourth lin"
4347 * f.gets # => "e\n"
4348 * f.close
4349 *
4350 * The two special values for +sep+ are honored:
4351 *
4352 * f = File.new('t.txt')
4353 * # Get all.
4354 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4355 * f.rewind
4356 * # Get paragraph (up to two line separators).
4357 * f.gets('') # => "First line\nSecond line\n\n"
4358 * f.close
4359 *
4360 * With only integer argument +limit+ given,
4361 * limits the number of bytes in the line;
4362 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4363 *
4364 * # No more than one line.
4365 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4366 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4367 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4368 *
4369 * With arguments +sep+ and +limit+ given,
4370 * combines the two behaviors
4371 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4372 *
4373 * Optional keyword argument +chomp+ specifies whether line separators
4374 * are to be omitted:
4375 *
4376 * f = File.open('t.txt')
4377 * # Chomp the lines.
4378 * f.gets(chomp: true) # => "First line"
4379 * f.gets(chomp: true) # => "Second line"
4380 * f.gets(chomp: true) # => ""
4381 * f.gets(chomp: true) # => "Fourth line"
4382 * f.gets(chomp: true) # => "Fifth line"
4383 * f.gets(chomp: true) # => nil
4384 * f.close
4385 *
4386 */
4387
4388static VALUE
4389rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4390{
4391 VALUE str;
4392
4393 str = rb_io_getline(argc, argv, io);
4394 rb_lastline_set(str);
4395
4396 return str;
4397}
4398
4399/*
4400 * call-seq:
4401 * lineno -> integer
4402 *
4403 * Returns the current line number for the stream;
4404 * see {Line Number}[rdoc-ref:IO@Line+Number].
4405 *
4406 */
4407
4408static VALUE
4409rb_io_lineno(VALUE io)
4410{
4411 rb_io_t *fptr;
4412
4413 GetOpenFile(io, fptr);
4415 return INT2NUM(fptr->lineno);
4416}
4417
4418/*
4419 * call-seq:
4420 * lineno = integer -> integer
4421 *
4422 * Sets and returns the line number for the stream;
4423 * see {Line Number}[rdoc-ref:IO@Line+Number].
4424 *
4425 */
4426
4427static VALUE
4428rb_io_set_lineno(VALUE io, VALUE lineno)
4429{
4430 rb_io_t *fptr;
4431
4432 GetOpenFile(io, fptr);
4434 fptr->lineno = NUM2INT(lineno);
4435 return lineno;
4436}
4437
4438/* :nodoc: */
4439static VALUE
4440io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4441{
4442 long limit = -1;
4443 if (NIL_P(lim)) {
4444 VALUE tmp = Qnil;
4445 // If sep is specified, but it's not a string and not nil, then assume
4446 // it's the limit (it should be an integer)
4447 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4448 // If the user has specified a non-nil / non-string value
4449 // for the separator, we assume it's the limit and set the
4450 // separator to default: rb_rs.
4451 lim = sep;
4452 limit = NUM2LONG(lim);
4453 sep = rb_rs;
4454 }
4455 else {
4456 sep = tmp;
4457 }
4458 }
4459 else {
4460 if (!NIL_P(sep)) StringValue(sep);
4461 limit = NUM2LONG(lim);
4462 }
4463
4464 check_getline_args(&sep, &limit, io);
4465
4466 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4467 rb_lastline_set_up(line, 1);
4468
4469 if (NIL_P(line)) {
4470 rb_eof_error();
4471 }
4472 return line;
4473}
4474
4475static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4476
4477/*
4478 * call-seq:
4479 * readlines(sep = $/, chomp: false) -> array
4480 * readlines(limit, chomp: false) -> array
4481 * readlines(sep, limit, chomp: false) -> array
4482 *
4483 * Reads and returns all remaining line from the stream;
4484 * does not modify <tt>$_</tt>.
4485 * See {Line IO}[rdoc-ref:IO@Line+IO].
4486 *
4487 * With no arguments given, returns lines
4488 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4489 *
4490 * f = File.new('t.txt')
4491 * f.readlines
4492 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4493 * f.readlines # => []
4494 * f.close
4495 *
4496 * With only string argument +sep+ given,
4497 * returns lines as determined by line separator +sep+,
4498 * or +nil+ if none;
4499 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4500 *
4501 * f = File.new('t.txt')
4502 * f.readlines('li')
4503 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4504 * f.close
4505 *
4506 * The two special values for +sep+ are honored:
4507 *
4508 * f = File.new('t.txt')
4509 * # Get all into one string.
4510 * f.readlines(nil)
4511 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4512 * # Get paragraphs (up to two line separators).
4513 * f.rewind
4514 * f.readlines('')
4515 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4516 * f.close
4517 *
4518 * With only integer argument +limit+ given,
4519 * limits the number of bytes in each line;
4520 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4521 *
4522 * f = File.new('t.txt')
4523 * f.readlines(8)
4524 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4525 * f.close
4526 *
4527 * With arguments +sep+ and +limit+ given,
4528 * combines the two behaviors
4529 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4530 *
4531 * Optional keyword argument +chomp+ specifies whether line separators
4532 * are to be omitted:
4533 *
4534 * f = File.new('t.txt')
4535 * f.readlines(chomp: true)
4536 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4537 * f.close
4538 *
4539 */
4540
4541static VALUE
4542rb_io_readlines(int argc, VALUE *argv, VALUE io)
4543{
4544 struct getline_arg args;
4545
4546 prepare_getline_args(argc, argv, &args, io);
4547 return io_readlines(&args, io);
4548}
4549
4550static VALUE
4551io_readlines(const struct getline_arg *arg, VALUE io)
4552{
4553 VALUE line, ary;
4554
4555 if (arg->limit == 0)
4556 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4557 ary = rb_ary_new();
4558 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4559 rb_ary_push(ary, line);
4560 }
4561 return ary;
4562}
4563
4564/*
4565 * call-seq:
4566 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4567 * each_line(limit, chomp: false) {|line| ... } -> self
4568 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4569 * each_line -> enumerator
4570 *
4571 * Calls the block with each remaining line read from the stream;
4572 * returns +self+.
4573 * Does nothing if already at end-of-stream;
4574 * See {Line IO}[rdoc-ref:IO@Line+IO].
4575 *
4576 * With no arguments given, reads lines
4577 * as determined by line separator <tt>$/</tt>:
4578 *
4579 * f = File.new('t.txt')
4580 * f.each_line {|line| p line }
4581 * f.each_line {|line| fail 'Cannot happen' }
4582 * f.close
4583 *
4584 * Output:
4585 *
4586 * "First line\n"
4587 * "Second line\n"
4588 * "\n"
4589 * "Fourth line\n"
4590 * "Fifth line\n"
4591 *
4592 * With only string argument +sep+ given,
4593 * reads lines as determined by line separator +sep+;
4594 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4595 *
4596 * f = File.new('t.txt')
4597 * f.each_line('li') {|line| p line }
4598 * f.close
4599 *
4600 * Output:
4601 *
4602 * "First li"
4603 * "ne\nSecond li"
4604 * "ne\n\nFourth li"
4605 * "ne\nFifth li"
4606 * "ne\n"
4607 *
4608 * The two special values for +sep+ are honored:
4609 *
4610 * f = File.new('t.txt')
4611 * # Get all into one string.
4612 * f.each_line(nil) {|line| p line }
4613 * f.close
4614 *
4615 * Output:
4616 *
4617 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4618 *
4619 * f.rewind
4620 * # Get paragraphs (up to two line separators).
4621 * f.each_line('') {|line| p line }
4622 *
4623 * Output:
4624 *
4625 * "First line\nSecond line\n\n"
4626 * "Fourth line\nFifth line\n"
4627 *
4628 * With only integer argument +limit+ given,
4629 * limits the number of bytes in each line;
4630 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4631 *
4632 * f = File.new('t.txt')
4633 * f.each_line(8) {|line| p line }
4634 * f.close
4635 *
4636 * Output:
4637 *
4638 * "First li"
4639 * "ne\n"
4640 * "Second l"
4641 * "ine\n"
4642 * "\n"
4643 * "Fourth l"
4644 * "ine\n"
4645 * "Fifth li"
4646 * "ne\n"
4647 *
4648 * With arguments +sep+ and +limit+ given,
4649 * combines the two behaviors
4650 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4651 *
4652 * Optional keyword argument +chomp+ specifies whether line separators
4653 * are to be omitted:
4654 *
4655 * f = File.new('t.txt')
4656 * f.each_line(chomp: true) {|line| p line }
4657 * f.close
4658 *
4659 * Output:
4660 *
4661 * "First line"
4662 * "Second line"
4663 * ""
4664 * "Fourth line"
4665 * "Fifth line"
4666 *
4667 * Returns an Enumerator if no block is given.
4668 */
4669
4670static VALUE
4671rb_io_each_line(int argc, VALUE *argv, VALUE io)
4672{
4673 VALUE str;
4674 struct getline_arg args;
4675
4676 RETURN_ENUMERATOR(io, argc, argv);
4677 prepare_getline_args(argc, argv, &args, io);
4678 if (args.limit == 0)
4679 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4680 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4681 rb_yield(str);
4682 }
4683 return io;
4684}
4685
4686/*
4687 * call-seq:
4688 * each_byte {|byte| ... } -> self
4689 * each_byte -> enumerator
4690 *
4691 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4692 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4693 *
4694 * f = File.new('t.rus')
4695 * a = []
4696 * f.each_byte {|b| a << b }
4697 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4698 * f.close
4699 *
4700 * Returns an Enumerator if no block is given.
4701 *
4702 * Related: IO#each_char, IO#each_codepoint.
4703 *
4704 */
4705
4706static VALUE
4707rb_io_each_byte(VALUE io)
4708{
4709 rb_io_t *fptr;
4710
4711 RETURN_ENUMERATOR(io, 0, 0);
4712 GetOpenFile(io, fptr);
4713
4714 do {
4715 while (fptr->rbuf.len > 0) {
4716 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4717 fptr->rbuf.len--;
4718 rb_yield(INT2FIX(*p & 0xff));
4720 errno = 0;
4721 }
4722 READ_CHECK(fptr);
4723 } while (io_fillbuf(fptr) >= 0);
4724 return io;
4725}
4726
4727static VALUE
4728io_getc(rb_io_t *fptr, rb_encoding *enc)
4729{
4730 int r, n, cr = 0;
4731 VALUE str;
4732
4733 if (NEED_READCONV(fptr)) {
4734 rb_encoding *read_enc = io_read_encoding(fptr);
4735
4736 str = Qnil;
4737 SET_BINARY_MODE(fptr);
4738 make_readconv(fptr, 0);
4739
4740 while (1) {
4741 if (fptr->cbuf.len) {
4742 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4743 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4744 read_enc);
4745 if (!MBCLEN_NEEDMORE_P(r))
4746 break;
4747 if (fptr->cbuf.len == fptr->cbuf.capa) {
4748 rb_raise(rb_eIOError, "too long character");
4749 }
4750 }
4751
4752 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4753 if (fptr->cbuf.len == 0) {
4754 clear_readconv(fptr);
4755 return Qnil;
4756 }
4757 /* return an unit of an incomplete character just before EOF */
4758 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4759 fptr->cbuf.off += 1;
4760 fptr->cbuf.len -= 1;
4761 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4763 return str;
4764 }
4765 }
4766 if (MBCLEN_INVALID_P(r)) {
4767 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4768 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4769 read_enc);
4770 io_shift_cbuf(fptr, r, &str);
4772 }
4773 else {
4774 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4776 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4777 ISASCII(RSTRING_PTR(str)[0])) {
4778 cr = ENC_CODERANGE_7BIT;
4779 }
4780 }
4781 str = io_enc_str(str, fptr);
4782 ENC_CODERANGE_SET(str, cr);
4783 return str;
4784 }
4785
4786 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4787 if (io_fillbuf(fptr) < 0) {
4788 return Qnil;
4789 }
4790 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4791 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4792 fptr->rbuf.off += 1;
4793 fptr->rbuf.len -= 1;
4794 cr = ENC_CODERANGE_7BIT;
4795 }
4796 else {
4797 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4798 if (MBCLEN_CHARFOUND_P(r) &&
4799 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4800 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4801 fptr->rbuf.off += n;
4802 fptr->rbuf.len -= n;
4804 }
4805 else if (MBCLEN_NEEDMORE_P(r)) {
4806 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4807 fptr->rbuf.len = 0;
4808 getc_needmore:
4809 if (io_fillbuf(fptr) != -1) {
4810 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4811 fptr->rbuf.off++;
4812 fptr->rbuf.len--;
4813 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4814 if (MBCLEN_NEEDMORE_P(r)) {
4815 goto getc_needmore;
4816 }
4817 else if (MBCLEN_CHARFOUND_P(r)) {
4819 }
4820 }
4821 }
4822 else {
4823 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4824 fptr->rbuf.off++;
4825 fptr->rbuf.len--;
4826 }
4827 }
4828 if (!cr) cr = ENC_CODERANGE_BROKEN;
4829 str = io_enc_str(str, fptr);
4830 ENC_CODERANGE_SET(str, cr);
4831 return str;
4832}
4833
4834/*
4835 * call-seq:
4836 * each_char {|c| ... } -> self
4837 * each_char -> enumerator
4838 *
4839 * Calls the given block with each character in the stream; returns +self+.
4840 * See {Character IO}[rdoc-ref:IO@Character+IO].
4841 *
4842 * f = File.new('t.rus')
4843 * a = []
4844 * f.each_char {|c| a << c.ord }
4845 * a # => [1090, 1077, 1089, 1090]
4846 * f.close
4847 *
4848 * Returns an Enumerator if no block is given.
4849 *
4850 * Related: IO#each_byte, IO#each_codepoint.
4851 *
4852 */
4853
4854static VALUE
4855rb_io_each_char(VALUE io)
4856{
4857 rb_io_t *fptr;
4858 rb_encoding *enc;
4859 VALUE c;
4860
4861 RETURN_ENUMERATOR(io, 0, 0);
4862 GetOpenFile(io, fptr);
4864
4865 enc = io_input_encoding(fptr);
4866 READ_CHECK(fptr);
4867 while (!NIL_P(c = io_getc(fptr, enc))) {
4868 rb_yield(c);
4869 }
4870 return io;
4871}
4872
4873/*
4874 * call-seq:
4875 * each_codepoint {|c| ... } -> self
4876 * each_codepoint -> enumerator
4877 *
4878 * Calls the given block with each codepoint in the stream; returns +self+:
4879 *
4880 * f = File.new('t.rus')
4881 * a = []
4882 * f.each_codepoint {|c| a << c }
4883 * a # => [1090, 1077, 1089, 1090]
4884 * f.close
4885 *
4886 * Returns an Enumerator if no block is given.
4887 *
4888 * Related: IO#each_byte, IO#each_char.
4889 *
4890 */
4891
4892static VALUE
4893rb_io_each_codepoint(VALUE io)
4894{
4895 rb_io_t *fptr;
4896 rb_encoding *enc;
4897 unsigned int c;
4898 int r, n;
4899
4900 RETURN_ENUMERATOR(io, 0, 0);
4901 GetOpenFile(io, fptr);
4903
4904 READ_CHECK(fptr);
4905 if (NEED_READCONV(fptr)) {
4906 SET_BINARY_MODE(fptr);
4907 r = 1; /* no invalid char yet */
4908 for (;;) {
4909 make_readconv(fptr, 0);
4910 for (;;) {
4911 if (fptr->cbuf.len) {
4912 if (fptr->encs.enc)
4913 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4914 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4915 fptr->encs.enc);
4916 else
4917 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4918 if (!MBCLEN_NEEDMORE_P(r))
4919 break;
4920 if (fptr->cbuf.len == fptr->cbuf.capa) {
4921 rb_raise(rb_eIOError, "too long character");
4922 }
4923 }
4924 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4925 clear_readconv(fptr);
4926 if (!MBCLEN_CHARFOUND_P(r)) {
4927 enc = fptr->encs.enc;
4928 goto invalid;
4929 }
4930 return io;
4931 }
4932 }
4933 if (MBCLEN_INVALID_P(r)) {
4934 enc = fptr->encs.enc;
4935 goto invalid;
4936 }
4937 n = MBCLEN_CHARFOUND_LEN(r);
4938 if (fptr->encs.enc) {
4939 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4940 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4941 fptr->encs.enc);
4942 }
4943 else {
4944 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4945 }
4946 fptr->cbuf.off += n;
4947 fptr->cbuf.len -= n;
4948 rb_yield(UINT2NUM(c));
4950 }
4951 }
4952 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4953 enc = io_input_encoding(fptr);
4954 while (io_fillbuf(fptr) >= 0) {
4955 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4956 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4957 if (MBCLEN_CHARFOUND_P(r) &&
4958 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4959 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4960 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4961 fptr->rbuf.off += n;
4962 fptr->rbuf.len -= n;
4963 rb_yield(UINT2NUM(c));
4964 }
4965 else if (MBCLEN_INVALID_P(r)) {
4966 goto invalid;
4967 }
4968 else if (MBCLEN_NEEDMORE_P(r)) {
4969 char cbuf[8], *p = cbuf;
4970 int more = MBCLEN_NEEDMORE_LEN(r);
4971 if (more > numberof(cbuf)) goto invalid;
4972 more += n = fptr->rbuf.len;
4973 if (more > numberof(cbuf)) goto invalid;
4974 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4975 (p += n, (more -= n) > 0)) {
4976 if (io_fillbuf(fptr) < 0) goto invalid;
4977 if ((n = fptr->rbuf.len) > more) n = more;
4978 }
4979 r = rb_enc_precise_mbclen(cbuf, p, enc);
4980 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4981 c = rb_enc_codepoint(cbuf, p, enc);
4982 rb_yield(UINT2NUM(c));
4983 }
4984 else {
4985 continue;
4986 }
4988 }
4989 return io;
4990
4991 invalid:
4992 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4994}
4995
4996/*
4997 * call-seq:
4998 * getc -> character or nil
4999 *
5000 * Reads and returns the next 1-character string from the stream;
5001 * returns +nil+ if already at end-of-stream.
5002 * See {Character IO}[rdoc-ref:IO@Character+IO].
5003 *
5004 * f = File.open('t.txt')
5005 * f.getc # => "F"
5006 * f.close
5007 * f = File.open('t.rus')
5008 * f.getc.ord # => 1090
5009 * f.close
5010 *
5011 * Related: IO#readchar (may raise EOFError).
5012 *
5013 */
5014
5015static VALUE
5016rb_io_getc(VALUE io)
5017{
5018 rb_io_t *fptr;
5019 rb_encoding *enc;
5020
5021 GetOpenFile(io, fptr);
5023
5024 enc = io_input_encoding(fptr);
5025 READ_CHECK(fptr);
5026 return io_getc(fptr, enc);
5027}
5028
5029/*
5030 * call-seq:
5031 * readchar -> string
5032 *
5033 * Reads and returns the next 1-character string from the stream;
5034 * raises EOFError if already at end-of-stream.
5035 * See {Character IO}[rdoc-ref:IO@Character+IO].
5036 *
5037 * f = File.open('t.txt')
5038 * f.readchar # => "F"
5039 * f.close
5040 * f = File.open('t.rus')
5041 * f.readchar.ord # => 1090
5042 * f.close
5043 *
5044 * Related: IO#getc (will not raise EOFError).
5045 *
5046 */
5047
5048static VALUE
5049rb_io_readchar(VALUE io)
5050{
5051 VALUE c = rb_io_getc(io);
5052
5053 if (NIL_P(c)) {
5054 rb_eof_error();
5055 }
5056 return c;
5057}
5058
5059/*
5060 * call-seq:
5061 * getbyte -> integer or nil
5062 *
5063 * Reads and returns the next byte (in range 0..255) from the stream;
5064 * returns +nil+ if already at end-of-stream.
5065 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5066 *
5067 * f = File.open('t.txt')
5068 * f.getbyte # => 70
5069 * f.close
5070 * f = File.open('t.rus')
5071 * f.getbyte # => 209
5072 * f.close
5073 *
5074 * Related: IO#readbyte (may raise EOFError).
5075 */
5076
5077VALUE
5079{
5080 rb_io_t *fptr;
5081 int c;
5082
5083 GetOpenFile(io, fptr);
5085 READ_CHECK(fptr);
5086 VALUE r_stdout = rb_ractor_stdout();
5087 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5088 rb_io_t *ofp;
5089 GetOpenFile(r_stdout, ofp);
5090 if (ofp->mode & FMODE_TTY) {
5091 rb_io_flush(r_stdout);
5092 }
5093 }
5094 if (io_fillbuf(fptr) < 0) {
5095 return Qnil;
5096 }
5097 fptr->rbuf.off++;
5098 fptr->rbuf.len--;
5099 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5100 return INT2FIX(c & 0xff);
5101}
5102
5103/*
5104 * call-seq:
5105 * readbyte -> integer
5106 *
5107 * Reads and returns the next byte (in range 0..255) from the stream;
5108 * raises EOFError if already at end-of-stream.
5109 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5110 *
5111 * f = File.open('t.txt')
5112 * f.readbyte # => 70
5113 * f.close
5114 * f = File.open('t.rus')
5115 * f.readbyte # => 209
5116 * f.close
5117 *
5118 * Related: IO#getbyte (will not raise EOFError).
5119 *
5120 */
5121
5122static VALUE
5123rb_io_readbyte(VALUE io)
5124{
5125 VALUE c = rb_io_getbyte(io);
5126
5127 if (NIL_P(c)) {
5128 rb_eof_error();
5129 }
5130 return c;
5131}
5132
5133/*
5134 * call-seq:
5135 * ungetbyte(integer) -> nil
5136 * ungetbyte(string) -> nil
5137 *
5138 * Pushes back ("unshifts") the given data onto the stream's buffer,
5139 * placing the data so that it is next to be read; returns +nil+.
5140 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5141 *
5142 * Note that:
5143 *
5144 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5145 * - Calling #rewind on the stream discards the pushed-back data.
5146 *
5147 * When argument +integer+ is given, uses only its low-order byte:
5148 *
5149 * File.write('t.tmp', '012')
5150 * f = File.open('t.tmp')
5151 * f.ungetbyte(0x41) # => nil
5152 * f.read # => "A012"
5153 * f.rewind
5154 * f.ungetbyte(0x4243) # => nil
5155 * f.read # => "C012"
5156 * f.close
5157 *
5158 * When argument +string+ is given, uses all bytes:
5159 *
5160 * File.write('t.tmp', '012')
5161 * f = File.open('t.tmp')
5162 * f.ungetbyte('A') # => nil
5163 * f.read # => "A012"
5164 * f.rewind
5165 * f.ungetbyte('BCDE') # => nil
5166 * f.read # => "BCDE012"
5167 * f.close
5168 *
5169 */
5170
5171VALUE
5173{
5174 rb_io_t *fptr;
5175
5176 GetOpenFile(io, fptr);
5178 switch (TYPE(b)) {
5179 case T_NIL:
5180 return Qnil;
5181 case T_FIXNUM:
5182 case T_BIGNUM: ;
5183 VALUE v = rb_int_modulo(b, INT2FIX(256));
5184 unsigned char c = NUM2INT(v) & 0xFF;
5185 b = rb_str_new((const char *)&c, 1);
5186 break;
5187 default:
5188 StringValue(b);
5189 }
5190 io_ungetbyte(b, fptr);
5191 return Qnil;
5192}
5193
5194/*
5195 * call-seq:
5196 * ungetc(integer) -> nil
5197 * ungetc(string) -> nil
5198 *
5199 * Pushes back ("unshifts") the given data onto the stream's buffer,
5200 * placing the data so that it is next to be read; returns +nil+.
5201 * See {Character IO}[rdoc-ref:IO@Character+IO].
5202 *
5203 * Note that:
5204 *
5205 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5206 * - Calling #rewind on the stream discards the pushed-back data.
5207 *
5208 * When argument +integer+ is given, interprets the integer as a character:
5209 *
5210 * File.write('t.tmp', '012')
5211 * f = File.open('t.tmp')
5212 * f.ungetc(0x41) # => nil
5213 * f.read # => "A012"
5214 * f.rewind
5215 * f.ungetc(0x0442) # => nil
5216 * f.getc.ord # => 1090
5217 * f.close
5218 *
5219 * When argument +string+ is given, uses all characters:
5220 *
5221 * File.write('t.tmp', '012')
5222 * f = File.open('t.tmp')
5223 * f.ungetc('A') # => nil
5224 * f.read # => "A012"
5225 * f.rewind
5226 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5227 * f.getc.ord # => 1090
5228 * f.getc.ord # => 1077
5229 * f.getc.ord # => 1089
5230 * f.getc.ord # => 1090
5231 * f.close
5232 *
5233 */
5234
5235VALUE
5237{
5238 rb_io_t *fptr;
5239 long len;
5240
5241 GetOpenFile(io, fptr);
5243 if (FIXNUM_P(c)) {
5244 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5245 }
5246 else if (RB_BIGNUM_TYPE_P(c)) {
5247 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5248 }
5249 else {
5250 StringValue(c);
5251 }
5252 if (NEED_READCONV(fptr)) {
5253 SET_BINARY_MODE(fptr);
5254 len = RSTRING_LEN(c);
5255#if SIZEOF_LONG > SIZEOF_INT
5256 if (len > INT_MAX)
5257 rb_raise(rb_eIOError, "ungetc failed");
5258#endif
5259 make_readconv(fptr, (int)len);
5260 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5261 rb_raise(rb_eIOError, "ungetc failed");
5262 if (fptr->cbuf.off < len) {
5263 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5264 fptr->cbuf.ptr+fptr->cbuf.off,
5265 char, fptr->cbuf.len);
5266 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5267 }
5268 fptr->cbuf.off -= (int)len;
5269 fptr->cbuf.len += (int)len;
5270 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5271 }
5272 else {
5273 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5274 io_ungetbyte(c, fptr);
5275 }
5276 return Qnil;
5277}
5278
5279/*
5280 * call-seq:
5281 * isatty -> true or false
5282 *
5283 * Returns +true+ if the stream is associated with a terminal device (tty),
5284 * +false+ otherwise:
5285 *
5286 * f = File.new('t.txt').isatty #=> false
5287 * f.close
5288 * f = File.new('/dev/tty').isatty #=> true
5289 * f.close
5290 *
5291 */
5292
5293static VALUE
5294rb_io_isatty(VALUE io)
5295{
5296 rb_io_t *fptr;
5297
5298 GetOpenFile(io, fptr);
5299 return RBOOL(isatty(fptr->fd) != 0);
5300}
5301
5302#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5303/*
5304 * call-seq:
5305 * close_on_exec? -> true or false
5306 *
5307 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5308 *
5309 * f = File.open('t.txt')
5310 * f.close_on_exec? # => true
5311 * f.close_on_exec = false
5312 * f.close_on_exec? # => false
5313 * f.close
5314 *
5315 */
5316
5317static VALUE
5318rb_io_close_on_exec_p(VALUE io)
5319{
5320 rb_io_t *fptr;
5321 VALUE write_io;
5322 int fd, ret;
5323
5324 write_io = GetWriteIO(io);
5325 if (io != write_io) {
5326 GetOpenFile(write_io, fptr);
5327 if (fptr && 0 <= (fd = fptr->fd)) {
5328 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5329 if (!(ret & FD_CLOEXEC)) return Qfalse;
5330 }
5331 }
5332
5333 GetOpenFile(io, fptr);
5334 if (fptr && 0 <= (fd = fptr->fd)) {
5335 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5336 if (!(ret & FD_CLOEXEC)) return Qfalse;
5337 }
5338 return Qtrue;
5339}
5340#else
5341#define rb_io_close_on_exec_p rb_f_notimplement
5342#endif
5343
5344#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5345/*
5346 * call-seq:
5347 * self.close_on_exec = bool -> true or false
5348 *
5349 * Sets a close-on-exec flag.
5350 *
5351 * f = File.open(File::NULL)
5352 * f.close_on_exec = true
5353 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5354 * f.closed? #=> false
5355 *
5356 * Ruby sets close-on-exec flags of all file descriptors by default
5357 * since Ruby 2.0.0.
5358 * So you don't need to set by yourself.
5359 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5360 * if another thread use fork() and exec() (via system() method for example).
5361 * If you really needs file descriptor inheritance to child process,
5362 * use spawn()'s argument such as fd=>fd.
5363 */
5364
5365static VALUE
5366rb_io_set_close_on_exec(VALUE io, VALUE arg)
5367{
5368 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5369 rb_io_t *fptr;
5370 VALUE write_io;
5371 int fd, ret;
5372
5373 write_io = GetWriteIO(io);
5374 if (io != write_io) {
5375 GetOpenFile(write_io, fptr);
5376 if (fptr && 0 <= (fd = fptr->fd)) {
5377 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5378 if ((ret & FD_CLOEXEC) != flag) {
5379 ret = (ret & ~FD_CLOEXEC) | flag;
5380 ret = fcntl(fd, F_SETFD, ret);
5381 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5382 }
5383 }
5384
5385 }
5386
5387 GetOpenFile(io, fptr);
5388 if (fptr && 0 <= (fd = fptr->fd)) {
5389 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5390 if ((ret & FD_CLOEXEC) != flag) {
5391 ret = (ret & ~FD_CLOEXEC) | flag;
5392 ret = fcntl(fd, F_SETFD, ret);
5393 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5394 }
5395 }
5396 return Qnil;
5397}
5398#else
5399#define rb_io_set_close_on_exec rb_f_notimplement
5400#endif
5401
5402#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5403#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5404
5405static VALUE
5406finish_writeconv(rb_io_t *fptr, int noalloc)
5407{
5408 unsigned char *ds, *dp, *de;
5410
5411 if (!fptr->wbuf.ptr) {
5412 unsigned char buf[1024];
5413
5415 while (res == econv_destination_buffer_full) {
5416 ds = dp = buf;
5417 de = buf + sizeof(buf);
5418 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5419 while (dp-ds) {
5420 size_t remaining = dp-ds;
5421 long result = rb_io_write_memory(fptr, ds, remaining);
5422
5423 if (result > 0) {
5424 ds += result;
5425 if ((size_t)result == remaining) break;
5426 }
5427 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5428 if (fptr->fd < 0)
5429 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5430 }
5431 else {
5432 return noalloc ? Qtrue : INT2NUM(errno);
5433 }
5434 }
5435 if (res == econv_invalid_byte_sequence ||
5436 res == econv_incomplete_input ||
5438 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5439 }
5440 }
5441
5442 return Qnil;
5443 }
5444
5446 while (res == econv_destination_buffer_full) {
5447 if (fptr->wbuf.len == fptr->wbuf.capa) {
5448 if (io_fflush(fptr) < 0) {
5449 return noalloc ? Qtrue : INT2NUM(errno);
5450 }
5451 }
5452
5453 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5454 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5455 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5456 fptr->wbuf.len += (int)(dp - ds);
5457 if (res == econv_invalid_byte_sequence ||
5458 res == econv_incomplete_input ||
5460 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5461 }
5462 }
5463 return Qnil;
5464}
5465
5467 rb_io_t *fptr;
5468 int noalloc;
5469};
5470
5471static VALUE
5472finish_writeconv_sync(VALUE arg)
5473{
5474 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5475 return finish_writeconv(p->fptr, p->noalloc);
5476}
5477
5478static void*
5479nogvl_close(void *ptr)
5480{
5481 int *fd = ptr;
5482
5483 return (void*)(intptr_t)close(*fd);
5484}
5485
5486static int
5487maygvl_close(int fd, int keepgvl)
5488{
5489 if (keepgvl)
5490 return close(fd);
5491
5492 /*
5493 * close() may block for certain file types (NFS, SO_LINGER sockets,
5494 * inotify), so let other threads run.
5495 */
5496 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5497}
5498
5499static void*
5500nogvl_fclose(void *ptr)
5501{
5502 FILE *file = ptr;
5503
5504 return (void*)(intptr_t)fclose(file);
5505}
5506
5507static int
5508maygvl_fclose(FILE *file, int keepgvl)
5509{
5510 if (keepgvl)
5511 return fclose(file);
5512
5513 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5514}
5515
5516static void free_io_buffer(rb_io_buffer_t *buf);
5517
5518static void
5519fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
5520 struct rb_io_close_wait_list *busy)
5521{
5522 VALUE error = Qnil;
5523 int fd = fptr->fd;
5524 FILE *stdio_file = fptr->stdio_file;
5525 int mode = fptr->mode;
5526
5527 if (fptr->writeconv) {
5528 if (!NIL_P(fptr->write_lock) && !noraise) {
5529 struct finish_writeconv_arg arg;
5530 arg.fptr = fptr;
5531 arg.noalloc = noraise;
5532 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5533 }
5534 else {
5535 error = finish_writeconv(fptr, noraise);
5536 }
5537 }
5538 if (fptr->wbuf.len) {
5539 if (noraise) {
5540 io_flush_buffer_sync(fptr);
5541 }
5542 else {
5543 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5544 error = INT2NUM(errno);
5545 }
5546 }
5547 }
5548
5549 int done = 0;
5550
5551 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5552 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5553 done = 1;
5554 }
5555
5556 fptr->fd = -1;
5557 fptr->stdio_file = 0;
5559
5560 // Ensure waiting_fd users do not hit EBADF.
5561 if (busy) {
5562 // Wait for them to exit before we call close().
5563 rb_notify_fd_close_wait(busy);
5564 }
5565
5566 // Disable for now.
5567 // if (!done && fd >= 0) {
5568 // VALUE scheduler = rb_fiber_scheduler_current();
5569 // if (scheduler != Qnil) {
5570 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5571 // if (!UNDEF_P(result)) done = 1;
5572 // }
5573 // }
5574
5575 if (!done && stdio_file) {
5576 // stdio_file is deallocated anyway even if fclose failed.
5577 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5578 if (!noraise) {
5579 error = INT2NUM(errno);
5580 }
5581 }
5582
5583 done = 1;
5584 }
5585
5586 if (!done && fd >= 0) {
5587 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5588 // We assumes it is closed.
5589
5590 keepgvl |= !(mode & FMODE_WRITABLE);
5591 keepgvl |= noraise;
5592 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5593 if (!noraise) {
5594 error = INT2NUM(errno);
5595 }
5596 }
5597
5598 done = 1;
5599 }
5600
5601 if (!NIL_P(error) && !noraise) {
5602 if (RB_INTEGER_TYPE_P(error))
5603 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5604 else
5605 rb_exc_raise(error);
5606 }
5607}
5608
5609static void
5610fptr_finalize(rb_io_t *fptr, int noraise)
5611{
5612 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5613 free_io_buffer(&fptr->rbuf);
5614 free_io_buffer(&fptr->wbuf);
5615 clear_codeconv(fptr);
5616}
5617
5618static void
5619rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5620{
5621 if (fptr->finalize) {
5622 (*fptr->finalize)(fptr, noraise);
5623 }
5624 else {
5625 fptr_finalize(fptr, noraise);
5626 }
5627}
5628
5629static void
5630free_io_buffer(rb_io_buffer_t *buf)
5631{
5632 if (buf->ptr) {
5633 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5634 buf->ptr = NULL;
5635 }
5636}
5637
5638static void
5639clear_readconv(rb_io_t *fptr)
5640{
5641 if (fptr->readconv) {
5642 rb_econv_close(fptr->readconv);
5643 fptr->readconv = NULL;
5644 }
5645 free_io_buffer(&fptr->cbuf);
5646}
5647
5648static void
5649clear_writeconv(rb_io_t *fptr)
5650{
5651 if (fptr->writeconv) {
5653 fptr->writeconv = NULL;
5654 }
5655 fptr->writeconv_initialized = 0;
5656}
5657
5658static void
5659clear_codeconv(rb_io_t *fptr)
5660{
5661 clear_readconv(fptr);
5662 clear_writeconv(fptr);
5663}
5664
5665static void
5666rb_io_fptr_cleanup_all(rb_io_t *fptr)
5667{
5668 fptr->pathv = Qnil;
5669 if (0 <= fptr->fd)
5670 rb_io_fptr_cleanup(fptr, TRUE);
5671 fptr->write_lock = Qnil;
5672 free_io_buffer(&fptr->rbuf);
5673 free_io_buffer(&fptr->wbuf);
5674 clear_codeconv(fptr);
5675}
5676
5677void
5678rb_io_fptr_finalize_internal(void *ptr)
5679{
5680 if (!ptr) return;
5681 rb_io_fptr_cleanup_all(ptr);
5682 free(ptr);
5683}
5684
5685#undef rb_io_fptr_finalize
5686int
5687rb_io_fptr_finalize(rb_io_t *fptr)
5688{
5689 if (!fptr) {
5690 return 0;
5691 }
5692 else {
5693 rb_io_fptr_finalize_internal(fptr);
5694 return 1;
5695 }
5696}
5697#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5698
5699size_t
5700rb_io_memsize(const rb_io_t *fptr)
5701{
5702 size_t size = sizeof(rb_io_t);
5703 size += fptr->rbuf.capa;
5704 size += fptr->wbuf.capa;
5705 size += fptr->cbuf.capa;
5706 if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
5707 if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
5708 return size;
5709}
5710
5711#ifdef _WIN32
5712/* keep GVL while closing to prevent crash on Windows */
5713# define KEEPGVL TRUE
5714#else
5715# define KEEPGVL FALSE
5716#endif
5717
5718static rb_io_t *
5719io_close_fptr(VALUE io)
5720{
5721 rb_io_t *fptr;
5722 VALUE write_io;
5723 rb_io_t *write_fptr;
5724 struct rb_io_close_wait_list busy;
5725
5726 write_io = GetWriteIO(io);
5727 if (io != write_io) {
5728 write_fptr = RFILE(write_io)->fptr;
5729 if (write_fptr && 0 <= write_fptr->fd) {
5730 rb_io_fptr_cleanup(write_fptr, TRUE);
5731 }
5732 }
5733
5734 fptr = RFILE(io)->fptr;
5735 if (!fptr) return 0;
5736 if (fptr->fd < 0) return 0;
5737
5738 if (rb_notify_fd_close(fptr->fd, &busy)) {
5739 /* calls close(fptr->fd): */
5740 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5741 }
5742 rb_io_fptr_cleanup(fptr, FALSE);
5743 return fptr;
5744}
5745
5746static void
5747fptr_waitpid(rb_io_t *fptr, int nohang)
5748{
5749 int status;
5750 if (fptr->pid) {
5751 rb_last_status_clear();
5752 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5753 fptr->pid = 0;
5754 }
5755}
5756
5757VALUE
5759{
5760 rb_io_t *fptr = io_close_fptr(io);
5761 if (fptr) fptr_waitpid(fptr, 0);
5762 return Qnil;
5763}
5764
5765/*
5766 * call-seq:
5767 * close -> nil
5768 *
5769 * Closes the stream for both reading and writing
5770 * if open for either or both; returns +nil+.
5771 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5772 *
5773 * If the stream is open for writing, flushes any buffered writes
5774 * to the operating system before closing.
5775 *
5776 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5777 * (child exit status).
5778 *
5779 * It is not an error to close an IO object that has already been closed.
5780 * It just returns nil.
5781 *
5782 * Example:
5783 *
5784 * IO.popen('ruby', 'r+') do |pipe|
5785 * puts pipe.closed?
5786 * pipe.close
5787 * puts $?
5788 * puts pipe.closed?
5789 * end
5790 *
5791 * Output:
5792 *
5793 * false
5794 * pid 13760 exit 0
5795 * true
5796 *
5797 * Related: IO#close_read, IO#close_write, IO#closed?.
5798 */
5799
5800static VALUE
5801rb_io_close_m(VALUE io)
5802{
5803 rb_io_t *fptr = rb_io_get_fptr(io);
5804 if (fptr->fd < 0) {
5805 return Qnil;
5806 }
5807 rb_io_close(io);
5808 return Qnil;
5809}
5810
5811static VALUE
5812io_call_close(VALUE io)
5813{
5814 rb_check_funcall(io, rb_intern("close"), 0, 0);
5815 return io;
5816}
5817
5818static VALUE
5819ignore_closed_stream(VALUE io, VALUE exc)
5820{
5821 enum {mesg_len = sizeof(closed_stream)-1};
5822 VALUE mesg = rb_attr_get(exc, idMesg);
5823 if (!RB_TYPE_P(mesg, T_STRING) ||
5824 RSTRING_LEN(mesg) != mesg_len ||
5825 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5826 rb_exc_raise(exc);
5827 }
5828 return io;
5829}
5830
5831static VALUE
5832io_close(VALUE io)
5833{
5834 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5835 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5836 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5837 rb_eIOError, (VALUE)0);
5838 return io;
5839}
5840
5841/*
5842 * call-seq:
5843 * closed? -> true or false
5844 *
5845 * Returns +true+ if the stream is closed for both reading and writing,
5846 * +false+ otherwise.
5847 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5848 *
5849 * IO.popen('ruby', 'r+') do |pipe|
5850 * puts pipe.closed?
5851 * pipe.close_read
5852 * puts pipe.closed?
5853 * pipe.close_write
5854 * puts pipe.closed?
5855 * end
5856 *
5857 * Output:
5858 *
5859 * false
5860 * false
5861 * true
5862 *
5863 * Related: IO#close_read, IO#close_write, IO#close.
5864 */
5865VALUE
5867{
5868 rb_io_t *fptr;
5869 VALUE write_io;
5870 rb_io_t *write_fptr;
5871
5872 write_io = GetWriteIO(io);
5873 if (io != write_io) {
5874 write_fptr = RFILE(write_io)->fptr;
5875 if (write_fptr && 0 <= write_fptr->fd) {
5876 return Qfalse;
5877 }
5878 }
5879
5880 fptr = rb_io_get_fptr(io);
5881 return RBOOL(0 > fptr->fd);
5882}
5883
5884/*
5885 * call-seq:
5886 * close_read -> nil
5887 *
5888 * Closes the stream for reading if open for reading;
5889 * returns +nil+.
5890 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5891 *
5892 * If the stream was opened by IO.popen and is also closed for writing,
5893 * sets global variable <tt>$?</tt> (child exit status).
5894 *
5895 * Example:
5896 *
5897 * IO.popen('ruby', 'r+') do |pipe|
5898 * puts pipe.closed?
5899 * pipe.close_write
5900 * puts pipe.closed?
5901 * pipe.close_read
5902 * puts $?
5903 * puts pipe.closed?
5904 * end
5905 *
5906 * Output:
5907 *
5908 * false
5909 * false
5910 * pid 14748 exit 0
5911 * true
5912 *
5913 * Related: IO#close, IO#close_write, IO#closed?.
5914 */
5915
5916static VALUE
5917rb_io_close_read(VALUE io)
5918{
5919 rb_io_t *fptr;
5920 VALUE write_io;
5921
5922 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5923 if (fptr->fd < 0) return Qnil;
5924 if (is_socket(fptr->fd, fptr->pathv)) {
5925#ifndef SHUT_RD
5926# define SHUT_RD 0
5927#endif
5928 if (shutdown(fptr->fd, SHUT_RD) < 0)
5929 rb_sys_fail_path(fptr->pathv);
5930 fptr->mode &= ~FMODE_READABLE;
5931 if (!(fptr->mode & FMODE_WRITABLE))
5932 return rb_io_close(io);
5933 return Qnil;
5934 }
5935
5936 write_io = GetWriteIO(io);
5937 if (io != write_io) {
5938 rb_io_t *wfptr;
5939 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5940 wfptr->pid = fptr->pid;
5941 fptr->pid = 0;
5942 RFILE(io)->fptr = wfptr;
5943 /* bind to write_io temporarily to get rid of memory/fd leak */
5944 fptr->tied_io_for_writing = 0;
5945 RFILE(write_io)->fptr = fptr;
5946 rb_io_fptr_cleanup(fptr, FALSE);
5947 /* should not finalize fptr because another thread may be reading it */
5948 return Qnil;
5949 }
5950
5951 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5952 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5953 }
5954 return rb_io_close(io);
5955}
5956
5957/*
5958 * call-seq:
5959 * close_write -> nil
5960 *
5961 * Closes the stream for writing if open for writing;
5962 * returns +nil+.
5963 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5964 *
5965 * Flushes any buffered writes to the operating system before closing.
5966 *
5967 * If the stream was opened by IO.popen and is also closed for reading,
5968 * sets global variable <tt>$?</tt> (child exit status).
5969 *
5970 * IO.popen('ruby', 'r+') do |pipe|
5971 * puts pipe.closed?
5972 * pipe.close_read
5973 * puts pipe.closed?
5974 * pipe.close_write
5975 * puts $?
5976 * puts pipe.closed?
5977 * end
5978 *
5979 * Output:
5980 *
5981 * false
5982 * false
5983 * pid 15044 exit 0
5984 * true
5985 *
5986 * Related: IO#close, IO#close_read, IO#closed?.
5987 */
5988
5989static VALUE
5990rb_io_close_write(VALUE io)
5991{
5992 rb_io_t *fptr;
5993 VALUE write_io;
5994
5995 write_io = GetWriteIO(io);
5996 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5997 if (fptr->fd < 0) return Qnil;
5998 if (is_socket(fptr->fd, fptr->pathv)) {
5999#ifndef SHUT_WR
6000# define SHUT_WR 1
6001#endif
6002 if (shutdown(fptr->fd, SHUT_WR) < 0)
6003 rb_sys_fail_path(fptr->pathv);
6004 fptr->mode &= ~FMODE_WRITABLE;
6005 if (!(fptr->mode & FMODE_READABLE))
6006 return rb_io_close(write_io);
6007 return Qnil;
6008 }
6009
6010 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6011 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6012 }
6013
6014 if (io != write_io) {
6015 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6016 fptr->tied_io_for_writing = 0;
6017 }
6018 rb_io_close(write_io);
6019 return Qnil;
6020}
6021
6022/*
6023 * call-seq:
6024 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6025 *
6026 * Behaves like IO#seek, except that it:
6027 *
6028 * - Uses low-level system functions.
6029 * - Returns the new position.
6030 *
6031 */
6032
6033static VALUE
6034rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6035{
6036 VALUE offset, ptrname;
6037 int whence = SEEK_SET;
6038 rb_io_t *fptr;
6039 rb_off_t pos;
6040
6041 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6042 whence = interpret_seek_whence(ptrname);
6043 }
6044 pos = NUM2OFFT(offset);
6045 GetOpenFile(io, fptr);
6046 if ((fptr->mode & FMODE_READABLE) &&
6047 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6048 rb_raise(rb_eIOError, "sysseek for buffered IO");
6049 }
6050 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6051 rb_warn("sysseek for buffered IO");
6052 }
6053 errno = 0;
6054 pos = lseek(fptr->fd, pos, whence);
6055 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6056
6057 return OFFT2NUM(pos);
6058}
6059
6060/*
6061 * call-seq:
6062 * syswrite(object) -> integer
6063 *
6064 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6065 * returns the number bytes written.
6066 * If +object+ is not a string is converted via method to_s:
6067 *
6068 * f = File.new('t.tmp', 'w')
6069 * f.syswrite('foo') # => 3
6070 * f.syswrite(30) # => 2
6071 * f.syswrite(:foo) # => 3
6072 * f.close
6073 *
6074 * This methods should not be used with other stream-writer methods.
6075 *
6076 */
6077
6078static VALUE
6079rb_io_syswrite(VALUE io, VALUE str)
6080{
6081 VALUE tmp;
6082 rb_io_t *fptr;
6083 long n, len;
6084 const char *ptr;
6085
6086 if (!RB_TYPE_P(str, T_STRING))
6087 str = rb_obj_as_string(str);
6088
6089 io = GetWriteIO(io);
6090 GetOpenFile(io, fptr);
6092
6093 if (fptr->wbuf.len) {
6094 rb_warn("syswrite for buffered IO");
6095 }
6096
6097 tmp = rb_str_tmp_frozen_acquire(str);
6098 RSTRING_GETMEM(tmp, ptr, len);
6099 n = rb_io_write_memory(fptr, ptr, len);
6100 if (n < 0) rb_sys_fail_path(fptr->pathv);
6101 rb_str_tmp_frozen_release(str, tmp);
6102
6103 return LONG2FIX(n);
6104}
6105
6106/*
6107 * call-seq:
6108 * sysread(maxlen) -> string
6109 * sysread(maxlen, out_string) -> string
6110 *
6111 * Behaves like IO#readpartial, except that it uses low-level system functions.
6112 *
6113 * This method should not be used with other stream-reader methods.
6114 *
6115 */
6116
6117static VALUE
6118rb_io_sysread(int argc, VALUE *argv, VALUE io)
6119{
6120 VALUE len, str;
6121 rb_io_t *fptr;
6122 long n, ilen;
6123 struct io_internal_read_struct iis;
6124 int shrinkable;
6125
6126 rb_scan_args(argc, argv, "11", &len, &str);
6127 ilen = NUM2LONG(len);
6128
6129 shrinkable = io_setstrbuf(&str, ilen);
6130 if (ilen == 0) return str;
6131
6132 GetOpenFile(io, fptr);
6134
6135 if (READ_DATA_BUFFERED(fptr)) {
6136 rb_raise(rb_eIOError, "sysread for buffered IO");
6137 }
6138
6139 rb_io_check_closed(fptr);
6140
6141 io_setstrbuf(&str, ilen);
6142 iis.th = rb_thread_current();
6143 iis.fptr = fptr;
6144 iis.nonblock = 0;
6145 iis.fd = fptr->fd;
6146 iis.buf = RSTRING_PTR(str);
6147 iis.capa = ilen;
6148 iis.timeout = NULL;
6149 n = io_read_memory_locktmp(str, &iis);
6150
6151 if (n < 0) {
6152 rb_sys_fail_path(fptr->pathv);
6153 }
6154
6155 io_set_read_length(str, n, shrinkable);
6156
6157 if (n == 0 && ilen > 0) {
6158 rb_eof_error();
6159 }
6160
6161 return str;
6162}
6163
6165 struct rb_io *io;
6166 int fd;
6167 void *buf;
6168 size_t count;
6169 rb_off_t offset;
6170};
6171
6172static VALUE
6173internal_pread_func(void *_arg)
6174{
6175 struct prdwr_internal_arg *arg = _arg;
6176
6177 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6178}
6179
6180static VALUE
6181pread_internal_call(VALUE _arg)
6182{
6183 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6184
6185 VALUE scheduler = rb_fiber_scheduler_current();
6186 if (scheduler != Qnil) {
6187 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6188
6189 if (!UNDEF_P(result)) {
6191 }
6192 }
6193
6194 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6195}
6196
6197/*
6198 * call-seq:
6199 * pread(maxlen, offset) -> string
6200 * pread(maxlen, offset, out_string) -> string
6201 *
6202 * Behaves like IO#readpartial, except that it:
6203 *
6204 * - Reads at the given +offset+ (in bytes).
6205 * - Disregards, and does not modify, the stream's position
6206 * (see {Position}[rdoc-ref:IO@Position]).
6207 * - Bypasses any user space buffering in the stream.
6208 *
6209 * Because this method does not disturb the stream's state
6210 * (its position, in particular), +pread+ allows multiple threads and processes
6211 * to use the same \IO object for reading at various offsets.
6212 *
6213 * f = File.open('t.txt')
6214 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6215 * f.pos # => 52
6216 * # Read 12 bytes at offset 0.
6217 * f.pread(12, 0) # => "First line\n"
6218 * # Read 9 bytes at offset 8.
6219 * f.pread(9, 8) # => "ne\nSecon"
6220 * f.close
6221 *
6222 * Not available on some platforms.
6223 *
6224 */
6225static VALUE
6226rb_io_pread(int argc, VALUE *argv, VALUE io)
6227{
6228 VALUE len, offset, str;
6229 rb_io_t *fptr;
6230 ssize_t n;
6231 struct prdwr_internal_arg arg;
6232 int shrinkable;
6233
6234 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6235 arg.count = NUM2SIZET(len);
6236 arg.offset = NUM2OFFT(offset);
6237
6238 shrinkable = io_setstrbuf(&str, (long)arg.count);
6239 if (arg.count == 0) return str;
6240 arg.buf = RSTRING_PTR(str);
6241
6242 GetOpenFile(io, fptr);
6244
6245 arg.io = fptr;
6246 arg.fd = fptr->fd;
6247 rb_io_check_closed(fptr);
6248
6249 rb_str_locktmp(str);
6250 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6251
6252 if (n < 0) {
6253 rb_sys_fail_path(fptr->pathv);
6254 }
6255 io_set_read_length(str, n, shrinkable);
6256 if (n == 0 && arg.count > 0) {
6257 rb_eof_error();
6258 }
6259
6260 return str;
6261}
6262
6263static VALUE
6264internal_pwrite_func(void *_arg)
6265{
6266 struct prdwr_internal_arg *arg = _arg;
6267
6268 VALUE scheduler = rb_fiber_scheduler_current();
6269 if (scheduler != Qnil) {
6270 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6271
6272 if (!UNDEF_P(result)) {
6274 }
6275 }
6276
6277
6278 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6279}
6280
6281/*
6282 * call-seq:
6283 * pwrite(object, offset) -> integer
6284 *
6285 * Behaves like IO#write, except that it:
6286 *
6287 * - Writes at the given +offset+ (in bytes).
6288 * - Disregards, and does not modify, the stream's position
6289 * (see {Position}[rdoc-ref:IO@Position]).
6290 * - Bypasses any user space buffering in the stream.
6291 *
6292 * Because this method does not disturb the stream's state
6293 * (its position, in particular), +pwrite+ allows multiple threads and processes
6294 * to use the same \IO object for writing at various offsets.
6295 *
6296 * f = File.open('t.tmp', 'w+')
6297 * # Write 6 bytes at offset 3.
6298 * f.pwrite('ABCDEF', 3) # => 6
6299 * f.rewind
6300 * f.read # => "\u0000\u0000\u0000ABCDEF"
6301 * f.close
6302 *
6303 * Not available on some platforms.
6304 *
6305 */
6306static VALUE
6307rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6308{
6309 rb_io_t *fptr;
6310 ssize_t n;
6311 struct prdwr_internal_arg arg;
6312 VALUE tmp;
6313
6314 if (!RB_TYPE_P(str, T_STRING))
6315 str = rb_obj_as_string(str);
6316
6317 arg.offset = NUM2OFFT(offset);
6318
6319 io = GetWriteIO(io);
6320 GetOpenFile(io, fptr);
6322
6323 arg.io = fptr;
6324 arg.fd = fptr->fd;
6325
6326 tmp = rb_str_tmp_frozen_acquire(str);
6327 arg.buf = RSTRING_PTR(tmp);
6328 arg.count = (size_t)RSTRING_LEN(tmp);
6329
6330 n = (ssize_t)rb_io_blocking_region_wait(fptr, internal_pwrite_func, &arg, RUBY_IO_WRITABLE);
6331 if (n < 0) rb_sys_fail_path(fptr->pathv);
6332 rb_str_tmp_frozen_release(str, tmp);
6333
6334 return SSIZET2NUM(n);
6335}
6336
6337VALUE
6339{
6340 rb_io_t *fptr;
6341
6342 GetOpenFile(io, fptr);
6343 if (fptr->readconv)
6345 if (fptr->writeconv)
6347 fptr->mode |= FMODE_BINMODE;
6348 fptr->mode &= ~FMODE_TEXTMODE;
6350#ifdef O_BINARY
6351 if (!fptr->readconv) {
6352 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6353 }
6354 else {
6355 setmode(fptr->fd, O_BINARY);
6356 }
6357#endif
6358 return io;
6359}
6360
6361static void
6362io_ascii8bit_binmode(rb_io_t *fptr)
6363{
6364 if (fptr->readconv) {
6365 rb_econv_close(fptr->readconv);
6366 fptr->readconv = NULL;
6367 }
6368 if (fptr->writeconv) {
6370 fptr->writeconv = NULL;
6371 }
6372 fptr->mode |= FMODE_BINMODE;
6373 fptr->mode &= ~FMODE_TEXTMODE;
6374 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6375
6376 fptr->encs.enc = rb_ascii8bit_encoding();
6377 fptr->encs.enc2 = NULL;
6378 fptr->encs.ecflags = 0;
6379 fptr->encs.ecopts = Qnil;
6380 clear_codeconv(fptr);
6381}
6382
6383VALUE
6385{
6386 rb_io_t *fptr;
6387
6388 GetOpenFile(io, fptr);
6389 io_ascii8bit_binmode(fptr);
6390
6391 return io;
6392}
6393
6394/*
6395 * call-seq:
6396 * binmode -> self
6397 *
6398 * Sets the stream's data mode as binary
6399 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6400 *
6401 * A stream's data mode may not be changed from binary to text.
6402 *
6403 */
6404
6405static VALUE
6406rb_io_binmode_m(VALUE io)
6407{
6408 VALUE write_io;
6409
6411
6412 write_io = GetWriteIO(io);
6413 if (write_io != io)
6414 rb_io_ascii8bit_binmode(write_io);
6415 return io;
6416}
6417
6418/*
6419 * call-seq:
6420 * binmode? -> true or false
6421 *
6422 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6423 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6424 *
6425 */
6426static VALUE
6427rb_io_binmode_p(VALUE io)
6428{
6429 rb_io_t *fptr;
6430 GetOpenFile(io, fptr);
6431 return RBOOL(fptr->mode & FMODE_BINMODE);
6432}
6433
6434static const char*
6435rb_io_fmode_modestr(int fmode)
6436{
6437 if (fmode & FMODE_APPEND) {
6438 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6439 return MODE_BTMODE("a+", "ab+", "at+");
6440 }
6441 return MODE_BTMODE("a", "ab", "at");
6442 }
6443 switch (fmode & FMODE_READWRITE) {
6444 default:
6445 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6446 case FMODE_READABLE:
6447 return MODE_BTMODE("r", "rb", "rt");
6448 case FMODE_WRITABLE:
6449 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6450 case FMODE_READWRITE:
6451 if (fmode & FMODE_CREATE) {
6452 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6453 }
6454 return MODE_BTMODE("r+", "rb+", "rt+");
6455 }
6456}
6457
6458static const char bom_prefix[] = "bom|";
6459static const char utf_prefix[] = "utf-";
6460enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6461enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6462
6463static int
6464io_encname_bom_p(const char *name, long len)
6465{
6466 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6467}
6468
6469int
6470rb_io_modestr_fmode(const char *modestr)
6471{
6472 int fmode = 0;
6473 const char *m = modestr, *p = NULL;
6474
6475 switch (*m++) {
6476 case 'r':
6477 fmode |= FMODE_READABLE;
6478 break;
6479 case 'w':
6481 break;
6482 case 'a':
6484 break;
6485 default:
6486 goto error;
6487 }
6488
6489 while (*m) {
6490 switch (*m++) {
6491 case 'b':
6492 fmode |= FMODE_BINMODE;
6493 break;
6494 case 't':
6495 fmode |= FMODE_TEXTMODE;
6496 break;
6497 case '+':
6498 fmode |= FMODE_READWRITE;
6499 break;
6500 case 'x':
6501 if (modestr[0] != 'w')
6502 goto error;
6503 fmode |= FMODE_EXCL;
6504 break;
6505 default:
6506 goto error;
6507 case ':':
6508 p = strchr(m, ':');
6509 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6510 fmode |= FMODE_SETENC_BY_BOM;
6511 goto finished;
6512 }
6513 }
6514
6515 finished:
6516 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6517 goto error;
6518
6519 return fmode;
6520
6521 error:
6522 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6524}
6525
6526int
6528{
6529 int fmode = 0;
6530
6531 switch (oflags & O_ACCMODE) {
6532 case O_RDONLY:
6533 fmode = FMODE_READABLE;
6534 break;
6535 case O_WRONLY:
6536 fmode = FMODE_WRITABLE;
6537 break;
6538 case O_RDWR:
6539 fmode = FMODE_READWRITE;
6540 break;
6541 }
6542
6543 if (oflags & O_APPEND) {
6544 fmode |= FMODE_APPEND;
6545 }
6546 if (oflags & O_TRUNC) {
6547 fmode |= FMODE_TRUNC;
6548 }
6549 if (oflags & O_CREAT) {
6550 fmode |= FMODE_CREATE;
6551 }
6552 if (oflags & O_EXCL) {
6553 fmode |= FMODE_EXCL;
6554 }
6555#ifdef O_BINARY
6556 if (oflags & O_BINARY) {
6557 fmode |= FMODE_BINMODE;
6558 }
6559#endif
6560
6561 return fmode;
6562}
6563
6564static int
6565rb_io_fmode_oflags(int fmode)
6566{
6567 int oflags = 0;
6568
6569 switch (fmode & FMODE_READWRITE) {
6570 case FMODE_READABLE:
6571 oflags |= O_RDONLY;
6572 break;
6573 case FMODE_WRITABLE:
6574 oflags |= O_WRONLY;
6575 break;
6576 case FMODE_READWRITE:
6577 oflags |= O_RDWR;
6578 break;
6579 }
6580
6581 if (fmode & FMODE_APPEND) {
6582 oflags |= O_APPEND;
6583 }
6584 if (fmode & FMODE_TRUNC) {
6585 oflags |= O_TRUNC;
6586 }
6587 if (fmode & FMODE_CREATE) {
6588 oflags |= O_CREAT;
6589 }
6590 if (fmode & FMODE_EXCL) {
6591 oflags |= O_EXCL;
6592 }
6593#ifdef O_BINARY
6594 if (fmode & FMODE_BINMODE) {
6595 oflags |= O_BINARY;
6596 }
6597#endif
6598
6599 return oflags;
6600}
6601
6602int
6603rb_io_modestr_oflags(const char *modestr)
6604{
6605 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6606}
6607
6608static const char*
6609rb_io_oflags_modestr(int oflags)
6610{
6611#ifdef O_BINARY
6612# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6613#else
6614# define MODE_BINARY(a,b) (a)
6615#endif
6616 int accmode;
6617 if (oflags & O_EXCL) {
6618 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6619 }
6620 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6621 if (oflags & O_APPEND) {
6622 if (accmode == O_WRONLY) {
6623 return MODE_BINARY("a", "ab");
6624 }
6625 if (accmode == O_RDWR) {
6626 return MODE_BINARY("a+", "ab+");
6627 }
6628 }
6629 switch (accmode) {
6630 default:
6631 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6632 case O_RDONLY:
6633 return MODE_BINARY("r", "rb");
6634 case O_WRONLY:
6635 return MODE_BINARY("w", "wb");
6636 case O_RDWR:
6637 if (oflags & O_TRUNC) {
6638 return MODE_BINARY("w+", "wb+");
6639 }
6640 return MODE_BINARY("r+", "rb+");
6641 }
6642}
6643
6644/*
6645 * Convert external/internal encodings to enc/enc2
6646 * NULL => use default encoding
6647 * Qnil => no encoding specified (internal only)
6648 */
6649static void
6650rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
6651{
6652 int default_ext = 0;
6653
6654 if (ext == NULL) {
6656 default_ext = 1;
6657 }
6658 if (rb_is_ascii8bit_enc(ext)) {
6659 /* If external is ASCII-8BIT, no transcoding */
6660 intern = NULL;
6661 }
6662 else if (intern == NULL) {
6664 }
6665 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6666 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6667 /* No internal encoding => use external + no transcoding */
6668 *enc = (default_ext && intern != ext) ? NULL : ext;
6669 *enc2 = NULL;
6670 }
6671 else {
6672 *enc = intern;
6673 *enc2 = ext;
6674 }
6675}
6676
6677static void
6678unsupported_encoding(const char *name, rb_encoding *enc)
6679{
6680 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6681}
6682
6683static void
6684parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6685 rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6686{
6687 const char *p;
6688 char encname[ENCODING_MAXNAMELEN+1];
6689 int idx, idx2;
6690 int fmode = fmode_p ? *fmode_p : 0;
6691 rb_encoding *ext_enc, *int_enc;
6692 long len;
6693
6694 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6695
6696 p = strrchr(estr, ':');
6697 len = p ? (p++ - estr) : (long)strlen(estr);
6698 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6699 estr += bom_prefix_len;
6700 len -= bom_prefix_len;
6701 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6702 fmode |= FMODE_SETENC_BY_BOM;
6703 }
6704 else {
6705 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6706 fmode &= ~FMODE_SETENC_BY_BOM;
6707 }
6708 }
6709 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6710 idx = -1;
6711 }
6712 else {
6713 if (p) {
6714 memcpy(encname, estr, len);
6715 encname[len] = '\0';
6716 estr = encname;
6717 }
6718 idx = rb_enc_find_index(estr);
6719 }
6720 if (fmode_p) *fmode_p = fmode;
6721
6722 if (idx >= 0)
6723 ext_enc = rb_enc_from_index(idx);
6724 else {
6725 if (idx != -2)
6726 unsupported_encoding(estr, estr_enc);
6727 ext_enc = NULL;
6728 }
6729
6730 int_enc = NULL;
6731 if (p) {
6732 if (*p == '-' && *(p+1) == '\0') {
6733 /* Special case - "-" => no transcoding */
6734 int_enc = (rb_encoding *)Qnil;
6735 }
6736 else {
6737 idx2 = rb_enc_find_index(p);
6738 if (idx2 < 0)
6739 unsupported_encoding(p, estr_enc);
6740 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6741 int_enc = (rb_encoding *)Qnil;
6742 }
6743 else
6744 int_enc = rb_enc_from_index(idx2);
6745 }
6746 }
6747
6748 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6749}
6750
6751int
6752rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6753{
6754 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6755 int extracted = 0;
6756 rb_encoding *extencoding = NULL;
6757 rb_encoding *intencoding = NULL;
6758
6759 if (!NIL_P(opt)) {
6760 VALUE v;
6761 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6762 if (v != Qnil) encoding = v;
6763 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6764 if (v != Qnil) extenc = v;
6765 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6766 if (!UNDEF_P(v)) intenc = v;
6767 }
6768 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6769 if (!NIL_P(ruby_verbose)) {
6770 int idx = rb_to_encoding_index(encoding);
6771 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6772 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6773 encoding, UNDEF_P(extenc) ? "internal" : "external");
6774 }
6775 encoding = Qnil;
6776 }
6777 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6778 extencoding = rb_to_encoding(extenc);
6779 }
6780 if (!UNDEF_P(intenc)) {
6781 if (NIL_P(intenc)) {
6782 /* internal_encoding: nil => no transcoding */
6783 intencoding = (rb_encoding *)Qnil;
6784 }
6785 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6786 char *p = StringValueCStr(tmp);
6787
6788 if (*p == '-' && *(p+1) == '\0') {
6789 /* Special case - "-" => no transcoding */
6790 intencoding = (rb_encoding *)Qnil;
6791 }
6792 else {
6793 intencoding = rb_to_encoding(intenc);
6794 }
6795 }
6796 else {
6797 intencoding = rb_to_encoding(intenc);
6798 }
6799 if (extencoding == intencoding) {
6800 intencoding = (rb_encoding *)Qnil;
6801 }
6802 }
6803 if (!NIL_P(encoding)) {
6804 extracted = 1;
6805 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6806 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6807 enc_p, enc2_p, fmode_p);
6808 }
6809 else {
6810 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6811 }
6812 }
6813 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6814 extracted = 1;
6815 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6816 }
6817 return extracted;
6818}
6819
6820static void
6821validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6822{
6823 int fmode = *fmode_p;
6824
6825 if ((fmode & FMODE_READABLE) &&
6826 !enc2 &&
6827 !(fmode & FMODE_BINMODE) &&
6828 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6829 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6830
6831 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6832 rb_raise(rb_eArgError, "newline decorator with binary mode");
6833 }
6834 if (!(fmode & FMODE_BINMODE) &&
6835 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6836 fmode |= FMODE_TEXTMODE;
6837 *fmode_p = fmode;
6838 }
6839#if !DEFAULT_TEXTMODE
6840 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6841 fmode &= ~FMODE_TEXTMODE;
6842 *fmode_p = fmode;
6843 }
6844#endif
6845}
6846
6847static void
6848extract_binmode(VALUE opthash, int *fmode)
6849{
6850 if (!NIL_P(opthash)) {
6851 VALUE v;
6852 v = rb_hash_aref(opthash, sym_textmode);
6853 if (!NIL_P(v)) {
6854 if (*fmode & FMODE_TEXTMODE)
6855 rb_raise(rb_eArgError, "textmode specified twice");
6856 if (*fmode & FMODE_BINMODE)
6857 rb_raise(rb_eArgError, "both textmode and binmode specified");
6858 if (RTEST(v))
6859 *fmode |= FMODE_TEXTMODE;
6860 }
6861 v = rb_hash_aref(opthash, sym_binmode);
6862 if (!NIL_P(v)) {
6863 if (*fmode & FMODE_BINMODE)
6864 rb_raise(rb_eArgError, "binmode specified twice");
6865 if (*fmode & FMODE_TEXTMODE)
6866 rb_raise(rb_eArgError, "both textmode and binmode specified");
6867 if (RTEST(v))
6868 *fmode |= FMODE_BINMODE;
6869 }
6870
6871 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6872 rb_raise(rb_eArgError, "both textmode and binmode specified");
6873 }
6874}
6875
6876void
6877rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6878 int *oflags_p, int *fmode_p, struct rb_io_encoding *convconfig_p)
6879{
6880 VALUE vmode;
6881 int oflags, fmode;
6882 rb_encoding *enc, *enc2;
6883 int ecflags;
6884 VALUE ecopts;
6885 int has_enc = 0, has_vmode = 0;
6886 VALUE intmode;
6887
6888 vmode = *vmode_p;
6889
6890 /* Set to defaults */
6891 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6892
6893 vmode_handle:
6894 if (NIL_P(vmode)) {
6895 fmode = FMODE_READABLE;
6896 oflags = O_RDONLY;
6897 }
6898 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6899 vmode = intmode;
6900 oflags = NUM2INT(intmode);
6901 fmode = rb_io_oflags_fmode(oflags);
6902 }
6903 else {
6904 const char *p;
6905
6906 StringValue(vmode);
6907 p = StringValueCStr(vmode);
6908 fmode = rb_io_modestr_fmode(p);
6909 oflags = rb_io_fmode_oflags(fmode);
6910 p = strchr(p, ':');
6911 if (p) {
6912 has_enc = 1;
6913 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6914 }
6915 else {
6916 rb_encoding *e;
6917
6918 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6919 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6920 }
6921 }
6922
6923 if (NIL_P(opthash)) {
6924 ecflags = (fmode & FMODE_READABLE) ?
6927#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6928 ecflags |= (fmode & FMODE_WRITABLE) ?
6929 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6930 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6931#endif
6932 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6933 ecopts = Qnil;
6934 if (fmode & FMODE_BINMODE) {
6935#ifdef O_BINARY
6936 oflags |= O_BINARY;
6937#endif
6938 if (!has_enc)
6939 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6940 }
6941#if DEFAULT_TEXTMODE
6942 else if (NIL_P(vmode)) {
6943 fmode |= DEFAULT_TEXTMODE;
6944 }
6945#endif
6946 }
6947 else {
6948 VALUE v;
6949 if (!has_vmode) {
6950 v = rb_hash_aref(opthash, sym_mode);
6951 if (!NIL_P(v)) {
6952 if (!NIL_P(vmode)) {
6953 rb_raise(rb_eArgError, "mode specified twice");
6954 }
6955 has_vmode = 1;
6956 vmode = v;
6957 goto vmode_handle;
6958 }
6959 }
6960 v = rb_hash_aref(opthash, sym_flags);
6961 if (!NIL_P(v)) {
6962 v = rb_to_int(v);
6963 oflags |= NUM2INT(v);
6964 vmode = INT2NUM(oflags);
6965 fmode = rb_io_oflags_fmode(oflags);
6966 }
6967 extract_binmode(opthash, &fmode);
6968 if (fmode & FMODE_BINMODE) {
6969#ifdef O_BINARY
6970 oflags |= O_BINARY;
6971#endif
6972 if (!has_enc)
6973 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6974 }
6975#if DEFAULT_TEXTMODE
6976 else if (NIL_P(vmode)) {
6977 fmode |= DEFAULT_TEXTMODE;
6978 }
6979#endif
6980 v = rb_hash_aref(opthash, sym_perm);
6981 if (!NIL_P(v)) {
6982 if (vperm_p) {
6983 if (!NIL_P(*vperm_p)) {
6984 rb_raise(rb_eArgError, "perm specified twice");
6985 }
6986 *vperm_p = v;
6987 }
6988 else {
6989 /* perm no use, just ignore */
6990 }
6991 }
6992 ecflags = (fmode & FMODE_READABLE) ?
6995#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6996 ecflags |= (fmode & FMODE_WRITABLE) ?
6997 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6998 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6999#endif
7000
7001 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7002 if (has_enc) {
7003 rb_raise(rb_eArgError, "encoding specified twice");
7004 }
7005 }
7006 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7007 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7008 }
7009
7010 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7011
7012 *vmode_p = vmode;
7013
7014 *oflags_p = oflags;
7015 *fmode_p = fmode;
7016 convconfig_p->enc = enc;
7017 convconfig_p->enc2 = enc2;
7018 convconfig_p->ecflags = ecflags;
7019 convconfig_p->ecopts = ecopts;
7020}
7021
7023 VALUE fname;
7024 int oflags;
7025 mode_t perm;
7026};
7027
7028static void *
7029sysopen_func(void *ptr)
7030{
7031 const struct sysopen_struct *data = ptr;
7032 const char *fname = RSTRING_PTR(data->fname);
7033 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7034}
7035
7036static inline int
7037rb_sysopen_internal(struct sysopen_struct *data)
7038{
7039 int fd;
7040 do {
7041 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7042 } while (fd < 0 && errno == EINTR);
7043 if (0 <= fd)
7044 rb_update_max_fd(fd);
7045 return fd;
7046}
7047
7048static int
7049rb_sysopen(VALUE fname, int oflags, mode_t perm)
7050{
7051 int fd = -1;
7052 struct sysopen_struct data;
7053
7054 data.fname = rb_str_encode_ospath(fname);
7055 StringValueCStr(data.fname);
7056 data.oflags = oflags;
7057 data.perm = perm;
7058
7059 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7060 rb_syserr_fail_path(first_errno, fname);
7061 }
7062 return fd;
7063}
7064
7065static inline FILE *
7066fdopen_internal(int fd, const char *modestr)
7067{
7068 FILE *file;
7069
7070#if defined(__sun)
7071 errno = 0;
7072#endif
7073 file = fdopen(fd, modestr);
7074 if (!file) {
7075#ifdef _WIN32
7076 if (errno == 0) errno = EINVAL;
7077#elif defined(__sun)
7078 if (errno == 0) errno = EMFILE;
7079#endif
7080 }
7081 return file;
7082}
7083
7084FILE *
7085rb_fdopen(int fd, const char *modestr)
7086{
7087 FILE *file = 0;
7088
7089 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7090 rb_syserr_fail(first_errno, 0);
7091 }
7092
7093 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7094#ifdef USE_SETVBUF
7095 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7096 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7097#endif
7098 return file;
7099}
7100
7101static int
7102io_check_tty(rb_io_t *fptr)
7103{
7104 int t = isatty(fptr->fd);
7105 if (t)
7106 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7107 return t;
7108}
7109
7110static VALUE rb_io_internal_encoding(VALUE);
7111static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7112
7113static int
7114io_strip_bom(VALUE io)
7115{
7116 VALUE b1, b2, b3, b4;
7117 rb_io_t *fptr;
7118
7119 GetOpenFile(io, fptr);
7120 if (!(fptr->mode & FMODE_READABLE)) return 0;
7121 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7122 switch (b1) {
7123 case INT2FIX(0xEF):
7124 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7125 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7126 if (b3 == INT2FIX(0xBF)) {
7127 return rb_utf8_encindex();
7128 }
7129 rb_io_ungetbyte(io, b3);
7130 }
7131 rb_io_ungetbyte(io, b2);
7132 break;
7133
7134 case INT2FIX(0xFE):
7135 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7136 if (b2 == INT2FIX(0xFF)) {
7137 return ENCINDEX_UTF_16BE;
7138 }
7139 rb_io_ungetbyte(io, b2);
7140 break;
7141
7142 case INT2FIX(0xFF):
7143 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7144 if (b2 == INT2FIX(0xFE)) {
7145 b3 = rb_io_getbyte(io);
7146 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7147 if (b4 == INT2FIX(0)) {
7148 return ENCINDEX_UTF_32LE;
7149 }
7150 rb_io_ungetbyte(io, b4);
7151 }
7152 rb_io_ungetbyte(io, b3);
7153 return ENCINDEX_UTF_16LE;
7154 }
7155 rb_io_ungetbyte(io, b2);
7156 break;
7157
7158 case INT2FIX(0):
7159 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7160 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7161 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7162 if (b4 == INT2FIX(0xFF)) {
7163 return ENCINDEX_UTF_32BE;
7164 }
7165 rb_io_ungetbyte(io, b4);
7166 }
7167 rb_io_ungetbyte(io, b3);
7168 }
7169 rb_io_ungetbyte(io, b2);
7170 break;
7171 }
7172 rb_io_ungetbyte(io, b1);
7173 return 0;
7174}
7175
7176static rb_encoding *
7177io_set_encoding_by_bom(VALUE io)
7178{
7179 int idx = io_strip_bom(io);
7180 rb_io_t *fptr;
7181 rb_encoding *extenc = NULL;
7182
7183 GetOpenFile(io, fptr);
7184 if (idx) {
7185 extenc = rb_enc_from_index(idx);
7186 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7187 rb_io_internal_encoding(io), Qnil);
7188 }
7189 else {
7190 fptr->encs.enc2 = NULL;
7191 }
7192 return extenc;
7193}
7194
7195static VALUE
7196rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
7197 const struct rb_io_encoding *convconfig, mode_t perm)
7198{
7199 VALUE pathv;
7200 rb_io_t *fptr;
7201 struct rb_io_encoding cc;
7202 if (!convconfig) {
7203 /* Set to default encodings */
7204 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7205 cc.ecflags = 0;
7206 cc.ecopts = Qnil;
7207 convconfig = &cc;
7208 }
7209 validate_enc_binmode(&fmode, convconfig->ecflags,
7210 convconfig->enc, convconfig->enc2);
7211
7212 MakeOpenFile(io, fptr);
7213 fptr->mode = fmode;
7214 fptr->encs = *convconfig;
7215 pathv = rb_str_new_frozen(filename);
7216#ifdef O_TMPFILE
7217 if (!(oflags & O_TMPFILE)) {
7218 fptr->pathv = pathv;
7219 }
7220#else
7221 fptr->pathv = pathv;
7222#endif
7223 fptr->fd = rb_sysopen(pathv, oflags, perm);
7224 io_check_tty(fptr);
7225 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7226
7227 return io;
7228}
7229
7230static VALUE
7231rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7232{
7233 int fmode = rb_io_modestr_fmode(modestr);
7234 const char *p = strchr(modestr, ':');
7235 struct rb_io_encoding convconfig;
7236
7237 if (p) {
7238 parse_mode_enc(p+1, rb_usascii_encoding(),
7239 &convconfig.enc, &convconfig.enc2, &fmode);
7240 }
7241 else {
7242 rb_encoding *e;
7243 /* Set to default encodings */
7244
7245 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7246 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7247 }
7248
7249 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7252#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7253 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7254 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7255 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7256#endif
7257 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7258 convconfig.ecopts = Qnil;
7259
7260 return rb_file_open_generic(io, filename,
7261 rb_io_fmode_oflags(fmode),
7262 fmode,
7263 &convconfig,
7264 0666);
7265}
7266
7267VALUE
7268rb_file_open_str(VALUE fname, const char *modestr)
7269{
7270 FilePathValue(fname);
7271 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7272}
7273
7274VALUE
7275rb_file_open(const char *fname, const char *modestr)
7276{
7277 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7278}
7279
7280#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7281static struct pipe_list {
7282 rb_io_t *fptr;
7283 struct pipe_list *next;
7284} *pipe_list;
7285
7286static void
7287pipe_add_fptr(rb_io_t *fptr)
7288{
7289 struct pipe_list *list;
7290
7291 list = ALLOC(struct pipe_list);
7292 list->fptr = fptr;
7293 list->next = pipe_list;
7294 pipe_list = list;
7295}
7296
7297static void
7298pipe_del_fptr(rb_io_t *fptr)
7299{
7300 struct pipe_list **prev = &pipe_list;
7301 struct pipe_list *tmp;
7302
7303 while ((tmp = *prev) != 0) {
7304 if (tmp->fptr == fptr) {
7305 *prev = tmp->next;
7306 free(tmp);
7307 return;
7308 }
7309 prev = &tmp->next;
7310 }
7311}
7312
7313#if defined (_WIN32) || defined(__CYGWIN__)
7314static void
7315pipe_atexit(void)
7316{
7317 struct pipe_list *list = pipe_list;
7318 struct pipe_list *tmp;
7319
7320 while (list) {
7321 tmp = list->next;
7322 rb_io_fptr_finalize(list->fptr);
7323 list = tmp;
7324 }
7325}
7326#endif
7327
7328static void
7329pipe_finalize(rb_io_t *fptr, int noraise)
7330{
7331#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7332 int status = 0;
7333 if (fptr->stdio_file) {
7334 status = pclose(fptr->stdio_file);
7335 }
7336 fptr->fd = -1;
7337 fptr->stdio_file = 0;
7338 rb_last_status_set(status, fptr->pid);
7339#else
7340 fptr_finalize(fptr, noraise);
7341#endif
7342 pipe_del_fptr(fptr);
7343}
7344#endif
7345
7346static void
7347fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7348{
7349#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7350 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7351
7352 if (old_finalize == orig->finalize) return;
7353#endif
7354
7355 fptr->finalize = orig->finalize;
7356
7357#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7358 if (old_finalize != pipe_finalize) {
7359 struct pipe_list *list;
7360 for (list = pipe_list; list; list = list->next) {
7361 if (list->fptr == fptr) break;
7362 }
7363 if (!list) pipe_add_fptr(fptr);
7364 }
7365 else {
7366 pipe_del_fptr(fptr);
7367 }
7368#endif
7369}
7370
7371void
7373{
7375 fptr->mode |= FMODE_SYNC;
7376}
7377
7378void
7379rb_io_unbuffered(rb_io_t *fptr)
7380{
7381 rb_io_synchronized(fptr);
7382}
7383
7384int
7385rb_pipe(int *pipes)
7386{
7387 int ret;
7388 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7389 if (ret == 0) {
7390 rb_update_max_fd(pipes[0]);
7391 rb_update_max_fd(pipes[1]);
7392 }
7393 return ret;
7394}
7395
7396#ifdef _WIN32
7397#define HAVE_SPAWNV 1
7398#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7399#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7400#endif
7401
7402#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7403struct popen_arg {
7404 VALUE execarg_obj;
7405 struct rb_execarg *eargp;
7406 int modef;
7407 int pair[2];
7408 int write_pair[2];
7409};
7410#endif
7411
7412#ifdef HAVE_WORKING_FORK
7413# ifndef __EMSCRIPTEN__
7414static void
7415popen_redirect(struct popen_arg *p)
7416{
7417 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7418 close(p->write_pair[1]);
7419 if (p->write_pair[0] != 0) {
7420 dup2(p->write_pair[0], 0);
7421 close(p->write_pair[0]);
7422 }
7423 close(p->pair[0]);
7424 if (p->pair[1] != 1) {
7425 dup2(p->pair[1], 1);
7426 close(p->pair[1]);
7427 }
7428 }
7429 else if (p->modef & FMODE_READABLE) {
7430 close(p->pair[0]);
7431 if (p->pair[1] != 1) {
7432 dup2(p->pair[1], 1);
7433 close(p->pair[1]);
7434 }
7435 }
7436 else {
7437 close(p->pair[1]);
7438 if (p->pair[0] != 0) {
7439 dup2(p->pair[0], 0);
7440 close(p->pair[0]);
7441 }
7442 }
7443}
7444# endif
7445
7446#if defined(__linux__)
7447/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7448 * Since /proc may not be available, linux_get_maxfd is just a hint.
7449 * This function, linux_get_maxfd, must be async-signal-safe.
7450 * I.e. opendir() is not usable.
7451 *
7452 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7453 * However they are easy to re-implement in async-signal-safe manner.
7454 * (Also note that there is missing/memcmp.c.)
7455 */
7456static int
7457linux_get_maxfd(void)
7458{
7459 int fd;
7460 char buf[4096], *p, *np, *e;
7461 ssize_t ss;
7462 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7463 if (fd < 0) return fd;
7464 ss = read(fd, buf, sizeof(buf));
7465 if (ss < 0) goto err;
7466 p = buf;
7467 e = buf + ss;
7468 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7469 (np = memchr(p, '\n', e-p)) != NULL) {
7470 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7471 int fdsize;
7472 p += sizeof("FDSize:")-1;
7473 *np = '\0';
7474 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7475 close(fd);
7476 return fdsize;
7477 }
7478 p = np+1;
7479 }
7480 /* fall through */
7481
7482 err:
7483 close(fd);
7484 return (int)ss;
7485}
7486#endif
7487
7488/* This function should be async-signal-safe. */
7489void
7490rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7491{
7492#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7493 int fd, ret;
7494 int max = (int)max_file_descriptor;
7495# ifdef F_MAXFD
7496 /* F_MAXFD is available since NetBSD 2.0. */
7497 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7498 if (ret != -1)
7499 maxhint = max = ret;
7500# elif defined(__linux__)
7501 ret = linux_get_maxfd();
7502 if (maxhint < ret)
7503 maxhint = ret;
7504 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7505# endif
7506 if (max < maxhint)
7507 max = maxhint;
7508 for (fd = lowfd; fd <= max; fd++) {
7509 if (!NIL_P(noclose_fds) &&
7510 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7511 continue;
7512 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7513 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7514 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7515 }
7516# define CONTIGUOUS_CLOSED_FDS 20
7517 if (ret != -1) {
7518 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7519 max = fd + CONTIGUOUS_CLOSED_FDS;
7520 }
7521 }
7522#endif
7523}
7524
7525# ifndef __EMSCRIPTEN__
7526static int
7527popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7528{
7529 struct popen_arg *p = (struct popen_arg*)pp;
7530
7531 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7532}
7533# endif
7534#endif
7535
7536#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7537static VALUE
7538rb_execarg_fixup_v(VALUE execarg_obj)
7539{
7540 rb_execarg_parent_start(execarg_obj);
7541 return Qnil;
7542}
7543#else
7544char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7545#endif
7546
7547#ifndef __EMSCRIPTEN__
7548static VALUE
7549pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7550 const struct rb_io_encoding *convconfig)
7551{
7552 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7553 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7554 rb_pid_t pid = 0;
7555 rb_io_t *fptr;
7556 VALUE port;
7557 rb_io_t *write_fptr;
7558 VALUE write_port;
7559#if defined(HAVE_WORKING_FORK)
7560 int status;
7561 char errmsg[80] = { '\0' };
7562#endif
7563#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7564 int state;
7565 struct popen_arg arg;
7566#endif
7567 int e = 0;
7568#if defined(HAVE_SPAWNV)
7569# if defined(HAVE_SPAWNVE)
7570# define DO_SPAWN(cmd, args, envp) ((args) ? \
7571 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7572 spawne(P_NOWAIT, (cmd), (envp)))
7573# else
7574# define DO_SPAWN(cmd, args, envp) ((args) ? \
7575 spawnv(P_NOWAIT, (cmd), (args)) : \
7576 spawn(P_NOWAIT, (cmd)))
7577# endif
7578# if !defined(HAVE_WORKING_FORK)
7579 char **args = NULL;
7580# if defined(HAVE_SPAWNVE)
7581 char **envp = NULL;
7582# endif
7583# endif
7584#endif
7585#if !defined(HAVE_WORKING_FORK)
7586 struct rb_execarg sarg, *sargp = &sarg;
7587#endif
7588 FILE *fp = 0;
7589 int fd = -1;
7590 int write_fd = -1;
7591#if !defined(HAVE_WORKING_FORK)
7592 const char *cmd = 0;
7593
7594 if (prog)
7595 cmd = StringValueCStr(prog);
7596#endif
7597
7598#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7599 arg.execarg_obj = execarg_obj;
7600 arg.eargp = eargp;
7601 arg.modef = fmode;
7602 arg.pair[0] = arg.pair[1] = -1;
7603 arg.write_pair[0] = arg.write_pair[1] = -1;
7604# if !defined(HAVE_WORKING_FORK)
7605 if (eargp && !eargp->use_shell) {
7606 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7607 }
7608# endif
7609 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7611 if (rb_pipe(arg.write_pair) < 0)
7612 rb_sys_fail_str(prog);
7613 if (rb_pipe(arg.pair) < 0) {
7614 e = errno;
7615 close(arg.write_pair[0]);
7616 close(arg.write_pair[1]);
7617 rb_syserr_fail_str(e, prog);
7618 }
7619 if (eargp) {
7620 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7621 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7622 }
7623 break;
7624 case FMODE_READABLE:
7625 if (rb_pipe(arg.pair) < 0)
7626 rb_sys_fail_str(prog);
7627 if (eargp)
7628 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7629 break;
7630 case FMODE_WRITABLE:
7631 if (rb_pipe(arg.pair) < 0)
7632 rb_sys_fail_str(prog);
7633 if (eargp)
7634 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7635 break;
7636 default:
7637 rb_sys_fail_str(prog);
7638 }
7639 if (!NIL_P(execarg_obj)) {
7640 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7641 if (state) {
7642 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7643 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7644 if (0 <= arg.pair[0]) close(arg.pair[0]);
7645 if (0 <= arg.pair[1]) close(arg.pair[1]);
7646 rb_execarg_parent_end(execarg_obj);
7647 rb_jump_tag(state);
7648 }
7649
7650# if defined(HAVE_WORKING_FORK)
7651 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7652# else
7653 rb_execarg_run_options(eargp, sargp, NULL, 0);
7654# if defined(HAVE_SPAWNVE)
7655 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7656# endif
7657 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7658 /* exec failed */
7659 switch (e = errno) {
7660 case EAGAIN:
7661# if EWOULDBLOCK != EAGAIN
7662 case EWOULDBLOCK:
7663# endif
7664 rb_thread_sleep(1);
7665 continue;
7666 }
7667 break;
7668 }
7669 if (eargp)
7670 rb_execarg_run_options(sargp, NULL, NULL, 0);
7671# endif
7672 rb_execarg_parent_end(execarg_obj);
7673 }
7674 else {
7675# if defined(HAVE_WORKING_FORK)
7676 pid = rb_call_proc__fork();
7677 if (pid == 0) { /* child */
7678 popen_redirect(&arg);
7679 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7680 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7681 return Qnil;
7682 }
7683# else
7685# endif
7686 }
7687
7688 /* parent */
7689 if (pid < 0) {
7690# if defined(HAVE_WORKING_FORK)
7691 e = errno;
7692# endif
7693 close(arg.pair[0]);
7694 close(arg.pair[1]);
7696 close(arg.write_pair[0]);
7697 close(arg.write_pair[1]);
7698 }
7699# if defined(HAVE_WORKING_FORK)
7700 if (errmsg[0])
7701 rb_syserr_fail(e, errmsg);
7702# endif
7703 rb_syserr_fail_str(e, prog);
7704 }
7705 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7706 close(arg.pair[1]);
7707 fd = arg.pair[0];
7708 close(arg.write_pair[0]);
7709 write_fd = arg.write_pair[1];
7710 }
7711 else if (fmode & FMODE_READABLE) {
7712 close(arg.pair[1]);
7713 fd = arg.pair[0];
7714 }
7715 else {
7716 close(arg.pair[0]);
7717 fd = arg.pair[1];
7718 }
7719#else
7720 cmd = rb_execarg_commandline(eargp, &prog);
7721 if (!NIL_P(execarg_obj)) {
7722 rb_execarg_parent_start(execarg_obj);
7723 rb_execarg_run_options(eargp, sargp, NULL, 0);
7724 }
7725 fp = popen(cmd, modestr);
7726 e = errno;
7727 if (eargp) {
7728 rb_execarg_parent_end(execarg_obj);
7729 rb_execarg_run_options(sargp, NULL, NULL, 0);
7730 }
7731 if (!fp) rb_syserr_fail_path(e, prog);
7732 fd = fileno(fp);
7733#endif
7734
7735 port = io_alloc(rb_cIO);
7736 MakeOpenFile(port, fptr);
7737 fptr->fd = fd;
7738 fptr->stdio_file = fp;
7739 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7740 if (convconfig) {
7741 fptr->encs = *convconfig;
7742#if RUBY_CRLF_ENVIRONMENT
7745 }
7746#endif
7747 }
7748 else {
7749 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7751 }
7752#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7753 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7754 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7755 }
7756#endif
7757 }
7758 fptr->pid = pid;
7759
7760 if (0 <= write_fd) {
7761 write_port = io_alloc(rb_cIO);
7762 MakeOpenFile(write_port, write_fptr);
7763 write_fptr->fd = write_fd;
7764 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7765 fptr->mode &= ~FMODE_WRITABLE;
7766 fptr->tied_io_for_writing = write_port;
7767 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7768 }
7769
7770#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7771 fptr->finalize = pipe_finalize;
7772 pipe_add_fptr(fptr);
7773#endif
7774 return port;
7775}
7776#else
7777static VALUE
7778pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7779 const struct rb_io_encoding *convconfig)
7780{
7781 rb_raise(rb_eNotImpError, "popen() is not available");
7782}
7783#endif
7784
7785static int
7786is_popen_fork(VALUE prog)
7787{
7788 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7789#if !defined(HAVE_WORKING_FORK)
7790 rb_raise(rb_eNotImpError,
7791 "fork() function is unimplemented on this machine");
7792#else
7793 return TRUE;
7794#endif
7795 }
7796 return FALSE;
7797}
7798
7799static VALUE
7800pipe_open_s(VALUE prog, const char *modestr, int fmode,
7801 const struct rb_io_encoding *convconfig)
7802{
7803 int argc = 1;
7804 VALUE *argv = &prog;
7805 VALUE execarg_obj = Qnil;
7806
7807 if (!is_popen_fork(prog))
7808 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7809 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7810}
7811
7812static VALUE
7813pipe_close(VALUE io)
7814{
7815 rb_io_t *fptr = io_close_fptr(io);
7816 if (fptr) {
7817 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7818 }
7819 return Qnil;
7820}
7821
7822static VALUE popen_finish(VALUE port, VALUE klass);
7823
7824/*
7825 * call-seq:
7826 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7827 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7828 *
7829 * Executes the given command +cmd+ as a subprocess
7830 * whose $stdin and $stdout are connected to a new stream +io+.
7831 *
7832 * This method has potential security vulnerabilities if called with untrusted input;
7833 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
7834 *
7835 * If no block is given, returns the new stream,
7836 * which depending on given +mode+ may be open for reading, writing, or both.
7837 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7838 *
7839 * If a block is given, the stream is passed to the block
7840 * (again, open for reading, writing, or both);
7841 * when the block exits, the stream is closed,
7842 * and the block's value is assigned to global variable <tt>$?</tt> and returned.
7843 *
7844 * Optional argument +mode+ may be any valid \IO mode.
7845 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7846 *
7847 * Required argument +cmd+ determines which of the following occurs:
7848 *
7849 * - The process forks.
7850 * - A specified program runs in a shell.
7851 * - A specified program runs with specified arguments.
7852 * - A specified program runs with specified arguments and a specified +argv0+.
7853 *
7854 * Each of these is detailed below.
7855 *
7856 * The optional hash argument +env+ specifies name/value pairs that are to be added
7857 * to the environment variables for the subprocess:
7858 *
7859 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7860 * pipe.puts 'puts ENV["FOO"]'
7861 * pipe.close_write
7862 * pipe.gets
7863 * end => "bar\n"
7864 *
7865 * Optional keyword arguments +opts+ specify:
7866 *
7867 * - {Open options}[rdoc-ref:IO@Open+Options].
7868 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7869 * - Options for Kernel#spawn.
7870 *
7871 * <b>Forked \Process</b>
7872 *
7873 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7874 * IO.popen('-') do |pipe|
7875 * if pipe
7876 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7877 * else
7878 * $stderr.puts "In child, pid is #{$$}\n"
7879 * end
7880 * end
7881 *
7882 * Output:
7883 *
7884 * In parent, child pid is 26253
7885 * In child, pid is 26253
7886 *
7887 * Note that this is not supported on all platforms.
7888 *
7889 * <b>Shell Subprocess</b>
7890 *
7891 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7892 * the program named +cmd+ is run as a shell command:
7893 *
7894 * IO.popen('uname') do |pipe|
7895 * pipe.readlines
7896 * end
7897 *
7898 * Output:
7899 *
7900 * ["Linux\n"]
7901 *
7902 * Another example:
7903 *
7904 * IO.popen('/bin/sh', 'r+') do |pipe|
7905 * pipe.puts('ls')
7906 * pipe.close_write
7907 * $stderr.puts pipe.readlines.size
7908 * end
7909 *
7910 * Output:
7911 *
7912 * 213
7913 *
7914 * <b>Program Subprocess</b>
7915 *
7916 * When argument +cmd+ is an array of strings,
7917 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7918 *
7919 * IO.popen(['du', '..', '.']) do |pipe|
7920 * $stderr.puts pipe.readlines.size
7921 * end
7922 *
7923 * Output:
7924 *
7925 * 1111
7926 *
7927 * <b>Program Subprocess with <tt>argv0</tt></b>
7928 *
7929 * When argument +cmd+ is an array whose first element is a 2-element string array
7930 * and whose remaining elements (if any) are strings:
7931 *
7932 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7933 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7934 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7935 *
7936 * Example (sets <tt>$0</tt> to 'foo'):
7937 *
7938 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7939 *
7940 * <b>Some Special Examples</b>
7941 *
7942 * # Set IO encoding.
7943 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7944 * euc_jp_string = nkf_io.read
7945 * }
7946 *
7947 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7948 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7949 * ls_result_with_error = io.read
7950 * end
7951 *
7952 * # Use mixture of spawn options and IO options.
7953 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7954 * ls_result_with_error = io.read
7955 * end
7956 *
7957 * f = IO.popen("uname")
7958 * p f.readlines
7959 * f.close
7960 * puts "Parent is #{Process.pid}"
7961 * IO.popen("date") {|f| puts f.gets }
7962 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7963 * p $?
7964 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7965 * f.puts "bar"; f.close_write; puts f.gets
7966 * }
7967 *
7968 * Output (from last section):
7969 *
7970 * ["Linux\n"]
7971 * Parent is 21346
7972 * Thu Jan 15 22:41:19 JST 2009
7973 * 21346 is here, f is #<IO:fd 3>
7974 * 21352 is here, f is nil
7975 * #<Process::Status: pid 21352 exit 0>
7976 * <foo>bar;zot;
7977 *
7978 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7979 *
7980 */
7981
7982static VALUE
7983rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7984{
7985 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7986
7987 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7988 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7989 switch (argc) {
7990 case 2:
7991 pmode = argv[1];
7992 case 1:
7993 pname = argv[0];
7994 break;
7995 default:
7996 {
7997 int ex = !NIL_P(opt);
7998 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7999 }
8000 }
8001 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8002}
8003
8004VALUE
8005rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8006{
8007 const char *modestr;
8008 VALUE tmp, execarg_obj = Qnil;
8009 int oflags, fmode;
8010 struct rb_io_encoding convconfig;
8011
8012 tmp = rb_check_array_type(pname);
8013 if (!NIL_P(tmp)) {
8014 long len = RARRAY_LEN(tmp);
8015#if SIZEOF_LONG > SIZEOF_INT
8016 if (len > INT_MAX) {
8017 rb_raise(rb_eArgError, "too many arguments");
8018 }
8019#endif
8020 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8021 RB_GC_GUARD(tmp);
8022 }
8023 else {
8024 StringValue(pname);
8025 execarg_obj = Qnil;
8026 if (!is_popen_fork(pname))
8027 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8028 }
8029 if (!NIL_P(execarg_obj)) {
8030 if (!NIL_P(opt))
8031 opt = rb_execarg_extract_options(execarg_obj, opt);
8032 if (!NIL_P(env))
8033 rb_execarg_setenv(execarg_obj, env);
8034 }
8035 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8036 modestr = rb_io_oflags_modestr(oflags);
8037
8038 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8039}
8040
8041static VALUE
8042popen_finish(VALUE port, VALUE klass)
8043{
8044 if (NIL_P(port)) {
8045 /* child */
8046 if (rb_block_given_p()) {
8047 rb_protect(rb_yield, Qnil, NULL);
8048 rb_io_flush(rb_ractor_stdout());
8049 rb_io_flush(rb_ractor_stderr());
8050 _exit(0);
8051 }
8052 return Qnil;
8053 }
8054 RBASIC_SET_CLASS(port, klass);
8055 if (rb_block_given_p()) {
8056 return rb_ensure(rb_yield, port, pipe_close, port);
8057 }
8058 return port;
8059}
8060
8061#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8062struct popen_writer_arg {
8063 char *const *argv;
8064 struct popen_arg popen;
8065};
8066
8067static int
8068exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8069{
8070 struct popen_writer_arg *pw = arg;
8071 pw->popen.modef = FMODE_WRITABLE;
8072 popen_redirect(&pw->popen);
8073 execv(pw->argv[0], pw->argv);
8074 strlcpy(errmsg, strerror(errno), buflen);
8075 return -1;
8076}
8077#endif
8078
8079FILE *
8080ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8081{
8082#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8083# ifdef HAVE_WORKING_FORK
8084 struct popen_writer_arg pw;
8085 int *const write_pair = pw.popen.pair;
8086# else
8087 int write_pair[2];
8088# endif
8089
8090#ifdef HAVE_PIPE2
8091 int result = pipe2(write_pair, O_CLOEXEC);
8092#else
8093 int result = pipe(write_pair);
8094#endif
8095
8096 *pid = -1;
8097 if (result == 0) {
8098# ifdef HAVE_WORKING_FORK
8099 pw.argv = argv;
8100 int status;
8101 char errmsg[80] = {'\0'};
8102 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8103# else
8104 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8105 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8106# endif
8107 close(write_pair[0]);
8108 if (*pid < 0) {
8109 close(write_pair[1]);
8110 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8111 }
8112 else {
8113 return fdopen(write_pair[1], "w");
8114 }
8115 }
8116#endif
8117 return NULL;
8118}
8119
8120static VALUE
8121rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8122{
8123 struct rb_io_encoding convconfig;
8124 int oflags, fmode;
8125 mode_t perm;
8126
8127 FilePathValue(fname);
8128
8129 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8130 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8131
8132 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8133
8134 return io;
8135}
8136
8137/*
8138 * Document-method: File::open
8139 *
8140 * call-seq:
8141 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8142 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8143 *
8144 * Creates a new File object, via File.new with the given arguments.
8145 *
8146 * With no block given, returns the File object.
8147 *
8148 * With a block given, calls the block with the File object
8149 * and returns the block's value.
8150 *
8151 */
8152
8153/*
8154 * Document-method: IO::open
8155 *
8156 * call-seq:
8157 * IO.open(fd, mode = 'r', **opts) -> io
8158 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8159 *
8160 * Creates a new \IO object, via IO.new with the given arguments.
8161 *
8162 * With no block given, returns the \IO object.
8163 *
8164 * With a block given, calls the block with the \IO object
8165 * and returns the block's value.
8166 *
8167 */
8168
8169static VALUE
8170rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8171{
8173
8174 if (rb_block_given_p()) {
8175 return rb_ensure(rb_yield, io, io_close, io);
8176 }
8177
8178 return io;
8179}
8180
8181/*
8182 * call-seq:
8183 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8184 *
8185 * Opens the file at the given path with the given mode and permissions;
8186 * returns the integer file descriptor.
8187 *
8188 * If the file is to be readable, it must exist;
8189 * if the file is to be writable and does not exist,
8190 * it is created with the given permissions:
8191 *
8192 * File.write('t.tmp', '') # => 0
8193 * IO.sysopen('t.tmp') # => 8
8194 * IO.sysopen('t.tmp', 'w') # => 9
8195 *
8196 *
8197 */
8198
8199static VALUE
8200rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8201{
8202 VALUE fname, vmode, vperm;
8203 VALUE intmode;
8204 int oflags, fd;
8205 mode_t perm;
8206
8207 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8208 FilePathValue(fname);
8209
8210 if (NIL_P(vmode))
8211 oflags = O_RDONLY;
8212 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8213 oflags = NUM2INT(intmode);
8214 else {
8215 StringValue(vmode);
8216 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8217 }
8218 if (NIL_P(vperm)) perm = 0666;
8219 else perm = NUM2MODET(vperm);
8220
8221 RB_GC_GUARD(fname) = rb_str_new4(fname);
8222 fd = rb_sysopen(fname, oflags, perm);
8223 return INT2NUM(fd);
8224}
8225
8226static VALUE
8227check_pipe_command(VALUE filename_or_command)
8228{
8229 char *s = RSTRING_PTR(filename_or_command);
8230 long l = RSTRING_LEN(filename_or_command);
8231 char *e = s + l;
8232 int chlen;
8233
8234 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8235 VALUE cmd = rb_str_new(s+chlen, l-chlen);
8236 return cmd;
8237 }
8238 return Qnil;
8239}
8240
8241/*
8242 * call-seq:
8243 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8244 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8245 *
8246 * Creates an IO object connected to the given file.
8247 *
8248 * This method has potential security vulnerabilities if called with untrusted input;
8249 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
8250 *
8251 * With no block given, file stream is returned:
8252 *
8253 * open('t.txt') # => #<File:t.txt>
8254 *
8255 * With a block given, calls the block with the open file stream,
8256 * then closes the stream:
8257 *
8258 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8259 *
8260 * Output:
8261 *
8262 * #<File:t.txt>
8263 *
8264 * See File.open for details.
8265 *
8266 */
8267
8268static VALUE
8269rb_f_open(int argc, VALUE *argv, VALUE _)
8270{
8271 ID to_open = 0;
8272 int redirect = FALSE;
8273
8274 if (argc >= 1) {
8275 CONST_ID(to_open, "to_open");
8276 if (rb_respond_to(argv[0], to_open)) {
8277 redirect = TRUE;
8278 }
8279 else {
8280 VALUE tmp = argv[0];
8281 FilePathValue(tmp);
8282 if (NIL_P(tmp)) {
8283 redirect = TRUE;
8284 }
8285 else {
8286 VALUE cmd = check_pipe_command(tmp);
8287 if (!NIL_P(cmd)) {
8288 // TODO: when removed in 4.0, update command_injection.rdoc
8289 rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen");
8290 argv[0] = cmd;
8291 return rb_io_s_popen(argc, argv, rb_cIO);
8292 }
8293 }
8294 }
8295 }
8296 if (redirect) {
8297 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8298
8299 if (rb_block_given_p()) {
8300 return rb_ensure(rb_yield, io, io_close, io);
8301 }
8302 return io;
8303 }
8304 return rb_io_s_open(argc, argv, rb_cFile);
8305}
8306
8307static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const struct rb_io_encoding *, mode_t);
8308
8309static VALUE
8310rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8311{
8312 int oflags, fmode;
8313 struct rb_io_encoding convconfig;
8314 mode_t perm;
8315
8316 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8317 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8318 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8319}
8320
8321static VALUE
8322rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode,
8323 const struct rb_io_encoding *convconfig, mode_t perm)
8324{
8325 VALUE cmd;
8326 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8327 // TODO: when removed in 4.0, update command_injection.rdoc
8328 rb_warn_deprecated_to_remove_at(4.0, "IO process creation with a leading '|'", "IO.popen");
8329 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8330 }
8331 else {
8332 return rb_file_open_generic(io_alloc(klass), filename,
8333 oflags, fmode, convconfig, perm);
8334 }
8335}
8336
8337static VALUE
8338io_reopen(VALUE io, VALUE nfile)
8339{
8340 rb_io_t *fptr, *orig;
8341 int fd, fd2;
8342 rb_off_t pos = 0;
8343
8344 nfile = rb_io_get_io(nfile);
8345 GetOpenFile(io, fptr);
8346 GetOpenFile(nfile, orig);
8347
8348 if (fptr == orig) return io;
8349 if (RUBY_IO_EXTERNAL_P(fptr)) {
8350 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8351 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8352 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8353 rb_raise(rb_eArgError,
8354 "%s can't change access mode from \"%s\" to \"%s\"",
8355 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8356 rb_io_fmode_modestr(orig->mode));
8357 }
8358 }
8359 if (fptr->mode & FMODE_WRITABLE) {
8360 if (io_fflush(fptr) < 0)
8361 rb_sys_fail_on_write(fptr);
8362 }
8363 else {
8364 flush_before_seek(fptr, true);
8365 }
8366 if (orig->mode & FMODE_READABLE) {
8367 pos = io_tell(orig);
8368 }
8369 if (orig->mode & FMODE_WRITABLE) {
8370 if (io_fflush(orig) < 0)
8371 rb_sys_fail_on_write(fptr);
8372 }
8373
8374 /* copy rb_io_t structure */
8375 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8376 fptr->encs = orig->encs;
8377 fptr->pid = orig->pid;
8378 fptr->lineno = orig->lineno;
8379 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8380 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8381 fptr_copy_finalizer(fptr, orig);
8382
8383 fd = fptr->fd;
8384 fd2 = orig->fd;
8385 if (fd != fd2) {
8386 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8387 /* need to keep FILE objects of stdin, stdout and stderr */
8388 if (rb_cloexec_dup2(fd2, fd) < 0)
8389 rb_sys_fail_path(orig->pathv);
8390 rb_update_max_fd(fd);
8391 }
8392 else {
8393 fclose(fptr->stdio_file);
8394 fptr->stdio_file = 0;
8395 fptr->fd = -1;
8396 if (rb_cloexec_dup2(fd2, fd) < 0)
8397 rb_sys_fail_path(orig->pathv);
8398 rb_update_max_fd(fd);
8399 fptr->fd = fd;
8400 }
8402 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8403 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8404 rb_sys_fail_path(fptr->pathv);
8405 }
8406 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8407 rb_sys_fail_path(orig->pathv);
8408 }
8409 }
8410 }
8411
8412 if (fptr->mode & FMODE_BINMODE) {
8413 rb_io_binmode(io);
8414 }
8415
8416 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8417 return io;
8418}
8419
8420#ifdef _WIN32
8421int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8422#else
8423static int
8424rb_freopen(VALUE fname, const char *mode, FILE *fp)
8425{
8426 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8427 RB_GC_GUARD(fname);
8428 return errno;
8429 }
8430 return 0;
8431}
8432#endif
8433
8434/*
8435 * call-seq:
8436 * reopen(other_io) -> self
8437 * reopen(path, mode = 'r', **opts) -> self
8438 *
8439 * Reassociates the stream with another stream,
8440 * which may be of a different class.
8441 * This method may be used to redirect an existing stream
8442 * to a new destination.
8443 *
8444 * With argument +other_io+ given, reassociates with that stream:
8445 *
8446 * # Redirect $stdin from a file.
8447 * f = File.open('t.txt')
8448 * $stdin.reopen(f)
8449 * f.close
8450 *
8451 * # Redirect $stdout to a file.
8452 * f = File.open('t.tmp', 'w')
8453 * $stdout.reopen(f)
8454 * f.close
8455 *
8456 * With argument +path+ given, reassociates with a new stream to that file path:
8457 *
8458 * $stdin.reopen('t.txt')
8459 * $stdout.reopen('t.tmp', 'w')
8460 *
8461 * Optional keyword arguments +opts+ specify:
8462 *
8463 * - {Open Options}[rdoc-ref:IO@Open+Options].
8464 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8465 *
8466 */
8467
8468static VALUE
8469rb_io_reopen(int argc, VALUE *argv, VALUE file)
8470{
8471 VALUE fname, nmode, opt;
8472 int oflags;
8473 rb_io_t *fptr;
8474
8475 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8476 VALUE tmp = rb_io_check_io(fname);
8477 if (!NIL_P(tmp)) {
8478 return io_reopen(file, tmp);
8479 }
8480 }
8481
8482 FilePathValue(fname);
8483 rb_io_taint_check(file);
8484 fptr = RFILE(file)->fptr;
8485 if (!fptr) {
8486 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8487 }
8488
8489 if (!NIL_P(nmode) || !NIL_P(opt)) {
8490 int fmode;
8491 struct rb_io_encoding convconfig;
8492
8493 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8494 if (RUBY_IO_EXTERNAL_P(fptr) &&
8495 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8496 (fptr->mode & FMODE_READWRITE)) {
8497 rb_raise(rb_eArgError,
8498 "%s can't change access mode from \"%s\" to \"%s\"",
8499 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8500 rb_io_fmode_modestr(fmode));
8501 }
8502 fptr->mode = fmode;
8503 fptr->encs = convconfig;
8504 }
8505 else {
8506 oflags = rb_io_fmode_oflags(fptr->mode);
8507 }
8508
8509 fptr->pathv = fname;
8510 if (fptr->fd < 0) {
8511 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8512 fptr->stdio_file = 0;
8513 return file;
8514 }
8515
8516 if (fptr->mode & FMODE_WRITABLE) {
8517 if (io_fflush(fptr) < 0)
8518 rb_sys_fail_on_write(fptr);
8519 }
8520 fptr->rbuf.off = fptr->rbuf.len = 0;
8521
8522 if (fptr->stdio_file) {
8523 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8524 rb_io_oflags_modestr(oflags),
8525 fptr->stdio_file);
8526 if (e) rb_syserr_fail_path(e, fptr->pathv);
8527 fptr->fd = fileno(fptr->stdio_file);
8528 rb_fd_fix_cloexec(fptr->fd);
8529#ifdef USE_SETVBUF
8530 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8531 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8532#endif
8533 if (fptr->stdio_file == stderr) {
8534 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8535 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8536 }
8537 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8538 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8539 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8540 }
8541 }
8542 else {
8543 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8544 int err = 0;
8545 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8546 err = errno;
8547 (void)close(tmpfd);
8548 if (err) {
8549 rb_syserr_fail_path(err, fptr->pathv);
8550 }
8551 }
8552
8553 return file;
8554}
8555
8556/* :nodoc: */
8557static VALUE
8558rb_io_init_copy(VALUE dest, VALUE io)
8559{
8560 rb_io_t *fptr, *orig;
8561 int fd;
8562 VALUE write_io;
8563 rb_off_t pos;
8564
8565 io = rb_io_get_io(io);
8566 if (!OBJ_INIT_COPY(dest, io)) return dest;
8567 GetOpenFile(io, orig);
8568 MakeOpenFile(dest, fptr);
8569
8570 rb_io_flush(io);
8571
8572 /* copy rb_io_t structure */
8573 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8574 fptr->encs = orig->encs;
8575 fptr->pid = orig->pid;
8576 fptr->lineno = orig->lineno;
8577 fptr->timeout = orig->timeout;
8578 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8579 fptr_copy_finalizer(fptr, orig);
8580
8581 fd = ruby_dup(orig->fd);
8582 fptr->fd = fd;
8583 pos = io_tell(orig);
8584 if (0 <= pos)
8585 io_seek(fptr, pos, SEEK_SET);
8586 if (fptr->mode & FMODE_BINMODE) {
8587 rb_io_binmode(dest);
8588 }
8589
8590 write_io = GetWriteIO(io);
8591 if (io != write_io) {
8592 write_io = rb_obj_dup(write_io);
8593 fptr->tied_io_for_writing = write_io;
8594 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8595 }
8596
8597 return dest;
8598}
8599
8600/*
8601 * call-seq:
8602 * printf(format_string, *objects) -> nil
8603 *
8604 * Formats and writes +objects+ to the stream.
8605 *
8606 * For details on +format_string+, see
8607 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8608 *
8609 */
8610
8611VALUE
8612rb_io_printf(int argc, const VALUE *argv, VALUE out)
8613{
8614 rb_io_write(out, rb_f_sprintf(argc, argv));
8615 return Qnil;
8616}
8617
8618/*
8619 * call-seq:
8620 * printf(format_string, *objects) -> nil
8621 * printf(io, format_string, *objects) -> nil
8622 *
8623 * Equivalent to:
8624 *
8625 * io.write(sprintf(format_string, *objects))
8626 *
8627 * For details on +format_string+, see
8628 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8629 *
8630 * With the single argument +format_string+, formats +objects+ into the string,
8631 * then writes the formatted string to $stdout:
8632 *
8633 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8634 *
8635 * Output (on $stdout):
8636 *
8637 * 0024 24 24.00#
8638 *
8639 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8640 * then writes the formatted string to +io+:
8641 *
8642 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8643 *
8644 * Output (on $stderr):
8645 *
8646 * 0024 24 24.00# => nil
8647 *
8648 * With no arguments, does nothing.
8649 *
8650 */
8651
8652static VALUE
8653rb_f_printf(int argc, VALUE *argv, VALUE _)
8654{
8655 VALUE out;
8656
8657 if (argc == 0) return Qnil;
8658 if (RB_TYPE_P(argv[0], T_STRING)) {
8659 out = rb_ractor_stdout();
8660 }
8661 else {
8662 out = argv[0];
8663 argv++;
8664 argc--;
8665 }
8666 rb_io_write(out, rb_f_sprintf(argc, argv));
8667
8668 return Qnil;
8669}
8670
8671static void
8672deprecated_str_setter(VALUE val, ID id, VALUE *var)
8673{
8674 rb_str_setter(val, id, &val);
8675 if (!NIL_P(val)) {
8676 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8677 }
8678 *var = val;
8679}
8680
8681/*
8682 * call-seq:
8683 * print(*objects) -> nil
8684 *
8685 * Writes the given objects to the stream; returns +nil+.
8686 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8687 * (<tt>$\</tt>), if it is not +nil+.
8688 * See {Line IO}[rdoc-ref:IO@Line+IO].
8689 *
8690 * With argument +objects+ given, for each object:
8691 *
8692 * - Converts via its method +to_s+ if not a string.
8693 * - Writes to the stream.
8694 * - If not the last object, writes the output field separator
8695 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8696 *
8697 * With default separators:
8698 *
8699 * f = File.open('t.tmp', 'w+')
8700 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8701 * p $OUTPUT_RECORD_SEPARATOR
8702 * p $OUTPUT_FIELD_SEPARATOR
8703 * f.print(*objects)
8704 * f.rewind
8705 * p f.read
8706 * f.close
8707 *
8708 * Output:
8709 *
8710 * nil
8711 * nil
8712 * "00.00/10+0izerozero"
8713 *
8714 * With specified separators:
8715 *
8716 * $\ = "\n"
8717 * $, = ','
8718 * f.rewind
8719 * f.print(*objects)
8720 * f.rewind
8721 * p f.read
8722 *
8723 * Output:
8724 *
8725 * "0,0.0,0/1,0+0i,zero,zero\n"
8726 *
8727 * With no argument given, writes the content of <tt>$_</tt>
8728 * (which is usually the most recent user input):
8729 *
8730 * f = File.open('t.tmp', 'w+')
8731 * gets # Sets $_ to the most recent user input.
8732 * f.print
8733 * f.close
8734 *
8735 */
8736
8737VALUE
8738rb_io_print(int argc, const VALUE *argv, VALUE out)
8739{
8740 int i;
8741 VALUE line;
8742
8743 /* if no argument given, print `$_' */
8744 if (argc == 0) {
8745 argc = 1;
8746 line = rb_lastline_get();
8747 argv = &line;
8748 }
8749 if (argc > 1 && !NIL_P(rb_output_fs)) {
8750 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8751 }
8752 for (i=0; i<argc; i++) {
8753 if (!NIL_P(rb_output_fs) && i>0) {
8754 rb_io_write(out, rb_output_fs);
8755 }
8756 rb_io_write(out, argv[i]);
8757 }
8758 if (argc > 0 && !NIL_P(rb_output_rs)) {
8759 rb_io_write(out, rb_output_rs);
8760 }
8761
8762 return Qnil;
8763}
8764
8765/*
8766 * call-seq:
8767 * print(*objects) -> nil
8768 *
8769 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8770 * this method is the straightforward way to write to <tt>$stdout</tt>.
8771 *
8772 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8773 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8774 * <tt>$\</tt>), if it is not +nil+.
8775 *
8776 * With argument +objects+ given, for each object:
8777 *
8778 * - Converts via its method +to_s+ if not a string.
8779 * - Writes to <tt>stdout</tt>.
8780 * - If not the last object, writes the output field separator
8781 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8782 *
8783 * With default separators:
8784 *
8785 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8786 * $OUTPUT_RECORD_SEPARATOR
8787 * $OUTPUT_FIELD_SEPARATOR
8788 * print(*objects)
8789 *
8790 * Output:
8791 *
8792 * nil
8793 * nil
8794 * 00.00/10+0izerozero
8795 *
8796 * With specified separators:
8797 *
8798 * $OUTPUT_RECORD_SEPARATOR = "\n"
8799 * $OUTPUT_FIELD_SEPARATOR = ','
8800 * print(*objects)
8801 *
8802 * Output:
8803 *
8804 * 0,0.0,0/1,0+0i,zero,zero
8805 *
8806 * With no argument given, writes the content of <tt>$_</tt>
8807 * (which is usually the most recent user input):
8808 *
8809 * gets # Sets $_ to the most recent user input.
8810 * print # Prints $_.
8811 *
8812 */
8813
8814static VALUE
8815rb_f_print(int argc, const VALUE *argv, VALUE _)
8816{
8817 rb_io_print(argc, argv, rb_ractor_stdout());
8818 return Qnil;
8819}
8820
8821/*
8822 * call-seq:
8823 * putc(object) -> object
8824 *
8825 * Writes a character to the stream.
8826 * See {Character IO}[rdoc-ref:IO@Character+IO].
8827 *
8828 * If +object+ is numeric, converts to integer if necessary,
8829 * then writes the character whose code is the
8830 * least significant byte;
8831 * if +object+ is a string, writes the first character:
8832 *
8833 * $stdout.putc "A"
8834 * $stdout.putc 65
8835 *
8836 * Output:
8837 *
8838 * AA
8839 *
8840 */
8841
8842static VALUE
8843rb_io_putc(VALUE io, VALUE ch)
8844{
8845 VALUE str;
8846 if (RB_TYPE_P(ch, T_STRING)) {
8847 str = rb_str_substr(ch, 0, 1);
8848 }
8849 else {
8850 char c = NUM2CHR(ch);
8851 str = rb_str_new(&c, 1);
8852 }
8853 rb_io_write(io, str);
8854 return ch;
8855}
8856
8857#define forward(obj, id, argc, argv) \
8858 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8859#define forward_public(obj, id, argc, argv) \
8860 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8861#define forward_current(id, argc, argv) \
8862 forward_public(ARGF.current_file, id, argc, argv)
8863
8864/*
8865 * call-seq:
8866 * putc(int) -> int
8867 *
8868 * Equivalent to:
8869 *
8870 * $stdout.putc(int)
8871 *
8872 * See IO#putc for important information regarding multi-byte characters.
8873 *
8874 */
8875
8876static VALUE
8877rb_f_putc(VALUE recv, VALUE ch)
8878{
8879 VALUE r_stdout = rb_ractor_stdout();
8880 if (recv == r_stdout) {
8881 return rb_io_putc(recv, ch);
8882 }
8883 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8884}
8885
8886
8887int
8888rb_str_end_with_asciichar(VALUE str, int c)
8889{
8890 long len = RSTRING_LEN(str);
8891 const char *ptr = RSTRING_PTR(str);
8892 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8893 int n;
8894
8895 if (len == 0) return 0;
8896 if ((n = rb_enc_mbminlen(enc)) == 1) {
8897 return ptr[len - 1] == c;
8898 }
8899 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8900}
8901
8902static VALUE
8903io_puts_ary(VALUE ary, VALUE out, int recur)
8904{
8905 VALUE tmp;
8906 long i;
8907
8908 if (recur) {
8909 tmp = rb_str_new2("[...]");
8910 rb_io_puts(1, &tmp, out);
8911 return Qtrue;
8912 }
8913 ary = rb_check_array_type(ary);
8914 if (NIL_P(ary)) return Qfalse;
8915 for (i=0; i<RARRAY_LEN(ary); i++) {
8916 tmp = RARRAY_AREF(ary, i);
8917 rb_io_puts(1, &tmp, out);
8918 }
8919 return Qtrue;
8920}
8921
8922/*
8923 * call-seq:
8924 * puts(*objects) -> nil
8925 *
8926 * Writes the given +objects+ to the stream, which must be open for writing;
8927 * returns +nil+.\
8928 * Writes a newline after each that does not already end with a newline sequence.
8929 * If called without arguments, writes a newline.
8930 * See {Line IO}[rdoc-ref:IO@Line+IO].
8931 *
8932 * Note that each added newline is the character <tt>"\n"<//tt>,
8933 * not the output record separator (<tt>$\</tt>).
8934 *
8935 * Treatment for each object:
8936 *
8937 * - String: writes the string.
8938 * - Neither string nor array: writes <tt>object.to_s</tt>.
8939 * - Array: writes each element of the array; arrays may be nested.
8940 *
8941 * To keep these examples brief, we define this helper method:
8942 *
8943 * def show(*objects)
8944 * # Puts objects to file.
8945 * f = File.new('t.tmp', 'w+')
8946 * f.puts(objects)
8947 * # Return file content.
8948 * f.rewind
8949 * p f.read
8950 * f.close
8951 * end
8952 *
8953 * # Strings without newlines.
8954 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8955 * # Strings, some with newlines.
8956 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8957 *
8958 * # Neither strings nor arrays:
8959 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8960 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8961 *
8962 * # Array of strings.
8963 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8964 * # Nested arrays.
8965 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8966 *
8967 */
8968
8969VALUE
8970rb_io_puts(int argc, const VALUE *argv, VALUE out)
8971{
8972 VALUE line, args[2];
8973
8974 /* if no argument given, print newline. */
8975 if (argc == 0) {
8976 rb_io_write(out, rb_default_rs);
8977 return Qnil;
8978 }
8979 for (int i = 0; i < argc; i++) {
8980 // Convert the argument to a string:
8981 if (RB_TYPE_P(argv[i], T_STRING)) {
8982 line = argv[i];
8983 }
8984 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8985 continue;
8986 }
8987 else {
8988 line = rb_obj_as_string(argv[i]);
8989 }
8990
8991 // Write the line:
8992 int n = 0;
8993 if (RSTRING_LEN(line) == 0) {
8994 args[n++] = rb_default_rs;
8995 }
8996 else {
8997 args[n++] = line;
8998 if (!rb_str_end_with_asciichar(line, '\n')) {
8999 args[n++] = rb_default_rs;
9000 }
9001 }
9002
9003 rb_io_writev(out, n, args);
9004 }
9005
9006 return Qnil;
9007}
9008
9009/*
9010 * call-seq:
9011 * puts(*objects) -> nil
9012 *
9013 * Equivalent to
9014 *
9015 * $stdout.puts(objects)
9016 */
9017
9018static VALUE
9019rb_f_puts(int argc, VALUE *argv, VALUE recv)
9020{
9021 VALUE r_stdout = rb_ractor_stdout();
9022 if (recv == r_stdout) {
9023 return rb_io_puts(argc, argv, recv);
9024 }
9025 return forward(r_stdout, rb_intern("puts"), argc, argv);
9026}
9027
9028static VALUE
9029rb_p_write(VALUE str)
9030{
9031 VALUE args[2];
9032 args[0] = str;
9033 args[1] = rb_default_rs;
9034 VALUE r_stdout = rb_ractor_stdout();
9035 if (RB_TYPE_P(r_stdout, T_FILE) &&
9036 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9037 io_writev(2, args, r_stdout);
9038 }
9039 else {
9040 rb_io_writev(r_stdout, 2, args);
9041 }
9042 return Qnil;
9043}
9044
9045void
9046rb_p(VALUE obj) /* for debug print within C code */
9047{
9048 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9049}
9050
9051static VALUE
9052rb_p_result(int argc, const VALUE *argv)
9053{
9054 VALUE ret = Qnil;
9055
9056 if (argc == 1) {
9057 ret = argv[0];
9058 }
9059 else if (argc > 1) {
9060 ret = rb_ary_new4(argc, argv);
9061 }
9062 VALUE r_stdout = rb_ractor_stdout();
9063 if (RB_TYPE_P(r_stdout, T_FILE)) {
9064 rb_uninterruptible(rb_io_flush, r_stdout);
9065 }
9066 return ret;
9067}
9068
9069/*
9070 * call-seq:
9071 * p(object) -> obj
9072 * p(*objects) -> array of objects
9073 * p -> nil
9074 *
9075 * For each object +obj+, executes:
9076 *
9077 * $stdout.write(obj.inspect, "\n")
9078 *
9079 * With one object given, returns the object;
9080 * with multiple objects given, returns an array containing the objects;
9081 * with no object given, returns +nil+.
9082 *
9083 * Examples:
9084 *
9085 * r = Range.new(0, 4)
9086 * p r # => 0..4
9087 * p [r, r, r] # => [0..4, 0..4, 0..4]
9088 * p # => nil
9089 *
9090 * Output:
9091 *
9092 * 0..4
9093 * [0..4, 0..4, 0..4]
9094 *
9095 * Kernel#p is designed for debugging purposes.
9096 * Ruby implementations may define Kernel#p to be uninterruptible
9097 * in whole or in part.
9098 * On CRuby, Kernel#p's writing of data is uninterruptible.
9099 */
9100
9101static VALUE
9102rb_f_p(int argc, VALUE *argv, VALUE self)
9103{
9104 int i;
9105 for (i=0; i<argc; i++) {
9106 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9107 rb_uninterruptible(rb_p_write, inspected);
9108 }
9109 return rb_p_result(argc, argv);
9110}
9111
9112/*
9113 * call-seq:
9114 * display(port = $>) -> nil
9115 *
9116 * Writes +self+ on the given port:
9117 *
9118 * 1.display
9119 * "cat".display
9120 * [ 4, 5, 6 ].display
9121 * puts
9122 *
9123 * Output:
9124 *
9125 * 1cat[4, 5, 6]
9126 *
9127 */
9128
9129static VALUE
9130rb_obj_display(int argc, VALUE *argv, VALUE self)
9131{
9132 VALUE out;
9133
9134 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9135 rb_io_write(out, self);
9136
9137 return Qnil;
9138}
9139
9140static int
9141rb_stderr_to_original_p(VALUE err)
9142{
9143 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9144}
9145
9146void
9147rb_write_error2(const char *mesg, long len)
9148{
9149 VALUE out = rb_ractor_stderr();
9150 if (rb_stderr_to_original_p(out)) {
9151#ifdef _WIN32
9152 if (isatty(fileno(stderr))) {
9153 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9154 }
9155#endif
9156 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9157 /* failed to write to stderr, what can we do? */
9158 return;
9159 }
9160 }
9161 else {
9162 rb_io_write(out, rb_str_new(mesg, len));
9163 }
9164}
9165
9166void
9167rb_write_error(const char *mesg)
9168{
9169 rb_write_error2(mesg, strlen(mesg));
9170}
9171
9172void
9173rb_write_error_str(VALUE mesg)
9174{
9175 VALUE out = rb_ractor_stderr();
9176 /* a stopgap measure for the time being */
9177 if (rb_stderr_to_original_p(out)) {
9178 size_t len = (size_t)RSTRING_LEN(mesg);
9179#ifdef _WIN32
9180 if (isatty(fileno(stderr))) {
9181 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9182 }
9183#endif
9184 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9185 RB_GC_GUARD(mesg);
9186 return;
9187 }
9188 }
9189 else {
9190 /* may unlock GVL, and */
9191 rb_io_write(out, mesg);
9192 }
9193}
9194
9195int
9196rb_stderr_tty_p(void)
9197{
9198 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9199 return isatty(fileno(stderr));
9200 return 0;
9201}
9202
9203static void
9204must_respond_to(ID mid, VALUE val, ID id)
9205{
9206 if (!rb_respond_to(val, mid)) {
9207 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9208 rb_id2str(id), rb_id2str(mid),
9209 rb_obj_class(val));
9210 }
9211}
9212
9213static void
9214stdin_setter(VALUE val, ID id, VALUE *ptr)
9215{
9217}
9218
9219static VALUE
9220stdin_getter(ID id, VALUE *ptr)
9221{
9222 return rb_ractor_stdin();
9223}
9224
9225static void
9226stdout_setter(VALUE val, ID id, VALUE *ptr)
9227{
9228 must_respond_to(id_write, val, id);
9230}
9231
9232static VALUE
9233stdout_getter(ID id, VALUE *ptr)
9234{
9235 return rb_ractor_stdout();
9236}
9237
9238static void
9239stderr_setter(VALUE val, ID id, VALUE *ptr)
9240{
9241 must_respond_to(id_write, val, id);
9243}
9244
9245static VALUE
9246stderr_getter(ID id, VALUE *ptr)
9247{
9248 return rb_ractor_stderr();
9249}
9250
9251static VALUE
9252allocate_and_open_new_file(VALUE klass)
9253{
9254 VALUE self = io_alloc(klass);
9255 rb_io_make_open_file(self);
9256 return self;
9257}
9258
9259VALUE
9260rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9261{
9262 int state;
9263 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9264 if (state) {
9265 /* if we raised an exception allocating an IO object, but the caller
9266 intended to transfer ownership of this FD to us, close the fd before
9267 raising the exception. Otherwise, we would leak a FD - the caller
9268 expects GC to close the file, but we never got around to assigning
9269 it to a rb_io. */
9270 if (!(mode & FMODE_EXTERNAL)) {
9271 maygvl_close(descriptor, 0);
9272 }
9273 rb_jump_tag(state);
9274 }
9275
9276
9277 rb_io_t *io = RFILE(self)->fptr;
9278 io->self = self;
9279 io->fd = descriptor;
9280 io->mode = mode;
9281
9282 /* At this point, Ruby fully owns the descriptor, and will close it when
9283 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9284 in the rest of this method. */
9285
9286 if (NIL_P(path)) {
9287 io->pathv = Qnil;
9288 }
9289 else {
9290 StringValue(path);
9291 io->pathv = rb_str_new_frozen(path);
9292 }
9293
9294 io->timeout = timeout;
9295
9296 if (encoding) {
9297 io->encs = *encoding;
9298 }
9299
9300 rb_update_max_fd(descriptor);
9301
9302 return self;
9303}
9304
9305static VALUE
9306prep_io(int fd, int fmode, VALUE klass, const char *path)
9307{
9308 VALUE path_value = Qnil;
9309 rb_encoding *e;
9310 struct rb_io_encoding convconfig;
9311
9312 if (path) {
9313 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9314 }
9315
9316 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9317 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9318 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9321#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9322 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9323 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9324 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9325#endif
9326 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9327 convconfig.ecopts = Qnil;
9328
9329 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9330 rb_io_t*io = RFILE(self)->fptr;
9331
9332 if (!io_check_tty(io)) {
9333#ifdef __CYGWIN__
9334 io->mode |= FMODE_BINMODE;
9335 setmode(fd, O_BINARY);
9336#endif
9337 }
9338
9339 return self;
9340}
9341
9342VALUE
9343rb_io_fdopen(int fd, int oflags, const char *path)
9344{
9345 VALUE klass = rb_cIO;
9346
9347 if (path && strcmp(path, "-")) klass = rb_cFile;
9348 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9349}
9350
9351static VALUE
9352prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
9353{
9354 rb_io_t *fptr;
9355 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9356
9357 GetOpenFile(io, fptr);
9359#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9360 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9361 if (fmode & FMODE_READABLE) {
9363 }
9364#endif
9365 fptr->stdio_file = f;
9366
9367 return io;
9368}
9369
9370VALUE
9371rb_io_prep_stdin(void)
9372{
9373 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9374}
9375
9376VALUE
9377rb_io_prep_stdout(void)
9378{
9379 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9380}
9381
9382VALUE
9383rb_io_prep_stderr(void)
9384{
9385 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9386}
9387
9388FILE *
9389rb_io_stdio_file(rb_io_t *fptr)
9390{
9391 if (!fptr->stdio_file) {
9392 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9393 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9394 }
9395 return fptr->stdio_file;
9396}
9397
9398static inline void
9399rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9400{
9401 buf->ptr = NULL;
9402 buf->off = 0;
9403 buf->len = 0;
9404 buf->capa = 0;
9405}
9406
9407static inline rb_io_t *
9408rb_io_fptr_new(void)
9409{
9410 rb_io_t *fp = ALLOC(rb_io_t);
9411 fp->self = Qnil;
9412 fp->fd = -1;
9413 fp->stdio_file = NULL;
9414 fp->mode = 0;
9415 fp->pid = 0;
9416 fp->lineno = 0;
9417 fp->pathv = Qnil;
9418 fp->finalize = 0;
9419 rb_io_buffer_init(&fp->wbuf);
9420 rb_io_buffer_init(&fp->rbuf);
9421 rb_io_buffer_init(&fp->cbuf);
9422 fp->readconv = NULL;
9423 fp->writeconv = NULL;
9425 fp->writeconv_pre_ecflags = 0;
9427 fp->writeconv_initialized = 0;
9428 fp->tied_io_for_writing = 0;
9429 fp->encs.enc = NULL;
9430 fp->encs.enc2 = NULL;
9431 fp->encs.ecflags = 0;
9432 fp->encs.ecopts = Qnil;
9433 fp->write_lock = Qnil;
9434 fp->timeout = Qnil;
9435 return fp;
9436}
9437
9438rb_io_t *
9439rb_io_make_open_file(VALUE obj)
9440{
9441 rb_io_t *fp = 0;
9442
9443 Check_Type(obj, T_FILE);
9444 if (RFILE(obj)->fptr) {
9445 rb_io_close(obj);
9446 rb_io_fptr_finalize(RFILE(obj)->fptr);
9447 RFILE(obj)->fptr = 0;
9448 }
9449 fp = rb_io_fptr_new();
9450 fp->self = obj;
9451 RFILE(obj)->fptr = fp;
9452 return fp;
9453}
9454
9455static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9456
9457/*
9458 * call-seq:
9459 * IO.new(fd, mode = 'r', **opts) -> io
9460 *
9461 * Creates and returns a new \IO object (file stream) from a file descriptor.
9462 *
9463 * \IO.new may be useful for interaction with low-level libraries.
9464 * For higher-level interactions, it may be simpler to create
9465 * the file stream using File.open.
9466 *
9467 * Argument +fd+ must be a valid file descriptor (integer):
9468 *
9469 * path = 't.tmp'
9470 * fd = IO.sysopen(path) # => 3
9471 * IO.new(fd) # => #<IO:fd 3>
9472 *
9473 * The new \IO object does not inherit encoding
9474 * (because the integer file descriptor does not have an encoding):
9475 *
9476 * fd = IO.sysopen('t.rus', 'rb')
9477 * io = IO.new(fd)
9478 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9479 *
9480 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9481 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9482 *
9483 * IO.new(fd, 'w') # => #<IO:fd 3>
9484 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9485 *
9486 * Optional keyword arguments +opts+ specify:
9487 *
9488 * - {Open Options}[rdoc-ref:IO@Open+Options].
9489 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9490 *
9491 * Examples:
9492 *
9493 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9494 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9495 *
9496 */
9497
9498static VALUE
9499rb_io_initialize(int argc, VALUE *argv, VALUE io)
9500{
9501 VALUE fnum, vmode;
9502 VALUE opt;
9503
9504 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9505 return io_initialize(io, fnum, vmode, opt);
9506}
9507
9508static VALUE
9509io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9510{
9511 rb_io_t *fp;
9512 int fd, fmode, oflags = O_RDONLY;
9513 struct rb_io_encoding convconfig;
9514#if defined(HAVE_FCNTL) && defined(F_GETFL)
9515 int ofmode;
9516#else
9517 struct stat st;
9518#endif
9519
9520 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9521
9522 fd = NUM2INT(fnum);
9523 if (rb_reserved_fd_p(fd)) {
9524 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9525 }
9526#if defined(HAVE_FCNTL) && defined(F_GETFL)
9527 oflags = fcntl(fd, F_GETFL);
9528 if (oflags == -1) rb_sys_fail(0);
9529#else
9530 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9531#endif
9532 rb_update_max_fd(fd);
9533#if defined(HAVE_FCNTL) && defined(F_GETFL)
9534 ofmode = rb_io_oflags_fmode(oflags);
9535 if (NIL_P(vmode)) {
9536 fmode = ofmode;
9537 }
9538 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9539 VALUE error = INT2FIX(EINVAL);
9540 rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
9541 }
9542#endif
9543 VALUE path = Qnil;
9544
9545 if (!NIL_P(opt)) {
9546 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9547 fmode |= FMODE_EXTERNAL;
9548 }
9549
9550 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9551 if (!NIL_P(path)) {
9552 StringValue(path);
9553 path = rb_str_new_frozen(path);
9554 }
9555 }
9556
9557 MakeOpenFile(io, fp);
9558 fp->self = io;
9559 fp->fd = fd;
9560 fp->mode = fmode;
9561 fp->encs = convconfig;
9562 fp->pathv = path;
9563 fp->timeout = Qnil;
9564 clear_codeconv(fp);
9565 io_check_tty(fp);
9566 if (fileno(stdin) == fd)
9567 fp->stdio_file = stdin;
9568 else if (fileno(stdout) == fd)
9569 fp->stdio_file = stdout;
9570 else if (fileno(stderr) == fd)
9571 fp->stdio_file = stderr;
9572
9573 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9574 return io;
9575}
9576
9577/*
9578 * call-seq:
9579 * set_encoding_by_bom -> encoding or nil
9580 *
9581 * If the stream begins with a BOM
9582 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9583 * consumes the BOM and sets the external encoding accordingly;
9584 * returns the result encoding if found, or +nil+ otherwise:
9585 *
9586 * File.write('t.tmp', "\u{FEFF}abc")
9587 * io = File.open('t.tmp', 'rb')
9588 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9589 * io.close
9590 *
9591 * File.write('t.tmp', 'abc')
9592 * io = File.open('t.tmp', 'rb')
9593 * io.set_encoding_by_bom # => nil
9594 * io.close
9595 *
9596 * Raises an exception if the stream is not binmode
9597 * or its encoding has already been set.
9598 *
9599 */
9600
9601static VALUE
9602rb_io_set_encoding_by_bom(VALUE io)
9603{
9604 rb_io_t *fptr;
9605
9606 GetOpenFile(io, fptr);
9607 if (!(fptr->mode & FMODE_BINMODE)) {
9608 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9609 }
9610 if (fptr->encs.enc2) {
9611 rb_raise(rb_eArgError, "encoding conversion is set");
9612 }
9613 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9614 rb_raise(rb_eArgError, "encoding is set to %s already",
9615 rb_enc_name(fptr->encs.enc));
9616 }
9617 if (!io_set_encoding_by_bom(io)) return Qnil;
9618 return rb_enc_from_encoding(fptr->encs.enc);
9619}
9620
9621/*
9622 * call-seq:
9623 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9624 *
9625 * Opens the file at the given +path+ according to the given +mode+;
9626 * creates and returns a new File object for that file.
9627 *
9628 * The new File object is buffered mode (or non-sync mode), unless
9629 * +filename+ is a tty.
9630 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9631 *
9632 * Argument +path+ must be a valid file path:
9633 *
9634 * f = File.new('/etc/fstab')
9635 * f.close
9636 * f = File.new('t.txt')
9637 * f.close
9638 *
9639 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9640 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9641 *
9642 * f = File.new('t.tmp', 'w')
9643 * f.close
9644 * f = File.new('t.tmp', File::RDONLY)
9645 * f.close
9646 *
9647 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9648 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9649 *
9650 * f = File.new('t.tmp', File::CREAT, 0644)
9651 * f.close
9652 * f = File.new('t.tmp', File::CREAT, 0444)
9653 * f.close
9654 *
9655 * Optional keyword arguments +opts+ specify:
9656 *
9657 * - {Open Options}[rdoc-ref:IO@Open+Options].
9658 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9659 *
9660 */
9661
9662static VALUE
9663rb_file_initialize(int argc, VALUE *argv, VALUE io)
9664{
9665 if (RFILE(io)->fptr) {
9666 rb_raise(rb_eRuntimeError, "reinitializing File");
9667 }
9668 VALUE fname, vmode, vperm, opt;
9669 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9670 if (posargc < 3) { /* perm is File only */
9671 VALUE fd = rb_check_to_int(fname);
9672
9673 if (!NIL_P(fd)) {
9674 return io_initialize(io, fd, vmode, opt);
9675 }
9676 }
9677 return rb_open_file(io, fname, vmode, vperm, opt);
9678}
9679
9680/* :nodoc: */
9681static VALUE
9682rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9683{
9684 if (rb_block_given_p()) {
9685 VALUE cname = rb_obj_as_string(klass);
9686
9687 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9688 cname, cname);
9689 }
9690 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9691}
9692
9693
9694/*
9695 * call-seq:
9696 * IO.for_fd(fd, mode = 'r', **opts) -> io
9697 *
9698 * Synonym for IO.new.
9699 *
9700 */
9701
9702static VALUE
9703rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9704{
9705 VALUE io = rb_obj_alloc(klass);
9706 rb_io_initialize(argc, argv, io);
9707 return io;
9708}
9709
9710/*
9711 * call-seq:
9712 * ios.autoclose? -> true or false
9713 *
9714 * Returns +true+ if the underlying file descriptor of _ios_ will be
9715 * closed at its finalization or at calling #close, otherwise +false+.
9716 */
9717
9718static VALUE
9719rb_io_autoclose_p(VALUE io)
9720{
9721 rb_io_t *fptr = RFILE(io)->fptr;
9722 rb_io_check_closed(fptr);
9723 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9724}
9725
9726/*
9727 * call-seq:
9728 * io.autoclose = bool -> true or false
9729 *
9730 * Sets auto-close flag.
9731 *
9732 * f = File.open(File::NULL)
9733 * IO.for_fd(f.fileno).close
9734 * f.gets # raises Errno::EBADF
9735 *
9736 * f = File.open(File::NULL)
9737 * g = IO.for_fd(f.fileno)
9738 * g.autoclose = false
9739 * g.close
9740 * f.gets # won't cause Errno::EBADF
9741 */
9742
9743static VALUE
9744rb_io_set_autoclose(VALUE io, VALUE autoclose)
9745{
9746 rb_io_t *fptr;
9747 GetOpenFile(io, fptr);
9748 if (!RTEST(autoclose))
9749 fptr->mode |= FMODE_EXTERNAL;
9750 else
9751 fptr->mode &= ~FMODE_EXTERNAL;
9752 return autoclose;
9753}
9754
9755static VALUE
9756io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9757{
9758 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9759
9760 if (!RB_TEST(result)) {
9761 return Qnil;
9762 }
9763
9764 int mask = RB_NUM2INT(result);
9765
9766 if (mask & event) {
9767 if (return_io)
9768 return io;
9769 else
9770 return result;
9771 }
9772 else {
9773 return Qfalse;
9774 }
9775}
9776
9777/*
9778 * call-seq:
9779 * io.wait_readable -> truthy or falsy
9780 * io.wait_readable(timeout) -> truthy or falsy
9781 *
9782 * Waits until IO is readable and returns a truthy value, or a falsy
9783 * value when times out. Returns a truthy value immediately when
9784 * buffered data is available.
9785 */
9786
9787static VALUE
9788io_wait_readable(int argc, VALUE *argv, VALUE io)
9789{
9790 rb_io_t *fptr;
9791
9792 RB_IO_POINTER(io, fptr);
9794
9795 if (rb_io_read_pending(fptr)) return Qtrue;
9796
9797 rb_check_arity(argc, 0, 1);
9798 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9799
9800 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9801}
9802
9803/*
9804 * call-seq:
9805 * io.wait_writable -> truthy or falsy
9806 * io.wait_writable(timeout) -> truthy or falsy
9807 *
9808 * Waits until IO is writable and returns a truthy value or a falsy
9809 * value when times out.
9810 */
9811static VALUE
9812io_wait_writable(int argc, VALUE *argv, VALUE io)
9813{
9814 rb_io_t *fptr;
9815
9816 RB_IO_POINTER(io, fptr);
9818
9819 rb_check_arity(argc, 0, 1);
9820 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9821
9822 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9823}
9824
9825/*
9826 * call-seq:
9827 * io.wait_priority -> truthy or falsy
9828 * io.wait_priority(timeout) -> truthy or falsy
9829 *
9830 * Waits until IO is priority and returns a truthy value or a falsy
9831 * value when times out. Priority data is sent and received using
9832 * the Socket::MSG_OOB flag and is typically limited to streams.
9833 */
9834static VALUE
9835io_wait_priority(int argc, VALUE *argv, VALUE io)
9836{
9837 rb_io_t *fptr = NULL;
9838
9839 RB_IO_POINTER(io, fptr);
9841
9842 if (rb_io_read_pending(fptr)) return Qtrue;
9843
9844 rb_check_arity(argc, 0, 1);
9845 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9846
9847 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9848}
9849
9850static int
9851wait_mode_sym(VALUE mode)
9852{
9853 if (mode == ID2SYM(rb_intern("r"))) {
9854 return RB_WAITFD_IN;
9855 }
9856 if (mode == ID2SYM(rb_intern("read"))) {
9857 return RB_WAITFD_IN;
9858 }
9859 if (mode == ID2SYM(rb_intern("readable"))) {
9860 return RB_WAITFD_IN;
9861 }
9862 if (mode == ID2SYM(rb_intern("w"))) {
9863 return RB_WAITFD_OUT;
9864 }
9865 if (mode == ID2SYM(rb_intern("write"))) {
9866 return RB_WAITFD_OUT;
9867 }
9868 if (mode == ID2SYM(rb_intern("writable"))) {
9869 return RB_WAITFD_OUT;
9870 }
9871 if (mode == ID2SYM(rb_intern("rw"))) {
9872 return RB_WAITFD_IN|RB_WAITFD_OUT;
9873 }
9874 if (mode == ID2SYM(rb_intern("read_write"))) {
9875 return RB_WAITFD_IN|RB_WAITFD_OUT;
9876 }
9877 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9878 return RB_WAITFD_IN|RB_WAITFD_OUT;
9879 }
9880
9881 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9882}
9883
9884static inline enum rb_io_event
9885io_event_from_value(VALUE value)
9886{
9887 int events = RB_NUM2INT(value);
9888
9889 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9890
9891 return events;
9892}
9893
9894/*
9895 * call-seq:
9896 * io.wait(events, timeout) -> event mask, false or nil
9897 * io.wait(timeout = nil, mode = :read) -> self, true, or false
9898 *
9899 * Waits until the IO becomes ready for the specified events and returns the
9900 * subset of events that become ready, or a falsy value when times out.
9901 *
9902 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9903 * +IO::PRIORITY+.
9904 *
9905 * Returns an event mask (truthy value) immediately when buffered data is available.
9906 *
9907 * Optional parameter +mode+ is one of +:read+, +:write+, or
9908 * +:read_write+.
9909 */
9910
9911static VALUE
9912io_wait(int argc, VALUE *argv, VALUE io)
9913{
9914 VALUE timeout = Qundef;
9915 enum rb_io_event events = 0;
9916 int return_io = 0;
9917
9918 // The documented signature for this method is actually incorrect.
9919 // A single timeout is allowed in any position, and multiple symbols can be given.
9920 // Whether this is intentional or not, I don't know, and as such I consider this to
9921 // be a legacy/slow path.
9922 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9923 // We'd prefer to return the actual mask, but this form would return the io itself:
9924 return_io = 1;
9925
9926 // Slow/messy path:
9927 for (int i = 0; i < argc; i += 1) {
9928 if (RB_SYMBOL_P(argv[i])) {
9929 events |= wait_mode_sym(argv[i]);
9930 }
9931 else if (UNDEF_P(timeout)) {
9932 rb_time_interval(timeout = argv[i]);
9933 }
9934 else {
9935 rb_raise(rb_eArgError, "timeout given more than once");
9936 }
9937 }
9938
9939 if (UNDEF_P(timeout)) timeout = Qnil;
9940
9941 if (events == 0) {
9942 events = RUBY_IO_READABLE;
9943 }
9944 }
9945 else /* argc == 2 and neither are symbols */ {
9946 // This is the fast path:
9947 events = io_event_from_value(argv[0]);
9948 timeout = argv[1];
9949 }
9950
9951 if (events & RUBY_IO_READABLE) {
9952 rb_io_t *fptr = NULL;
9953 RB_IO_POINTER(io, fptr);
9954
9955 if (rb_io_read_pending(fptr)) {
9956 // This was the original behaviour:
9957 if (return_io) return Qtrue;
9958 // New behaviour always returns an event mask:
9959 else return RB_INT2NUM(RUBY_IO_READABLE);
9960 }
9961 }
9962
9963 return io_wait_event(io, events, timeout, return_io);
9964}
9965
9966static void
9967argf_mark(void *ptr)
9968{
9969 struct argf *p = ptr;
9970 rb_gc_mark(p->filename);
9971 rb_gc_mark(p->current_file);
9972 rb_gc_mark(p->argv);
9973 rb_gc_mark(p->inplace);
9974 rb_gc_mark(p->encs.ecopts);
9975}
9976
9977static size_t
9978argf_memsize(const void *ptr)
9979{
9980 const struct argf *p = ptr;
9981 size_t size = sizeof(*p);
9982 return size;
9983}
9984
9985static const rb_data_type_t argf_type = {
9986 "ARGF",
9987 {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize},
9988 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9989};
9990
9991static inline void
9992argf_init(struct argf *p, VALUE v)
9993{
9994 p->filename = Qnil;
9995 p->current_file = Qnil;
9996 p->lineno = 0;
9997 p->argv = v;
9998}
9999
10000static VALUE
10001argf_alloc(VALUE klass)
10002{
10003 struct argf *p;
10004 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10005
10006 argf_init(p, Qnil);
10007 return argf;
10008}
10009
10010#undef rb_argv
10011
10012/* :nodoc: */
10013static VALUE
10014argf_initialize(VALUE argf, VALUE argv)
10015{
10016 memset(&ARGF, 0, sizeof(ARGF));
10017 argf_init(&ARGF, argv);
10018
10019 return argf;
10020}
10021
10022/* :nodoc: */
10023static VALUE
10024argf_initialize_copy(VALUE argf, VALUE orig)
10025{
10026 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10027 ARGF = argf_of(orig);
10028 ARGF.argv = rb_obj_dup(ARGF.argv);
10029 return argf;
10030}
10031
10032/*
10033 * call-seq:
10034 * ARGF.lineno = integer -> integer
10035 *
10036 * Sets the line number of ARGF as a whole to the given Integer.
10037 *
10038 * ARGF sets the line number automatically as you read data, so normally
10039 * you will not need to set it explicitly. To access the current line number
10040 * use ARGF.lineno.
10041 *
10042 * For example:
10043 *
10044 * ARGF.lineno #=> 0
10045 * ARGF.readline #=> "This is line 1\n"
10046 * ARGF.lineno #=> 1
10047 * ARGF.lineno = 0 #=> 0
10048 * ARGF.lineno #=> 0
10049 */
10050static VALUE
10051argf_set_lineno(VALUE argf, VALUE val)
10052{
10053 ARGF.lineno = NUM2INT(val);
10054 ARGF.last_lineno = ARGF.lineno;
10055 return val;
10056}
10057
10058/*
10059 * call-seq:
10060 * ARGF.lineno -> integer
10061 *
10062 * Returns the current line number of ARGF as a whole. This value
10063 * can be set manually with ARGF.lineno=.
10064 *
10065 * For example:
10066 *
10067 * ARGF.lineno #=> 0
10068 * ARGF.readline #=> "This is line 1\n"
10069 * ARGF.lineno #=> 1
10070 */
10071static VALUE
10072argf_lineno(VALUE argf)
10073{
10074 return INT2FIX(ARGF.lineno);
10075}
10076
10077static VALUE
10078argf_forward(int argc, VALUE *argv, VALUE argf)
10079{
10080 return forward_current(rb_frame_this_func(), argc, argv);
10081}
10082
10083#define next_argv() argf_next_argv(argf)
10084#define ARGF_GENERIC_INPUT_P() \
10085 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10086#define ARGF_FORWARD(argc, argv) do {\
10087 if (ARGF_GENERIC_INPUT_P())\
10088 return argf_forward((argc), (argv), argf);\
10089} while (0)
10090#define NEXT_ARGF_FORWARD(argc, argv) do {\
10091 if (!next_argv()) return Qnil;\
10092 ARGF_FORWARD((argc), (argv));\
10093} while (0)
10094
10095static void
10096argf_close(VALUE argf)
10097{
10098 VALUE file = ARGF.current_file;
10099 if (file == rb_stdin) return;
10100 if (RB_TYPE_P(file, T_FILE)) {
10101 rb_io_set_write_io(file, Qnil);
10102 }
10103 io_close(file);
10104 ARGF.init_p = -1;
10105}
10106
10107static int
10108argf_next_argv(VALUE argf)
10109{
10110 char *fn;
10111 rb_io_t *fptr;
10112 int stdout_binmode = 0;
10113 int fmode;
10114
10115 VALUE r_stdout = rb_ractor_stdout();
10116
10117 if (RB_TYPE_P(r_stdout, T_FILE)) {
10118 GetOpenFile(r_stdout, fptr);
10119 if (fptr->mode & FMODE_BINMODE)
10120 stdout_binmode = 1;
10121 }
10122
10123 if (ARGF.init_p == 0) {
10124 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10125 ARGF.next_p = 1;
10126 }
10127 else {
10128 ARGF.next_p = -1;
10129 }
10130 ARGF.init_p = 1;
10131 }
10132 else {
10133 if (NIL_P(ARGF.argv)) {
10134 ARGF.next_p = -1;
10135 }
10136 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10137 ARGF.next_p = 1;
10138 }
10139 }
10140
10141 if (ARGF.next_p == 1) {
10142 if (ARGF.init_p == 1) argf_close(argf);
10143 retry:
10144 if (RARRAY_LEN(ARGF.argv) > 0) {
10145 VALUE filename = rb_ary_shift(ARGF.argv);
10146 FilePathValue(filename);
10147 ARGF.filename = filename;
10148 filename = rb_str_encode_ospath(filename);
10149 fn = StringValueCStr(filename);
10150 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10151 ARGF.current_file = rb_stdin;
10152 if (ARGF.inplace) {
10153 rb_warn("Can't do inplace edit for stdio; skipping");
10154 goto retry;
10155 }
10156 }
10157 else {
10158 VALUE write_io = Qnil;
10159 int fr = rb_sysopen(filename, O_RDONLY, 0);
10160
10161 if (ARGF.inplace) {
10162 struct stat st;
10163#ifndef NO_SAFE_RENAME
10164 struct stat st2;
10165#endif
10166 VALUE str;
10167 int fw;
10168
10169 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10170 rb_io_close(r_stdout);
10171 }
10172 fstat(fr, &st);
10173 str = filename;
10174 if (!NIL_P(ARGF.inplace)) {
10175 VALUE suffix = ARGF.inplace;
10176 str = rb_str_dup(str);
10177 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10178 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10179 rb_enc_get(suffix), 0, Qnil))) {
10180 rb_str_append(str, suffix);
10181 }
10182#ifdef NO_SAFE_RENAME
10183 (void)close(fr);
10184 (void)unlink(RSTRING_PTR(str));
10185 if (rename(fn, RSTRING_PTR(str)) < 0) {
10186 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10187 filename, str, strerror(errno));
10188 goto retry;
10189 }
10190 fr = rb_sysopen(str, O_RDONLY, 0);
10191#else
10192 if (rename(fn, RSTRING_PTR(str)) < 0) {
10193 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10194 filename, str, strerror(errno));
10195 close(fr);
10196 goto retry;
10197 }
10198#endif
10199 }
10200 else {
10201#ifdef NO_SAFE_RENAME
10202 rb_fatal("Can't do inplace edit without backup");
10203#else
10204 if (unlink(fn) < 0) {
10205 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10206 filename, strerror(errno));
10207 close(fr);
10208 goto retry;
10209 }
10210#endif
10211 }
10212 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10213#ifndef NO_SAFE_RENAME
10214 fstat(fw, &st2);
10215#ifdef HAVE_FCHMOD
10216 fchmod(fw, st.st_mode);
10217#else
10218 chmod(fn, st.st_mode);
10219#endif
10220 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10221 int err;
10222#ifdef HAVE_FCHOWN
10223 err = fchown(fw, st.st_uid, st.st_gid);
10224#else
10225 err = chown(fn, st.st_uid, st.st_gid);
10226#endif
10227 if (err && getuid() == 0 && st2.st_uid == 0) {
10228 const char *wkfn = RSTRING_PTR(filename);
10229 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10230 filename, str, strerror(errno));
10231 (void)close(fr);
10232 (void)close(fw);
10233 (void)unlink(wkfn);
10234 goto retry;
10235 }
10236 }
10237#endif
10238 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10239 rb_ractor_stdout_set(write_io);
10240 if (stdout_binmode) rb_io_binmode(rb_stdout);
10241 }
10242 fmode = FMODE_READABLE;
10243 if (!ARGF.binmode) {
10244 fmode |= DEFAULT_TEXTMODE;
10245 }
10246 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10247 if (!NIL_P(write_io)) {
10248 rb_io_set_write_io(ARGF.current_file, write_io);
10249 }
10250 RB_GC_GUARD(filename);
10251 }
10252 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10253 GetOpenFile(ARGF.current_file, fptr);
10254 if (ARGF.encs.enc) {
10255 fptr->encs = ARGF.encs;
10256 clear_codeconv(fptr);
10257 }
10258 else {
10260 if (!ARGF.binmode) {
10262#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10263 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10264#endif
10265 }
10266 }
10267 ARGF.next_p = 0;
10268 }
10269 else {
10270 ARGF.next_p = 1;
10271 return FALSE;
10272 }
10273 }
10274 else if (ARGF.next_p == -1) {
10275 ARGF.current_file = rb_stdin;
10276 ARGF.filename = rb_str_new2("-");
10277 if (ARGF.inplace) {
10278 rb_warn("Can't do inplace edit for stdio");
10279 rb_ractor_stdout_set(orig_stdout);
10280 }
10281 }
10282 if (ARGF.init_p == -1) ARGF.init_p = 1;
10283 return TRUE;
10284}
10285
10286static VALUE
10287argf_getline(int argc, VALUE *argv, VALUE argf)
10288{
10289 VALUE line;
10290 long lineno = ARGF.lineno;
10291
10292 retry:
10293 if (!next_argv()) return Qnil;
10294 if (ARGF_GENERIC_INPUT_P()) {
10295 line = forward_current(idGets, argc, argv);
10296 }
10297 else {
10298 if (argc == 0 && rb_rs == rb_default_rs) {
10299 line = rb_io_gets(ARGF.current_file);
10300 }
10301 else {
10302 line = rb_io_getline(argc, argv, ARGF.current_file);
10303 }
10304 if (NIL_P(line) && ARGF.next_p != -1) {
10305 argf_close(argf);
10306 ARGF.next_p = 1;
10307 goto retry;
10308 }
10309 }
10310 if (!NIL_P(line)) {
10311 ARGF.lineno = ++lineno;
10312 ARGF.last_lineno = ARGF.lineno;
10313 }
10314 return line;
10315}
10316
10317static VALUE
10318argf_lineno_getter(ID id, VALUE *var)
10319{
10320 VALUE argf = *var;
10321 return INT2FIX(ARGF.last_lineno);
10322}
10323
10324static void
10325argf_lineno_setter(VALUE val, ID id, VALUE *var)
10326{
10327 VALUE argf = *var;
10328 int n = NUM2INT(val);
10329 ARGF.last_lineno = ARGF.lineno = n;
10330}
10331
10332void
10333rb_reset_argf_lineno(long n)
10334{
10335 ARGF.last_lineno = ARGF.lineno = n;
10336}
10337
10338static VALUE argf_gets(int, VALUE *, VALUE);
10339
10340/*
10341 * call-seq:
10342 * gets(sep=$/ [, getline_args]) -> string or nil
10343 * gets(limit [, getline_args]) -> string or nil
10344 * gets(sep, limit [, getline_args]) -> string or nil
10345 *
10346 * Returns (and assigns to <code>$_</code>) the next line from the list
10347 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10348 * no files are present on the command line. Returns +nil+ at end of
10349 * file. The optional argument specifies the record separator. The
10350 * separator is included with the contents of each record. A separator
10351 * of +nil+ reads the entire contents, and a zero-length separator
10352 * reads the input one paragraph at a time, where paragraphs are
10353 * divided by two consecutive newlines. If the first argument is an
10354 * integer, or optional second argument is given, the returning string
10355 * would not be longer than the given value in bytes. If multiple
10356 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10357 * the contents one file at a time.
10358 *
10359 * ARGV << "testfile"
10360 * print while gets
10361 *
10362 * <em>produces:</em>
10363 *
10364 * This is line one
10365 * This is line two
10366 * This is line three
10367 * And so on...
10368 *
10369 * The style of programming using <code>$_</code> as an implicit
10370 * parameter is gradually losing favor in the Ruby community.
10371 */
10372
10373static VALUE
10374rb_f_gets(int argc, VALUE *argv, VALUE recv)
10375{
10376 if (recv == argf) {
10377 return argf_gets(argc, argv, argf);
10378 }
10379 return forward(argf, idGets, argc, argv);
10380}
10381
10382/*
10383 * call-seq:
10384 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10385 * ARGF.gets(limit [, getline_args]) -> string or nil
10386 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10387 *
10388 * Returns the next line from the current file in ARGF.
10389 *
10390 * By default lines are assumed to be separated by <code>$/</code>;
10391 * to use a different character as a separator, supply it as a String
10392 * for the _sep_ argument.
10393 *
10394 * The optional _limit_ argument specifies how many characters of each line
10395 * to return. By default all characters are returned.
10396 *
10397 * See IO.readlines for details about getline_args.
10398 *
10399 */
10400static VALUE
10401argf_gets(int argc, VALUE *argv, VALUE argf)
10402{
10403 VALUE line;
10404
10405 line = argf_getline(argc, argv, argf);
10406 rb_lastline_set(line);
10407
10408 return line;
10409}
10410
10411VALUE
10413{
10414 VALUE line;
10415
10416 if (rb_rs != rb_default_rs) {
10417 return rb_f_gets(0, 0, argf);
10418 }
10419
10420 retry:
10421 if (!next_argv()) return Qnil;
10422 line = rb_io_gets(ARGF.current_file);
10423 if (NIL_P(line) && ARGF.next_p != -1) {
10424 rb_io_close(ARGF.current_file);
10425 ARGF.next_p = 1;
10426 goto retry;
10427 }
10428 rb_lastline_set(line);
10429 if (!NIL_P(line)) {
10430 ARGF.lineno++;
10431 ARGF.last_lineno = ARGF.lineno;
10432 }
10433
10434 return line;
10435}
10436
10437static VALUE argf_readline(int, VALUE *, VALUE);
10438
10439/*
10440 * call-seq:
10441 * readline(sep = $/, chomp: false) -> string
10442 * readline(limit, chomp: false) -> string
10443 * readline(sep, limit, chomp: false) -> string
10444 *
10445 * Equivalent to method Kernel#gets, except that it raises an exception
10446 * if called at end-of-stream:
10447 *
10448 * $ cat t.txt | ruby -e "p readlines; readline"
10449 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10450 * in `readline': end of file reached (EOFError)
10451 *
10452 * Optional keyword argument +chomp+ specifies whether line separators
10453 * are to be omitted.
10454 */
10455
10456static VALUE
10457rb_f_readline(int argc, VALUE *argv, VALUE recv)
10458{
10459 if (recv == argf) {
10460 return argf_readline(argc, argv, argf);
10461 }
10462 return forward(argf, rb_intern("readline"), argc, argv);
10463}
10464
10465
10466/*
10467 * call-seq:
10468 * ARGF.readline(sep=$/) -> string
10469 * ARGF.readline(limit) -> string
10470 * ARGF.readline(sep, limit) -> string
10471 *
10472 * Returns the next line from the current file in ARGF.
10473 *
10474 * By default lines are assumed to be separated by <code>$/</code>;
10475 * to use a different character as a separator, supply it as a String
10476 * for the _sep_ argument.
10477 *
10478 * The optional _limit_ argument specifies how many characters of each line
10479 * to return. By default all characters are returned.
10480 *
10481 * An EOFError is raised at the end of the file.
10482 */
10483static VALUE
10484argf_readline(int argc, VALUE *argv, VALUE argf)
10485{
10486 VALUE line;
10487
10488 if (!next_argv()) rb_eof_error();
10489 ARGF_FORWARD(argc, argv);
10490 line = argf_gets(argc, argv, argf);
10491 if (NIL_P(line)) {
10492 rb_eof_error();
10493 }
10494
10495 return line;
10496}
10497
10498static VALUE argf_readlines(int, VALUE *, VALUE);
10499
10500/*
10501 * call-seq:
10502 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10503 * readlines(limit, chomp: false, **enc_opts) -> array
10504 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10505 *
10506 * Returns an array containing the lines returned by calling
10507 * Kernel#gets until the end-of-stream is reached;
10508 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10509 *
10510 * With only string argument +sep+ given,
10511 * returns the remaining lines as determined by line separator +sep+,
10512 * or +nil+ if none;
10513 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10514 *
10515 * # Default separator.
10516 * $ cat t.txt | ruby -e "p readlines"
10517 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10518 *
10519 * # Specified separator.
10520 * $ cat t.txt | ruby -e "p readlines 'li'"
10521 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10522 *
10523 * # Get-all separator.
10524 * $ cat t.txt | ruby -e "p readlines nil"
10525 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10526 *
10527 * # Get-paragraph separator.
10528 * $ cat t.txt | ruby -e "p readlines ''"
10529 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10530 *
10531 * With only integer argument +limit+ given,
10532 * limits the number of bytes in the line;
10533 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10534 *
10535 * $cat t.txt | ruby -e "p readlines 10"
10536 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10537 *
10538 * $cat t.txt | ruby -e "p readlines 11"
10539 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10540 *
10541 * $cat t.txt | ruby -e "p readlines 12"
10542 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10543 *
10544 * With arguments +sep+ and +limit+ given,
10545 * combines the two behaviors
10546 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10547 *
10548 * Optional keyword argument +chomp+ specifies whether line separators
10549 * are to be omitted:
10550 *
10551 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10552 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10553 *
10554 * Optional keyword arguments +enc_opts+ specify encoding options;
10555 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10556 *
10557 */
10558
10559static VALUE
10560rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10561{
10562 if (recv == argf) {
10563 return argf_readlines(argc, argv, argf);
10564 }
10565 return forward(argf, rb_intern("readlines"), argc, argv);
10566}
10567
10568/*
10569 * call-seq:
10570 * ARGF.readlines(sep = $/, chomp: false) -> array
10571 * ARGF.readlines(limit, chomp: false) -> array
10572 * ARGF.readlines(sep, limit, chomp: false) -> array
10573 *
10574 * ARGF.to_a(sep = $/, chomp: false) -> array
10575 * ARGF.to_a(limit, chomp: false) -> array
10576 * ARGF.to_a(sep, limit, chomp: false) -> array
10577 *
10578 * Reads each file in ARGF in its entirety, returning an Array containing
10579 * lines from the files. Lines are assumed to be separated by _sep_.
10580 *
10581 * lines = ARGF.readlines
10582 * lines[0] #=> "This is line one\n"
10583 *
10584 * See +IO.readlines+ for a full description of all options.
10585 */
10586static VALUE
10587argf_readlines(int argc, VALUE *argv, VALUE argf)
10588{
10589 long lineno = ARGF.lineno;
10590 VALUE lines, ary;
10591
10592 ary = rb_ary_new();
10593 while (next_argv()) {
10594 if (ARGF_GENERIC_INPUT_P()) {
10595 lines = forward_current(rb_intern("readlines"), argc, argv);
10596 }
10597 else {
10598 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10599 argf_close(argf);
10600 }
10601 ARGF.next_p = 1;
10602 rb_ary_concat(ary, lines);
10603 ARGF.lineno = lineno + RARRAY_LEN(ary);
10604 ARGF.last_lineno = ARGF.lineno;
10605 }
10606 ARGF.init_p = 0;
10607 return ary;
10608}
10609
10610/*
10611 * call-seq:
10612 * `command` -> string
10613 *
10614 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10615 * sets global variable <tt>$?</tt> to the process status.
10616 *
10617 * This method has potential security vulnerabilities if called with untrusted input;
10618 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10619 *
10620 * Examples:
10621 *
10622 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10623 * $ `echo oops && exit 99` # => "oops\n"
10624 * $ $? # => #<Process::Status: pid 17088 exit 99>
10625 * $ $?.status # => 99>
10626 *
10627 * The built-in syntax <tt>%x{...}</tt> uses this method.
10628 *
10629 */
10630
10631static VALUE
10632rb_f_backquote(VALUE obj, VALUE str)
10633{
10634 VALUE port;
10635 VALUE result;
10636 rb_io_t *fptr;
10637
10638 StringValue(str);
10639 rb_last_status_clear();
10640 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10641 if (NIL_P(port)) return rb_str_new(0,0);
10642
10643 GetOpenFile(port, fptr);
10644 result = read_all(fptr, remain_size(fptr), Qnil);
10645 rb_io_close(port);
10646 rb_io_fptr_cleanup_all(fptr);
10647 RB_GC_GUARD(port);
10648
10649 return result;
10650}
10651
10652#ifdef HAVE_SYS_SELECT_H
10653#include <sys/select.h>
10654#endif
10655
10656static VALUE
10657select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10658{
10659 VALUE res, list;
10660 rb_fdset_t *rp, *wp, *ep;
10661 rb_io_t *fptr;
10662 long i;
10663 int max = 0, n;
10664 int pending = 0;
10665 struct timeval timerec;
10666
10667 if (!NIL_P(read)) {
10668 Check_Type(read, T_ARRAY);
10669 for (i=0; i<RARRAY_LEN(read); i++) {
10670 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10671 rb_fd_set(fptr->fd, &fds[0]);
10672 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10673 pending++;
10674 rb_fd_set(fptr->fd, &fds[3]);
10675 }
10676 if (max < fptr->fd) max = fptr->fd;
10677 }
10678 if (pending) { /* no blocking if there's buffered data */
10679 timerec.tv_sec = timerec.tv_usec = 0;
10680 tp = &timerec;
10681 }
10682 rp = &fds[0];
10683 }
10684 else
10685 rp = 0;
10686
10687 if (!NIL_P(write)) {
10688 Check_Type(write, T_ARRAY);
10689 for (i=0; i<RARRAY_LEN(write); i++) {
10690 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10691 GetOpenFile(write_io, fptr);
10692 rb_fd_set(fptr->fd, &fds[1]);
10693 if (max < fptr->fd) max = fptr->fd;
10694 }
10695 wp = &fds[1];
10696 }
10697 else
10698 wp = 0;
10699
10700 if (!NIL_P(except)) {
10701 Check_Type(except, T_ARRAY);
10702 for (i=0; i<RARRAY_LEN(except); i++) {
10703 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10704 VALUE write_io = GetWriteIO(io);
10705 GetOpenFile(io, fptr);
10706 rb_fd_set(fptr->fd, &fds[2]);
10707 if (max < fptr->fd) max = fptr->fd;
10708 if (io != write_io) {
10709 GetOpenFile(write_io, fptr);
10710 rb_fd_set(fptr->fd, &fds[2]);
10711 if (max < fptr->fd) max = fptr->fd;
10712 }
10713 }
10714 ep = &fds[2];
10715 }
10716 else {
10717 ep = 0;
10718 }
10719
10720 max++;
10721
10722 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10723 if (n < 0) {
10724 rb_sys_fail(0);
10725 }
10726 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10727
10728 res = rb_ary_new2(3);
10729 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10730 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10731 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10732
10733 if (rp) {
10734 list = RARRAY_AREF(res, 0);
10735 for (i=0; i< RARRAY_LEN(read); i++) {
10736 VALUE obj = rb_ary_entry(read, i);
10737 VALUE io = rb_io_get_io(obj);
10738 GetOpenFile(io, fptr);
10739 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10740 rb_fd_isset(fptr->fd, &fds[3])) {
10741 rb_ary_push(list, obj);
10742 }
10743 }
10744 }
10745
10746 if (wp) {
10747 list = RARRAY_AREF(res, 1);
10748 for (i=0; i< RARRAY_LEN(write); i++) {
10749 VALUE obj = rb_ary_entry(write, i);
10750 VALUE io = rb_io_get_io(obj);
10751 VALUE write_io = GetWriteIO(io);
10752 GetOpenFile(write_io, fptr);
10753 if (rb_fd_isset(fptr->fd, &fds[1])) {
10754 rb_ary_push(list, obj);
10755 }
10756 }
10757 }
10758
10759 if (ep) {
10760 list = RARRAY_AREF(res, 2);
10761 for (i=0; i< RARRAY_LEN(except); i++) {
10762 VALUE obj = rb_ary_entry(except, i);
10763 VALUE io = rb_io_get_io(obj);
10764 VALUE write_io = GetWriteIO(io);
10765 GetOpenFile(io, fptr);
10766 if (rb_fd_isset(fptr->fd, &fds[2])) {
10767 rb_ary_push(list, obj);
10768 }
10769 else if (io != write_io) {
10770 GetOpenFile(write_io, fptr);
10771 if (rb_fd_isset(fptr->fd, &fds[2])) {
10772 rb_ary_push(list, obj);
10773 }
10774 }
10775 }
10776 }
10777
10778 return res; /* returns an empty array on interrupt */
10779}
10780
10782 VALUE read, write, except;
10783 struct timeval *timeout;
10784 rb_fdset_t fdsets[4];
10785};
10786
10787static VALUE
10788select_call(VALUE arg)
10789{
10790 struct select_args *p = (struct select_args *)arg;
10791
10792 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10793}
10794
10795static VALUE
10796select_end(VALUE arg)
10797{
10798 struct select_args *p = (struct select_args *)arg;
10799 int i;
10800
10801 for (i = 0; i < numberof(p->fdsets); ++i)
10802 rb_fd_term(&p->fdsets[i]);
10803 return Qnil;
10804}
10805
10806static VALUE sym_normal, sym_sequential, sym_random,
10807 sym_willneed, sym_dontneed, sym_noreuse;
10808
10809#ifdef HAVE_POSIX_FADVISE
10810struct io_advise_struct {
10811 int fd;
10812 int advice;
10813 rb_off_t offset;
10814 rb_off_t len;
10815};
10816
10817static VALUE
10818io_advise_internal(void *arg)
10819{
10820 struct io_advise_struct *ptr = arg;
10821 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10822}
10823
10824static VALUE
10825io_advise_sym_to_const(VALUE sym)
10826{
10827#ifdef POSIX_FADV_NORMAL
10828 if (sym == sym_normal)
10829 return INT2NUM(POSIX_FADV_NORMAL);
10830#endif
10831
10832#ifdef POSIX_FADV_RANDOM
10833 if (sym == sym_random)
10834 return INT2NUM(POSIX_FADV_RANDOM);
10835#endif
10836
10837#ifdef POSIX_FADV_SEQUENTIAL
10838 if (sym == sym_sequential)
10839 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10840#endif
10841
10842#ifdef POSIX_FADV_WILLNEED
10843 if (sym == sym_willneed)
10844 return INT2NUM(POSIX_FADV_WILLNEED);
10845#endif
10846
10847#ifdef POSIX_FADV_DONTNEED
10848 if (sym == sym_dontneed)
10849 return INT2NUM(POSIX_FADV_DONTNEED);
10850#endif
10851
10852#ifdef POSIX_FADV_NOREUSE
10853 if (sym == sym_noreuse)
10854 return INT2NUM(POSIX_FADV_NOREUSE);
10855#endif
10856
10857 return Qnil;
10858}
10859
10860static VALUE
10861do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10862{
10863 int rv;
10864 struct io_advise_struct ias;
10865 VALUE num_adv;
10866
10867 num_adv = io_advise_sym_to_const(advice);
10868
10869 /*
10870 * The platform doesn't support this hint. We don't raise exception, instead
10871 * silently ignore it. Because IO::advise is only hint.
10872 */
10873 if (NIL_P(num_adv))
10874 return Qnil;
10875
10876 ias.fd = fptr->fd;
10877 ias.advice = NUM2INT(num_adv);
10878 ias.offset = offset;
10879 ias.len = len;
10880
10881 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10882 if (rv && rv != ENOSYS) {
10883 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10884 it returns the error code. */
10885 VALUE message = rb_sprintf("%"PRIsVALUE" "
10886 "(%"PRI_OFFT_PREFIX"d, "
10887 "%"PRI_OFFT_PREFIX"d, "
10888 "%"PRIsVALUE")",
10889 fptr->pathv, offset, len, advice);
10890 rb_syserr_fail_str(rv, message);
10891 }
10892
10893 return Qnil;
10894}
10895
10896#endif /* HAVE_POSIX_FADVISE */
10897
10898static void
10899advice_arg_check(VALUE advice)
10900{
10901 if (!SYMBOL_P(advice))
10902 rb_raise(rb_eTypeError, "advice must be a Symbol");
10903
10904 if (advice != sym_normal &&
10905 advice != sym_sequential &&
10906 advice != sym_random &&
10907 advice != sym_willneed &&
10908 advice != sym_dontneed &&
10909 advice != sym_noreuse) {
10910 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10911 }
10912}
10913
10914/*
10915 * call-seq:
10916 * advise(advice, offset = 0, len = 0) -> nil
10917 *
10918 * Invokes Posix system call
10919 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10920 * which announces an intention to access data from the current file
10921 * in a particular manner.
10922 *
10923 * The arguments and results are platform-dependent.
10924 *
10925 * The relevant data is specified by:
10926 *
10927 * - +offset+: The offset of the first byte of data.
10928 * - +len+: The number of bytes to be accessed;
10929 * if +len+ is zero, or is larger than the number of bytes remaining,
10930 * all remaining bytes will be accessed.
10931 *
10932 * Argument +advice+ is one of the following symbols:
10933 *
10934 * - +:normal+: The application has no advice to give
10935 * about its access pattern for the specified data.
10936 * If no advice is given for an open file, this is the default assumption.
10937 * - +:sequential+: The application expects to access the specified data sequentially
10938 * (with lower offsets read before higher ones).
10939 * - +:random+: The specified data will be accessed in random order.
10940 * - +:noreuse+: The specified data will be accessed only once.
10941 * - +:willneed+: The specified data will be accessed in the near future.
10942 * - +:dontneed+: The specified data will not be accessed in the near future.
10943 *
10944 * Not implemented on all platforms.
10945 *
10946 */
10947static VALUE
10948rb_io_advise(int argc, VALUE *argv, VALUE io)
10949{
10950 VALUE advice, offset, len;
10951 rb_off_t off, l;
10952 rb_io_t *fptr;
10953
10954 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10955 advice_arg_check(advice);
10956
10957 io = GetWriteIO(io);
10958 GetOpenFile(io, fptr);
10959
10960 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10961 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10962
10963#ifdef HAVE_POSIX_FADVISE
10964 return do_io_advise(fptr, advice, off, l);
10965#else
10966 ((void)off, (void)l); /* Ignore all hint */
10967 return Qnil;
10968#endif
10969}
10970
10971/*
10972 * call-seq:
10973 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
10974 *
10975 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
10976 * which monitors multiple file descriptors,
10977 * waiting until one or more of the file descriptors
10978 * becomes ready for some class of I/O operation.
10979 *
10980 * Not implemented on all platforms.
10981 *
10982 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
10983 * is an array of IO objects.
10984 *
10985 * Argument +timeout+ is a numeric value (such as integer or float) timeout
10986 * interval in seconds.
10987 *
10988 * The method monitors the \IO objects given in all three arrays,
10989 * waiting for some to be ready;
10990 * returns a 3-element array whose elements are:
10991 *
10992 * - An array of the objects in +read_ios+ that are ready for reading.
10993 * - An array of the objects in +write_ios+ that are ready for writing.
10994 * - An array of the objects in +error_ios+ have pending exceptions.
10995 *
10996 * If no object becomes ready within the given +timeout+, +nil+ is returned.
10997 *
10998 * \IO.select peeks the buffer of \IO objects for testing readability.
10999 * If the \IO buffer is not empty, \IO.select immediately notifies
11000 * readability. This "peek" only happens for \IO objects. It does not
11001 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11002 *
11003 * The best way to use \IO.select is invoking it after non-blocking
11004 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11005 * raise an exception which is extended by IO::WaitReadable or
11006 * IO::WaitWritable. The modules notify how the caller should wait
11007 * with \IO.select. If IO::WaitReadable is raised, the caller should
11008 * wait for reading. If IO::WaitWritable is raised, the caller should
11009 * wait for writing.
11010 *
11011 * So, blocking read (#readpartial) can be emulated using
11012 * #read_nonblock and \IO.select as follows:
11013 *
11014 * begin
11015 * result = io_like.read_nonblock(maxlen)
11016 * rescue IO::WaitReadable
11017 * IO.select([io_like])
11018 * retry
11019 * rescue IO::WaitWritable
11020 * IO.select(nil, [io_like])
11021 * retry
11022 * end
11023 *
11024 * Especially, the combination of non-blocking methods and \IO.select is
11025 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11026 * has #to_io method to return underlying IO object. IO.select calls
11027 * #to_io to obtain the file descriptor to wait.
11028 *
11029 * This means that readability notified by \IO.select doesn't mean
11030 * readability from OpenSSL::SSL::SSLSocket object.
11031 *
11032 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11033 * some data. \IO.select doesn't see the buffer. So \IO.select can
11034 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11035 *
11036 * However, several more complicated situations exist.
11037 *
11038 * SSL is a protocol which is sequence of records.
11039 * The record consists of multiple bytes.
11040 * So, the remote side of SSL sends a partial record, IO.select
11041 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11042 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11043 *
11044 * Also, the remote side can request SSL renegotiation which forces
11045 * the local SSL engine to write some data.
11046 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11047 * system call and it can block.
11048 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11049 * IO::WaitWritable instead of blocking.
11050 * So, the caller should wait for ready for writability as above
11051 * example.
11052 *
11053 * The combination of non-blocking methods and \IO.select is also useful
11054 * for streams such as tty, pipe socket socket when multiple processes
11055 * read from a stream.
11056 *
11057 * Finally, Linux kernel developers don't guarantee that
11058 * readability of select(2) means readability of following read(2) even
11059 * for a single process;
11060 * see {select(2)}[https://linux.die.net/man/2/select]
11061 *
11062 * Invoking \IO.select before IO#readpartial works well as usual.
11063 * However it is not the best way to use \IO.select.
11064 *
11065 * The writability notified by select(2) doesn't show
11066 * how many bytes are writable.
11067 * IO#write method blocks until given whole string is written.
11068 * So, <tt>IO#write(two or more bytes)</tt> can block after
11069 * writability is notified by \IO.select. IO#write_nonblock is required
11070 * to avoid the blocking.
11071 *
11072 * Blocking write (#write) can be emulated using #write_nonblock and
11073 * IO.select as follows: IO::WaitReadable should also be rescued for
11074 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11075 *
11076 * while 0 < string.bytesize
11077 * begin
11078 * written = io_like.write_nonblock(string)
11079 * rescue IO::WaitReadable
11080 * IO.select([io_like])
11081 * retry
11082 * rescue IO::WaitWritable
11083 * IO.select(nil, [io_like])
11084 * retry
11085 * end
11086 * string = string.byteslice(written..-1)
11087 * end
11088 *
11089 * Example:
11090 *
11091 * rp, wp = IO.pipe
11092 * mesg = "ping "
11093 * 100.times {
11094 * # IO.select follows IO#read. Not the best way to use IO.select.
11095 * rs, ws, = IO.select([rp], [wp])
11096 * if r = rs[0]
11097 * ret = r.read(5)
11098 * print ret
11099 * case ret
11100 * when /ping/
11101 * mesg = "pong\n"
11102 * when /pong/
11103 * mesg = "ping "
11104 * end
11105 * end
11106 * if w = ws[0]
11107 * w.write(mesg)
11108 * end
11109 * }
11110 *
11111 * Output:
11112 *
11113 * ping pong
11114 * ping pong
11115 * ping pong
11116 * (snipped)
11117 * ping
11118 *
11119 */
11120
11121static VALUE
11122rb_f_select(int argc, VALUE *argv, VALUE obj)
11123{
11124 VALUE scheduler = rb_fiber_scheduler_current();
11125 if (scheduler != Qnil) {
11126 // It's optionally supported.
11127 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11128 if (!UNDEF_P(result)) return result;
11129 }
11130
11131 VALUE timeout;
11132 struct select_args args;
11133 struct timeval timerec;
11134 int i;
11135
11136 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11137 if (NIL_P(timeout)) {
11138 args.timeout = 0;
11139 }
11140 else {
11141 timerec = rb_time_interval(timeout);
11142 args.timeout = &timerec;
11143 }
11144
11145 for (i = 0; i < numberof(args.fdsets); ++i)
11146 rb_fd_init(&args.fdsets[i]);
11147
11148 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11149}
11150
11151#ifdef IOCTL_REQ_TYPE
11152 typedef IOCTL_REQ_TYPE ioctl_req_t;
11153#else
11154 typedef int ioctl_req_t;
11155# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11156#endif
11157
11158#ifdef HAVE_IOCTL
11159struct ioctl_arg {
11160 int fd;
11161 ioctl_req_t cmd;
11162 long narg;
11163};
11164
11165static VALUE
11166nogvl_ioctl(void *ptr)
11167{
11168 struct ioctl_arg *arg = ptr;
11169
11170 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11171}
11172
11173static int
11174do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11175{
11176 int retval;
11177 struct ioctl_arg arg;
11178
11179 arg.fd = io->fd;
11180 arg.cmd = cmd;
11181 arg.narg = narg;
11182
11183 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11184
11185 return retval;
11186}
11187#endif
11188
11189#define DEFAULT_IOCTL_NARG_LEN (256)
11190
11191#if defined(__linux__) && defined(_IOC_SIZE)
11192static long
11193linux_iocparm_len(ioctl_req_t cmd)
11194{
11195 long len;
11196
11197 if ((cmd & 0xFFFF0000) == 0) {
11198 /* legacy and unstructured ioctl number. */
11199 return DEFAULT_IOCTL_NARG_LEN;
11200 }
11201
11202 len = _IOC_SIZE(cmd);
11203
11204 /* paranoia check for silly drivers which don't keep ioctl convention */
11205 if (len < DEFAULT_IOCTL_NARG_LEN)
11206 len = DEFAULT_IOCTL_NARG_LEN;
11207
11208 return len;
11209}
11210#endif
11211
11212#ifdef HAVE_IOCTL
11213static long
11214ioctl_narg_len(ioctl_req_t cmd)
11215{
11216 long len;
11217
11218#ifdef IOCPARM_MASK
11219#ifndef IOCPARM_LEN
11220#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11221#endif
11222#endif
11223#ifdef IOCPARM_LEN
11224 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11225#elif defined(__linux__) && defined(_IOC_SIZE)
11226 len = linux_iocparm_len(cmd);
11227#else
11228 /* otherwise guess at what's safe */
11229 len = DEFAULT_IOCTL_NARG_LEN;
11230#endif
11231
11232 return len;
11233}
11234#endif
11235
11236#ifdef HAVE_FCNTL
11237#ifdef __linux__
11238typedef long fcntl_arg_t;
11239#else
11240/* posix */
11241typedef int fcntl_arg_t;
11242#endif
11243
11244static long
11245fcntl_narg_len(ioctl_req_t cmd)
11246{
11247 long len;
11248
11249 switch (cmd) {
11250#ifdef F_DUPFD
11251 case F_DUPFD:
11252 len = sizeof(fcntl_arg_t);
11253 break;
11254#endif
11255#ifdef F_DUP2FD /* bsd specific */
11256 case F_DUP2FD:
11257 len = sizeof(int);
11258 break;
11259#endif
11260#ifdef F_DUPFD_CLOEXEC /* linux specific */
11261 case F_DUPFD_CLOEXEC:
11262 len = sizeof(fcntl_arg_t);
11263 break;
11264#endif
11265#ifdef F_GETFD
11266 case F_GETFD:
11267 len = 1;
11268 break;
11269#endif
11270#ifdef F_SETFD
11271 case F_SETFD:
11272 len = sizeof(fcntl_arg_t);
11273 break;
11274#endif
11275#ifdef F_GETFL
11276 case F_GETFL:
11277 len = 1;
11278 break;
11279#endif
11280#ifdef F_SETFL
11281 case F_SETFL:
11282 len = sizeof(fcntl_arg_t);
11283 break;
11284#endif
11285#ifdef F_GETOWN
11286 case F_GETOWN:
11287 len = 1;
11288 break;
11289#endif
11290#ifdef F_SETOWN
11291 case F_SETOWN:
11292 len = sizeof(fcntl_arg_t);
11293 break;
11294#endif
11295#ifdef F_GETOWN_EX /* linux specific */
11296 case F_GETOWN_EX:
11297 len = sizeof(struct f_owner_ex);
11298 break;
11299#endif
11300#ifdef F_SETOWN_EX /* linux specific */
11301 case F_SETOWN_EX:
11302 len = sizeof(struct f_owner_ex);
11303 break;
11304#endif
11305#ifdef F_GETLK
11306 case F_GETLK:
11307 len = sizeof(struct flock);
11308 break;
11309#endif
11310#ifdef F_SETLK
11311 case F_SETLK:
11312 len = sizeof(struct flock);
11313 break;
11314#endif
11315#ifdef F_SETLKW
11316 case F_SETLKW:
11317 len = sizeof(struct flock);
11318 break;
11319#endif
11320#ifdef F_READAHEAD /* bsd specific */
11321 case F_READAHEAD:
11322 len = sizeof(int);
11323 break;
11324#endif
11325#ifdef F_RDAHEAD /* Darwin specific */
11326 case F_RDAHEAD:
11327 len = sizeof(int);
11328 break;
11329#endif
11330#ifdef F_GETSIG /* linux specific */
11331 case F_GETSIG:
11332 len = 1;
11333 break;
11334#endif
11335#ifdef F_SETSIG /* linux specific */
11336 case F_SETSIG:
11337 len = sizeof(fcntl_arg_t);
11338 break;
11339#endif
11340#ifdef F_GETLEASE /* linux specific */
11341 case F_GETLEASE:
11342 len = 1;
11343 break;
11344#endif
11345#ifdef F_SETLEASE /* linux specific */
11346 case F_SETLEASE:
11347 len = sizeof(fcntl_arg_t);
11348 break;
11349#endif
11350#ifdef F_NOTIFY /* linux specific */
11351 case F_NOTIFY:
11352 len = sizeof(fcntl_arg_t);
11353 break;
11354#endif
11355
11356 default:
11357 len = 256;
11358 break;
11359 }
11360
11361 return len;
11362}
11363#else /* HAVE_FCNTL */
11364static long
11365fcntl_narg_len(ioctl_req_t cmd)
11366{
11367 return 0;
11368}
11369#endif /* HAVE_FCNTL */
11370
11371#define NARG_SENTINEL 17
11372
11373static long
11374setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11375{
11376 long narg = 0;
11377 VALUE arg = *argp;
11378
11379 if (!RTEST(arg)) {
11380 narg = 0;
11381 }
11382 else if (FIXNUM_P(arg)) {
11383 narg = FIX2LONG(arg);
11384 }
11385 else if (arg == Qtrue) {
11386 narg = 1;
11387 }
11388 else {
11389 VALUE tmp = rb_check_string_type(arg);
11390
11391 if (NIL_P(tmp)) {
11392 narg = NUM2LONG(arg);
11393 }
11394 else {
11395 char *ptr;
11396 long len, slen;
11397
11398 *argp = arg = tmp;
11399 len = narg_len(cmd);
11400 rb_str_modify(arg);
11401
11402 slen = RSTRING_LEN(arg);
11403 /* expand for data + sentinel. */
11404 if (slen < len+1) {
11405 rb_str_resize(arg, len+1);
11406 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11407 slen = len+1;
11408 }
11409 /* a little sanity check here */
11410 ptr = RSTRING_PTR(arg);
11411 ptr[slen - 1] = NARG_SENTINEL;
11412 narg = (long)(SIGNED_VALUE)ptr;
11413 }
11414 }
11415
11416 return narg;
11417}
11418
11419static VALUE
11420finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11421{
11422 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11423 if (RB_TYPE_P(arg, T_STRING)) {
11424 char *ptr;
11425 long slen;
11426 RSTRING_GETMEM(arg, ptr, slen);
11427 if (ptr[slen-1] != NARG_SENTINEL)
11428 rb_raise(rb_eArgError, "return value overflowed string");
11429 ptr[slen-1] = '\0';
11430 }
11431
11432 return INT2NUM(retval);
11433}
11434
11435#ifdef HAVE_IOCTL
11436static VALUE
11437rb_ioctl(VALUE io, VALUE req, VALUE arg)
11438{
11439 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11440 rb_io_t *fptr;
11441 long narg;
11442 int retval;
11443
11444 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11445 GetOpenFile(io, fptr);
11446 retval = do_ioctl(fptr, cmd, narg);
11447 return finish_narg(retval, arg, fptr);
11448}
11449
11450/*
11451 * call-seq:
11452 * ioctl(integer_cmd, argument) -> integer
11453 *
11454 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11455 * which issues a low-level command to an I/O device.
11456 *
11457 * Issues a low-level command to an I/O device.
11458 * The arguments and returned value are platform-dependent.
11459 * The effect of the call is platform-dependent.
11460 *
11461 * If argument +argument+ is an integer, it is passed directly;
11462 * if it is a string, it is interpreted as a binary sequence of bytes.
11463 *
11464 * Not implemented on all platforms.
11465 *
11466 */
11467
11468static VALUE
11469rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11470{
11471 VALUE req, arg;
11472
11473 rb_scan_args(argc, argv, "11", &req, &arg);
11474 return rb_ioctl(io, req, arg);
11475}
11476#else
11477#define rb_io_ioctl rb_f_notimplement
11478#endif
11479
11480#ifdef HAVE_FCNTL
11481struct fcntl_arg {
11482 int fd;
11483 int cmd;
11484 long narg;
11485};
11486
11487static VALUE
11488nogvl_fcntl(void *ptr)
11489{
11490 struct fcntl_arg *arg = ptr;
11491
11492#if defined(F_DUPFD)
11493 if (arg->cmd == F_DUPFD)
11494 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11495#endif
11496 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11497}
11498
11499static int
11500do_fcntl(struct rb_io *io, int cmd, long narg)
11501{
11502 int retval;
11503 struct fcntl_arg arg;
11504
11505 arg.fd = io->fd;
11506 arg.cmd = cmd;
11507 arg.narg = narg;
11508
11509 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11510 if (retval != -1) {
11511 switch (cmd) {
11512#if defined(F_DUPFD)
11513 case F_DUPFD:
11514#endif
11515#if defined(F_DUPFD_CLOEXEC)
11516 case F_DUPFD_CLOEXEC:
11517#endif
11518 rb_update_max_fd(retval);
11519 }
11520 }
11521
11522 return retval;
11523}
11524
11525static VALUE
11526rb_fcntl(VALUE io, VALUE req, VALUE arg)
11527{
11528 int cmd = NUM2INT(req);
11529 rb_io_t *fptr;
11530 long narg;
11531 int retval;
11532
11533 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11534 GetOpenFile(io, fptr);
11535 retval = do_fcntl(fptr, cmd, narg);
11536 return finish_narg(retval, arg, fptr);
11537}
11538
11539/*
11540 * call-seq:
11541 * fcntl(integer_cmd, argument) -> integer
11542 *
11543 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11544 * which provides a mechanism for issuing low-level commands to control or query
11545 * a file-oriented I/O stream. Arguments and results are platform
11546 * dependent.
11547 *
11548 * If +argument+ is a number, its value is passed directly;
11549 * if it is a string, it is interpreted as a binary sequence of bytes.
11550 * (Array#pack might be a useful way to build this string.)
11551 *
11552 * Not implemented on all platforms.
11553 *
11554 */
11555
11556static VALUE
11557rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11558{
11559 VALUE req, arg;
11560
11561 rb_scan_args(argc, argv, "11", &req, &arg);
11562 return rb_fcntl(io, req, arg);
11563}
11564#else
11565#define rb_io_fcntl rb_f_notimplement
11566#endif
11567
11568#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11569/*
11570 * call-seq:
11571 * syscall(integer_callno, *arguments) -> integer
11572 *
11573 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11574 * which calls a specified function.
11575 *
11576 * Calls the operating system function identified by +integer_callno+;
11577 * returns the result of the function or raises SystemCallError if it failed.
11578 * The effect of the call is platform-dependent.
11579 * The arguments and returned value are platform-dependent.
11580 *
11581 * For each of +arguments+: if it is an integer, it is passed directly;
11582 * if it is a string, it is interpreted as a binary sequence of bytes.
11583 * There may be as many as nine such arguments.
11584 *
11585 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11586 * are platform-dependent.
11587 *
11588 * Note: Method +syscall+ is essentially unsafe and unportable.
11589 * The DL (Fiddle) library is preferred for safer and a bit
11590 * more portable programming.
11591 *
11592 * Not implemented on all platforms.
11593 *
11594 */
11595
11596static VALUE
11597rb_f_syscall(int argc, VALUE *argv, VALUE _)
11598{
11599 VALUE arg[8];
11600#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11601# define SYSCALL __syscall
11602# define NUM2SYSCALLID(x) NUM2LONG(x)
11603# define RETVAL2NUM(x) LONG2NUM(x)
11604# if SIZEOF_LONG == 8
11605 long num, retval = -1;
11606# elif SIZEOF_LONG_LONG == 8
11607 long long num, retval = -1;
11608# else
11609# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11610# endif
11611#elif defined(__linux__)
11612# define SYSCALL syscall
11613# define NUM2SYSCALLID(x) NUM2LONG(x)
11614# define RETVAL2NUM(x) LONG2NUM(x)
11615 /*
11616 * Linux man page says, syscall(2) function prototype is below.
11617 *
11618 * int syscall(int number, ...);
11619 *
11620 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11621 */
11622 long num, retval = -1;
11623#else
11624# define SYSCALL syscall
11625# define NUM2SYSCALLID(x) NUM2INT(x)
11626# define RETVAL2NUM(x) INT2NUM(x)
11627 int num, retval = -1;
11628#endif
11629 int i;
11630
11631 if (RTEST(ruby_verbose)) {
11633 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11634 }
11635
11636 if (argc == 0)
11637 rb_raise(rb_eArgError, "too few arguments for syscall");
11638 if (argc > numberof(arg))
11639 rb_raise(rb_eArgError, "too many arguments for syscall");
11640 num = NUM2SYSCALLID(argv[0]); ++argv;
11641 for (i = argc - 1; i--; ) {
11642 VALUE v = rb_check_string_type(argv[i]);
11643
11644 if (!NIL_P(v)) {
11645 StringValue(v);
11646 rb_str_modify(v);
11647 arg[i] = (VALUE)StringValueCStr(v);
11648 }
11649 else {
11650 arg[i] = (VALUE)NUM2LONG(argv[i]);
11651 }
11652 }
11653
11654 switch (argc) {
11655 case 1:
11656 retval = SYSCALL(num);
11657 break;
11658 case 2:
11659 retval = SYSCALL(num, arg[0]);
11660 break;
11661 case 3:
11662 retval = SYSCALL(num, arg[0],arg[1]);
11663 break;
11664 case 4:
11665 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11666 break;
11667 case 5:
11668 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11669 break;
11670 case 6:
11671 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11672 break;
11673 case 7:
11674 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11675 break;
11676 case 8:
11677 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11678 break;
11679 }
11680
11681 if (retval == -1)
11682 rb_sys_fail(0);
11683 return RETVAL2NUM(retval);
11684#undef SYSCALL
11685#undef NUM2SYSCALLID
11686#undef RETVAL2NUM
11687}
11688#else
11689#define rb_f_syscall rb_f_notimplement
11690#endif
11691
11692static VALUE
11693io_new_instance(VALUE args)
11694{
11695 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11696}
11697
11698static rb_encoding *
11699find_encoding(VALUE v)
11700{
11701 rb_encoding *enc = rb_find_encoding(v);
11702 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11703 return enc;
11704}
11705
11706static void
11707io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11708{
11709 rb_encoding *enc, *enc2;
11710 int ecflags = fptr->encs.ecflags;
11711 VALUE ecopts, tmp;
11712
11713 if (!NIL_P(v2)) {
11714 enc2 = find_encoding(v1);
11715 tmp = rb_check_string_type(v2);
11716 if (!NIL_P(tmp)) {
11717 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11718 /* Special case - "-" => no transcoding */
11719 enc = enc2;
11720 enc2 = NULL;
11721 }
11722 else
11723 enc = find_encoding(v2);
11724 if (enc == enc2) {
11725 /* Special case - "-" => no transcoding */
11726 enc2 = NULL;
11727 }
11728 }
11729 else {
11730 enc = find_encoding(v2);
11731 if (enc == enc2) {
11732 /* Special case - "-" => no transcoding */
11733 enc2 = NULL;
11734 }
11735 }
11736 if (enc2 == rb_ascii8bit_encoding()) {
11737 /* If external is ASCII-8BIT, no transcoding */
11738 enc = enc2;
11739 enc2 = NULL;
11740 }
11741 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11742 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11743 }
11744 else {
11745 if (NIL_P(v1)) {
11746 /* Set to default encodings */
11747 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11748 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11749 ecopts = Qnil;
11750 }
11751 else {
11752 tmp = rb_check_string_type(v1);
11753 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11754 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11755 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11756 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11757 }
11758 else {
11759 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11760 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11761 ecopts = Qnil;
11762 }
11763 }
11764 }
11765 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11766 fptr->encs.enc = enc;
11767 fptr->encs.enc2 = enc2;
11768 fptr->encs.ecflags = ecflags;
11769 fptr->encs.ecopts = ecopts;
11770 clear_codeconv(fptr);
11771
11772}
11773
11775 rb_io_t *fptr;
11776 VALUE v1;
11777 VALUE v2;
11778 VALUE opt;
11779};
11780
11781static VALUE
11782io_encoding_set_v(VALUE v)
11783{
11784 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11785 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11786 return Qnil;
11787}
11788
11789static VALUE
11790pipe_pair_close(VALUE rw)
11791{
11792 VALUE *rwp = (VALUE *)rw;
11793 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11794}
11795
11796/*
11797 * call-seq:
11798 * IO.pipe(**opts) -> [read_io, write_io]
11799 * IO.pipe(enc, **opts) -> [read_io, write_io]
11800 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11801 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11802 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11803 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11804 *
11805 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11806 * connected to each other.
11807 *
11808 * If argument +enc_string+ is given, it must be a string containing one of:
11809 *
11810 * - The name of the encoding to be used as the external encoding.
11811 * - The colon-separated names of two encodings to be used as the external
11812 * and internal encodings.
11813 *
11814 * If argument +int_enc+ is given, it must be an Encoding object
11815 * or encoding name string that specifies the internal encoding to be used;
11816 * if argument +ext_enc+ is also given, it must be an Encoding object
11817 * or encoding name string that specifies the external encoding to be used.
11818 *
11819 * The string read from +read_io+ is tagged with the external encoding;
11820 * if an internal encoding is also specified, the string is converted
11821 * to, and tagged with, that encoding.
11822 *
11823 * If any encoding is specified,
11824 * optional hash arguments specify the conversion option.
11825 *
11826 * Optional keyword arguments +opts+ specify:
11827 *
11828 * - {Open Options}[rdoc-ref:IO@Open+Options].
11829 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11830 *
11831 * With no block given, returns the two endpoints in an array:
11832 *
11833 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11834 *
11835 * With a block given, calls the block with the two endpoints;
11836 * closes both endpoints and returns the value of the block:
11837 *
11838 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11839 *
11840 * Output:
11841 *
11842 * #<IO:fd 6>
11843 * #<IO:fd 7>
11844 *
11845 * Not available on all platforms.
11846 *
11847 * In the example below, the two processes close the ends of the pipe
11848 * that they are not using. This is not just a cosmetic nicety. The
11849 * read end of a pipe will not generate an end of file condition if
11850 * there are any writers with the pipe still open. In the case of the
11851 * parent process, the <tt>rd.read</tt> will never return if it
11852 * does not first issue a <tt>wr.close</tt>:
11853 *
11854 * rd, wr = IO.pipe
11855 *
11856 * if fork
11857 * wr.close
11858 * puts "Parent got: <#{rd.read}>"
11859 * rd.close
11860 * Process.wait
11861 * else
11862 * rd.close
11863 * puts 'Sending message to parent'
11864 * wr.write "Hi Dad"
11865 * wr.close
11866 * end
11867 *
11868 * <em>produces:</em>
11869 *
11870 * Sending message to parent
11871 * Parent got: <Hi Dad>
11872 *
11873 */
11874
11875static VALUE
11876rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11877{
11878 int pipes[2], state;
11879 VALUE r, w, args[3], v1, v2;
11880 VALUE opt;
11881 rb_io_t *fptr, *fptr2;
11882 struct io_encoding_set_args ies_args;
11883 int fmode = 0;
11884 VALUE ret;
11885
11886 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11887 if (rb_pipe(pipes) < 0)
11888 rb_sys_fail(0);
11889
11890 args[0] = klass;
11891 args[1] = INT2NUM(pipes[0]);
11892 args[2] = INT2FIX(O_RDONLY);
11893 r = rb_protect(io_new_instance, (VALUE)args, &state);
11894 if (state) {
11895 close(pipes[0]);
11896 close(pipes[1]);
11897 rb_jump_tag(state);
11898 }
11899 GetOpenFile(r, fptr);
11900
11901 ies_args.fptr = fptr;
11902 ies_args.v1 = v1;
11903 ies_args.v2 = v2;
11904 ies_args.opt = opt;
11905 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11906 if (state) {
11907 close(pipes[1]);
11908 io_close(r);
11909 rb_jump_tag(state);
11910 }
11911
11912 args[1] = INT2NUM(pipes[1]);
11913 args[2] = INT2FIX(O_WRONLY);
11914 w = rb_protect(io_new_instance, (VALUE)args, &state);
11915 if (state) {
11916 close(pipes[1]);
11917 if (!NIL_P(r)) rb_io_close(r);
11918 rb_jump_tag(state);
11919 }
11920 GetOpenFile(w, fptr2);
11921 rb_io_synchronized(fptr2);
11922
11923 extract_binmode(opt, &fmode);
11924
11925 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11928 }
11929
11930#if DEFAULT_TEXTMODE
11931 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11932 fptr->mode &= ~FMODE_TEXTMODE;
11933 setmode(fptr->fd, O_BINARY);
11934 }
11935#if RUBY_CRLF_ENVIRONMENT
11938 }
11939#endif
11940#endif
11941 fptr->mode |= fmode;
11942#if DEFAULT_TEXTMODE
11943 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11944 fptr2->mode &= ~FMODE_TEXTMODE;
11945 setmode(fptr2->fd, O_BINARY);
11946 }
11947#endif
11948 fptr2->mode |= fmode;
11949
11950 ret = rb_assoc_new(r, w);
11951 if (rb_block_given_p()) {
11952 VALUE rw[2];
11953 rw[0] = r;
11954 rw[1] = w;
11955 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11956 }
11957 return ret;
11958}
11959
11961 int argc;
11962 VALUE *argv;
11963 VALUE io;
11964};
11965
11966static void
11967open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
11968{
11969 VALUE path, v;
11970 VALUE vmode = Qnil, vperm = Qnil;
11971
11972 path = *argv++;
11973 argc--;
11974 FilePathValue(path);
11975 arg->io = 0;
11976 arg->argc = argc;
11977 arg->argv = argv;
11978 if (NIL_P(opt)) {
11979 vmode = INT2NUM(O_RDONLY);
11980 vperm = INT2FIX(0666);
11981 }
11982 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11983 int n;
11984
11985 v = rb_to_array_type(v);
11986 n = RARRAY_LENINT(v);
11987 rb_check_arity(n, 0, 3); /* rb_io_open */
11988 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
11989 }
11990 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11991}
11992
11993static VALUE
11994io_s_foreach(VALUE v)
11995{
11996 struct getline_arg *arg = (void *)v;
11997 VALUE str;
11998
11999 if (arg->limit == 0)
12000 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12001 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12002 rb_lastline_set(str);
12003 rb_yield(str);
12004 }
12006 return Qnil;
12007}
12008
12009/*
12010 * call-seq:
12011 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12012 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12013 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12014 * IO.foreach(...) -> an_enumerator
12015 *
12016 * Calls the block with each successive line read from the stream.
12017 *
12018 * When called from class \IO (but not subclasses of \IO),
12019 * this method has potential security vulnerabilities if called with untrusted input;
12020 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12021 *
12022 * The first argument must be a string that is the path to a file.
12023 *
12024 * With only argument +path+ given, parses lines from the file at the given +path+,
12025 * as determined by the default line separator,
12026 * and calls the block with each successive line:
12027 *
12028 * File.foreach('t.txt') {|line| p line }
12029 *
12030 * Output: the same as above.
12031 *
12032 * For both forms, command and path, the remaining arguments are the same.
12033 *
12034 * With argument +sep+ given, parses lines as determined by that line separator
12035 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12036 *
12037 * File.foreach('t.txt', 'li') {|line| p line }
12038 *
12039 * Output:
12040 *
12041 * "First li"
12042 * "ne\nSecond li"
12043 * "ne\n\nThird li"
12044 * "ne\nFourth li"
12045 * "ne\n"
12046 *
12047 * Each paragraph:
12048 *
12049 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12050 *
12051 * Output:
12052 *
12053 * "First line\nSecond line\n\n"
12054 * "Third line\nFourth line\n"
12055 *
12056 * With argument +limit+ given, parses lines as determined by the default
12057 * line separator and the given line-length limit
12058 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12059 *
12060 * File.foreach('t.txt', 7) {|line| p line }
12061 *
12062 * Output:
12063 *
12064 * "First l"
12065 * "ine\n"
12066 * "Second "
12067 * "line\n"
12068 * "\n"
12069 * "Third l"
12070 * "ine\n"
12071 * "Fourth l"
12072 * "line\n"
12073 *
12074 * With arguments +sep+ and +limit+ given,
12075 * combines the two behaviors
12076 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12077 *
12078 * Optional keyword arguments +opts+ specify:
12079 *
12080 * - {Open Options}[rdoc-ref:IO@Open+Options].
12081 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12082 * - {Line Options}[rdoc-ref:IO@Line+IO].
12083 *
12084 * Returns an Enumerator if no block is given.
12085 *
12086 */
12087
12088static VALUE
12089rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12090{
12091 VALUE opt;
12092 int orig_argc = argc;
12093 struct foreach_arg arg;
12094 struct getline_arg garg;
12095
12096 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12097 RETURN_ENUMERATOR(self, orig_argc, argv);
12098 extract_getline_args(argc-1, argv+1, &garg);
12099 open_key_args(self, argc, argv, opt, &arg);
12100 if (NIL_P(arg.io)) return Qnil;
12101 extract_getline_opts(opt, &garg);
12102 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12103 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12104}
12105
12106static VALUE
12107io_s_readlines(VALUE v)
12108{
12109 struct getline_arg *arg = (void *)v;
12110 return io_readlines(arg, arg->io);
12111}
12112
12113/*
12114 * call-seq:
12115 * IO.readlines(path, sep = $/, **opts) -> array
12116 * IO.readlines(path, limit, **opts) -> array
12117 * IO.readlines(path, sep, limit, **opts) -> array
12118 *
12119 * Returns an array of all lines read from the stream.
12120 *
12121 * When called from class \IO (but not subclasses of \IO),
12122 * this method has potential security vulnerabilities if called with untrusted input;
12123 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12124 *
12125 * The first argument must be a string that is the path to a file.
12126 *
12127 * With only argument +path+ given, parses lines from the file at the given +path+,
12128 * as determined by the default line separator,
12129 * and returns those lines in an array:
12130 *
12131 * IO.readlines('t.txt')
12132 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12133 *
12134 * With argument +sep+ given, parses lines as determined by that line separator
12135 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12136 *
12137 * # Ordinary separator.
12138 * IO.readlines('t.txt', 'li')
12139 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12140 * # Get-paragraphs separator.
12141 * IO.readlines('t.txt', '')
12142 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12143 * # Get-all separator.
12144 * IO.readlines('t.txt', nil)
12145 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12146 *
12147 * With argument +limit+ given, parses lines as determined by the default
12148 * line separator and the given line-length limit
12149 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12150 *
12151 * IO.readlines('t.txt', 7)
12152 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12153 *
12154 * With arguments +sep+ and +limit+ given,
12155 * combines the two behaviors
12156 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12157 *
12158 * Optional keyword arguments +opts+ specify:
12159 *
12160 * - {Open Options}[rdoc-ref:IO@Open+Options].
12161 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12162 * - {Line Options}[rdoc-ref:IO@Line+IO].
12163 *
12164 */
12165
12166static VALUE
12167rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12168{
12169 VALUE opt;
12170 struct foreach_arg arg;
12171 struct getline_arg garg;
12172
12173 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12174 extract_getline_args(argc-1, argv+1, &garg);
12175 open_key_args(io, argc, argv, opt, &arg);
12176 if (NIL_P(arg.io)) return Qnil;
12177 extract_getline_opts(opt, &garg);
12178 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12179 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12180}
12181
12182static VALUE
12183io_s_read(VALUE v)
12184{
12185 struct foreach_arg *arg = (void *)v;
12186 return io_read(arg->argc, arg->argv, arg->io);
12187}
12188
12189struct seek_arg {
12190 VALUE io;
12191 VALUE offset;
12192 int mode;
12193};
12194
12195static VALUE
12196seek_before_access(VALUE argp)
12197{
12198 struct seek_arg *arg = (struct seek_arg *)argp;
12199 rb_io_binmode(arg->io);
12200 return rb_io_seek(arg->io, arg->offset, arg->mode);
12201}
12202
12203/*
12204 * call-seq:
12205 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12206 *
12207 * Opens the stream, reads and returns some or all of its content,
12208 * and closes the stream; returns +nil+ if no bytes were read.
12209 *
12210 * When called from class \IO (but not subclasses of \IO),
12211 * this method has potential security vulnerabilities if called with untrusted input;
12212 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12213 *
12214 * The first argument must be a string that is the path to a file.
12215 *
12216 * With only argument +path+ given, reads in text mode and returns the entire content
12217 * of the file at the given path:
12218 *
12219 * IO.read('t.txt')
12220 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12221 *
12222 * On Windows, text mode can terminate reading and leave bytes in the file
12223 * unread when encountering certain special bytes. Consider using
12224 * IO.binread if all bytes in the file should be read.
12225 *
12226 * With argument +length+, returns +length+ bytes if available:
12227 *
12228 * IO.read('t.txt', 7) # => "First l"
12229 * IO.read('t.txt', 700)
12230 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12231 *
12232 * With arguments +length+ and +offset+, returns +length+ bytes
12233 * if available, beginning at the given +offset+:
12234 *
12235 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12236 * IO.read('t.txt', 10, 200) # => nil
12237 *
12238 * Optional keyword arguments +opts+ specify:
12239 *
12240 * - {Open Options}[rdoc-ref:IO@Open+Options].
12241 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12242 *
12243 */
12244
12245static VALUE
12246rb_io_s_read(int argc, VALUE *argv, VALUE io)
12247{
12248 VALUE opt, offset;
12249 long off;
12250 struct foreach_arg arg;
12251
12252 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12253 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12254 rb_raise(rb_eArgError, "negative offset %ld given", off);
12255 }
12256 open_key_args(io, argc, argv, opt, &arg);
12257 if (NIL_P(arg.io)) return Qnil;
12258 if (!NIL_P(offset)) {
12259 struct seek_arg sarg;
12260 int state = 0;
12261 sarg.io = arg.io;
12262 sarg.offset = offset;
12263 sarg.mode = SEEK_SET;
12264 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12265 if (state) {
12266 rb_io_close(arg.io);
12267 rb_jump_tag(state);
12268 }
12269 if (arg.argc == 2) arg.argc = 1;
12270 }
12271 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12272}
12273
12274/*
12275 * call-seq:
12276 * IO.binread(path, length = nil, offset = 0) -> string or nil
12277 *
12278 * Behaves like IO.read, except that the stream is opened in binary mode
12279 * with ASCII-8BIT encoding.
12280 *
12281 * When called from class \IO (but not subclasses of \IO),
12282 * this method has potential security vulnerabilities if called with untrusted input;
12283 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12284 *
12285 */
12286
12287static VALUE
12288rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12289{
12290 VALUE offset;
12291 struct foreach_arg arg;
12292 enum {
12294 oflags = O_RDONLY
12295#ifdef O_BINARY
12296 |O_BINARY
12297#endif
12298 };
12299 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12300
12301 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12302 FilePathValue(argv[0]);
12303 convconfig.enc = rb_ascii8bit_encoding();
12304 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12305 if (NIL_P(arg.io)) return Qnil;
12306 arg.argv = argv+1;
12307 arg.argc = (argc > 1) ? 1 : 0;
12308 if (!NIL_P(offset)) {
12309 struct seek_arg sarg;
12310 int state = 0;
12311 sarg.io = arg.io;
12312 sarg.offset = offset;
12313 sarg.mode = SEEK_SET;
12314 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12315 if (state) {
12316 rb_io_close(arg.io);
12317 rb_jump_tag(state);
12318 }
12319 }
12320 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12321}
12322
12323static VALUE
12324io_s_write0(VALUE v)
12325{
12326 struct write_arg *arg = (void *)v;
12327 return io_write(arg->io,arg->str,arg->nosync);
12328}
12329
12330static VALUE
12331io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12332{
12333 VALUE string, offset, opt;
12334 struct foreach_arg arg;
12335 struct write_arg warg;
12336
12337 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12338
12339 if (NIL_P(opt)) opt = rb_hash_new();
12340 else opt = rb_hash_dup(opt);
12341
12342
12343 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12344 int mode = O_WRONLY|O_CREAT;
12345#ifdef O_BINARY
12346 if (binary) mode |= O_BINARY;
12347#endif
12348 if (NIL_P(offset)) mode |= O_TRUNC;
12349 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12350 }
12351 open_key_args(klass, argc, argv, opt, &arg);
12352
12353#ifndef O_BINARY
12354 if (binary) rb_io_binmode_m(arg.io);
12355#endif
12356
12357 if (NIL_P(arg.io)) return Qnil;
12358 if (!NIL_P(offset)) {
12359 struct seek_arg sarg;
12360 int state = 0;
12361 sarg.io = arg.io;
12362 sarg.offset = offset;
12363 sarg.mode = SEEK_SET;
12364 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12365 if (state) {
12366 rb_io_close(arg.io);
12367 rb_jump_tag(state);
12368 }
12369 }
12370
12371 warg.io = arg.io;
12372 warg.str = string;
12373 warg.nosync = 0;
12374
12375 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12376}
12377
12378/*
12379 * call-seq:
12380 * IO.write(path, data, offset = 0, **opts) -> integer
12381 *
12382 * Opens the stream, writes the given +data+ to it,
12383 * and closes the stream; returns the number of bytes written.
12384 *
12385 * When called from class \IO (but not subclasses of \IO),
12386 * this method has potential security vulnerabilities if called with untrusted input;
12387 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12388 *
12389 * The first argument must be a string that is the path to a file.
12390 *
12391 * With only argument +path+ given, writes the given +data+ to the file at that path:
12392 *
12393 * IO.write('t.tmp', 'abc') # => 3
12394 * File.read('t.tmp') # => "abc"
12395 *
12396 * If +offset+ is zero (the default), the file is overwritten:
12397 *
12398 * IO.write('t.tmp', 'A') # => 1
12399 * File.read('t.tmp') # => "A"
12400 *
12401 * If +offset+ in within the file content, the file is partly overwritten:
12402 *
12403 * IO.write('t.tmp', 'abcdef') # => 3
12404 * File.read('t.tmp') # => "abcdef"
12405 * # Offset within content.
12406 * IO.write('t.tmp', '012', 2) # => 3
12407 * File.read('t.tmp') # => "ab012f"
12408 *
12409 * If +offset+ is outside the file content,
12410 * the file is padded with null characters <tt>"\u0000"</tt>:
12411 *
12412 * IO.write('t.tmp', 'xyz', 10) # => 3
12413 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12414 *
12415 * Optional keyword arguments +opts+ specify:
12416 *
12417 * - {Open Options}[rdoc-ref:IO@Open+Options].
12418 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12419 *
12420 */
12421
12422static VALUE
12423rb_io_s_write(int argc, VALUE *argv, VALUE io)
12424{
12425 return io_s_write(argc, argv, io, 0);
12426}
12427
12428/*
12429 * call-seq:
12430 * IO.binwrite(path, string, offset = 0) -> integer
12431 *
12432 * Behaves like IO.write, except that the stream is opened in binary mode
12433 * with ASCII-8BIT encoding.
12434 *
12435 * When called from class \IO (but not subclasses of \IO),
12436 * this method has potential security vulnerabilities if called with untrusted input;
12437 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12438 *
12439 */
12440
12441static VALUE
12442rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12443{
12444 return io_s_write(argc, argv, io, 1);
12445}
12446
12448 VALUE src;
12449 VALUE dst;
12450 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12451 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12452
12453 rb_io_t *src_fptr;
12454 rb_io_t *dst_fptr;
12455 unsigned close_src : 1;
12456 unsigned close_dst : 1;
12457 int error_no;
12458 rb_off_t total;
12459 const char *syserr;
12460 const char *notimp;
12461 VALUE th;
12462 struct stat src_stat;
12463 struct stat dst_stat;
12464#ifdef HAVE_FCOPYFILE
12465 copyfile_state_t copyfile_state;
12466#endif
12467};
12468
12469static void *
12470exec_interrupts(void *arg)
12471{
12472 VALUE th = (VALUE)arg;
12473 rb_thread_execute_interrupts(th);
12474 return NULL;
12475}
12476
12477/*
12478 * returns TRUE if the preceding system call was interrupted
12479 * so we can continue. If the thread was interrupted, we
12480 * reacquire the GVL to execute interrupts before continuing.
12481 */
12482static int
12483maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12484{
12485 switch (errno) {
12486 case EINTR:
12487#if defined(ERESTART)
12488 case ERESTART:
12489#endif
12490 if (rb_thread_interrupted(stp->th)) {
12491 if (has_gvl)
12492 rb_thread_execute_interrupts(stp->th);
12493 else
12494 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12495 }
12496 return TRUE;
12497 }
12498 return FALSE;
12499}
12500
12502 VALUE scheduler;
12503
12504 rb_io_t *fptr;
12505 short events;
12506
12507 VALUE result;
12508};
12509
12510static void *
12511fiber_scheduler_wait_for(void * _arguments)
12512{
12513 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12514
12515 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12516
12517 return NULL;
12518}
12519
12520#if USE_POLL
12521# define IOWAIT_SYSCALL "poll"
12522STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12523STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12524static int
12525nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12526{
12528 if (scheduler != Qnil) {
12529 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12530 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12531 return RTEST(args.result);
12532 }
12533
12534 int fd = fptr->fd;
12535 if (fd == -1) return 0;
12536
12537 struct pollfd fds;
12538
12539 fds.fd = fd;
12540 fds.events = events;
12541
12542 int timeout_milliseconds = -1;
12543
12544 if (timeout) {
12545 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12546 }
12547
12548 return poll(&fds, 1, timeout_milliseconds);
12549}
12550#else /* !USE_POLL */
12551# define IOWAIT_SYSCALL "select"
12552static int
12553nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12554{
12556 if (scheduler != Qnil) {
12557 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12558 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12559 return RTEST(args.result);
12560 }
12561
12562 int fd = fptr->fd;
12563
12564 if (fd == -1) {
12565 errno = EBADF;
12566 return -1;
12567 }
12568
12569 rb_fdset_t fds;
12570 int ret;
12571
12572 rb_fd_init(&fds);
12573 rb_fd_set(fd, &fds);
12574
12575 switch (events) {
12576 case RB_WAITFD_IN:
12577 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12578 break;
12579 case RB_WAITFD_OUT:
12580 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12581 break;
12582 default:
12583 VM_UNREACHABLE(nogvl_wait_for);
12584 }
12585
12586 rb_fd_term(&fds);
12587
12588 // On timeout, this returns 0.
12589 return ret;
12590}
12591#endif /* !USE_POLL */
12592
12593static int
12594maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12595{
12596 int ret;
12597
12598 do {
12599 if (has_gvl) {
12601 }
12602 else {
12603 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12604 }
12605 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12606
12607 if (ret < 0) {
12608 stp->syserr = IOWAIT_SYSCALL;
12609 stp->error_no = errno;
12610 return ret;
12611 }
12612 return 0;
12613}
12614
12615static int
12616nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12617{
12618 int ret;
12619
12620 do {
12621 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12622 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12623
12624 if (ret < 0) {
12625 stp->syserr = IOWAIT_SYSCALL;
12626 stp->error_no = errno;
12627 return ret;
12628 }
12629 return 0;
12630}
12631
12632#ifdef USE_COPY_FILE_RANGE
12633
12634static ssize_t
12635simple_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)
12636{
12637#ifdef HAVE_COPY_FILE_RANGE
12638 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12639#else
12640 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12641#endif
12642}
12643
12644static int
12645nogvl_copy_file_range(struct copy_stream_struct *stp)
12646{
12647 ssize_t ss;
12648 rb_off_t src_size;
12649 rb_off_t copy_length, src_offset, *src_offset_ptr;
12650
12651 if (!S_ISREG(stp->src_stat.st_mode))
12652 return 0;
12653
12654 src_size = stp->src_stat.st_size;
12655 src_offset = stp->src_offset;
12656 if (src_offset >= (rb_off_t)0) {
12657 src_offset_ptr = &src_offset;
12658 }
12659 else {
12660 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12661 }
12662
12663 copy_length = stp->copy_length;
12664 if (copy_length < (rb_off_t)0) {
12665 if (src_offset < (rb_off_t)0) {
12666 rb_off_t current_offset;
12667 errno = 0;
12668 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12669 if (current_offset < (rb_off_t)0 && errno) {
12670 stp->syserr = "lseek";
12671 stp->error_no = errno;
12672 return (int)current_offset;
12673 }
12674 copy_length = src_size - current_offset;
12675 }
12676 else {
12677 copy_length = src_size - src_offset;
12678 }
12679 }
12680
12681 retry_copy_file_range:
12682# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12683 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12684 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12685# else
12686 ss = (ssize_t)copy_length;
12687# endif
12688 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12689 if (0 < ss) {
12690 stp->total += ss;
12691 copy_length -= ss;
12692 if (0 < copy_length) {
12693 goto retry_copy_file_range;
12694 }
12695 }
12696 if (ss < 0) {
12697 if (maygvl_copy_stream_continue_p(0, stp)) {
12698 goto retry_copy_file_range;
12699 }
12700 switch (errno) {
12701 case EINVAL:
12702 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12703 docker container) */
12704#ifdef ENOSYS
12705 case ENOSYS:
12706#endif
12707#ifdef EXDEV
12708 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12709#endif
12710 return 0;
12711 case EAGAIN:
12712#if EWOULDBLOCK != EAGAIN
12713 case EWOULDBLOCK:
12714#endif
12715 {
12716 int ret = nogvl_copy_stream_wait_write(stp);
12717 if (ret < 0) return ret;
12718 }
12719 goto retry_copy_file_range;
12720 case EBADF:
12721 {
12722 int e = errno;
12723 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12724
12725 if (flags != -1 && flags & O_APPEND) {
12726 return 0;
12727 }
12728 errno = e;
12729 }
12730 }
12731 stp->syserr = "copy_file_range";
12732 stp->error_no = errno;
12733 return (int)ss;
12734 }
12735 return 1;
12736}
12737#endif
12738
12739#ifdef HAVE_FCOPYFILE
12740static int
12741nogvl_fcopyfile(struct copy_stream_struct *stp)
12742{
12743 rb_off_t cur, ss = 0;
12744 const rb_off_t src_offset = stp->src_offset;
12745 int ret;
12746
12747 if (stp->copy_length >= (rb_off_t)0) {
12748 /* copy_length can't be specified in fcopyfile(3) */
12749 return 0;
12750 }
12751
12752 if (!S_ISREG(stp->src_stat.st_mode))
12753 return 0;
12754
12755 if (!S_ISREG(stp->dst_stat.st_mode))
12756 return 0;
12757 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12758 return 0;
12759 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12760 /* fcopyfile(3) appends src IO to dst IO and then truncates
12761 * dst IO to src IO's original size. */
12762 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12763 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12764 if (end > (rb_off_t)0) return 0;
12765 }
12766
12767 if (src_offset > (rb_off_t)0) {
12768 rb_off_t r;
12769
12770 /* get current offset */
12771 errno = 0;
12772 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12773 if (cur < (rb_off_t)0 && errno) {
12774 stp->error_no = errno;
12775 return 1;
12776 }
12777
12778 errno = 0;
12779 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12780 if (r < (rb_off_t)0 && errno) {
12781 stp->error_no = errno;
12782 return 1;
12783 }
12784 }
12785
12786 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12787 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12788 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12789
12790 if (ret == 0) { /* success */
12791 stp->total = ss;
12792 if (src_offset > (rb_off_t)0) {
12793 rb_off_t r;
12794 errno = 0;
12795 /* reset offset */
12796 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12797 if (r < (rb_off_t)0 && errno) {
12798 stp->error_no = errno;
12799 return 1;
12800 }
12801 }
12802 }
12803 else {
12804 switch (errno) {
12805 case ENOTSUP:
12806 case EPERM:
12807 case EINVAL:
12808 return 0;
12809 }
12810 stp->syserr = "fcopyfile";
12811 stp->error_no = errno;
12812 return (int)ret;
12813 }
12814 return 1;
12815}
12816#endif
12817
12818#ifdef HAVE_SENDFILE
12819
12820# ifdef __linux__
12821# define USE_SENDFILE
12822
12823# ifdef HAVE_SYS_SENDFILE_H
12824# include <sys/sendfile.h>
12825# endif
12826
12827static ssize_t
12828simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12829{
12830 return sendfile(out_fd, in_fd, offset, (size_t)count);
12831}
12832
12833# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12834/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12835 * without cpuset -l 0.
12836 */
12837# define USE_SENDFILE
12838
12839static ssize_t
12840simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12841{
12842 int r;
12843 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12844 rb_off_t sbytes;
12845# ifdef __APPLE__
12846 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12847 sbytes = count;
12848# else
12849 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12850# endif
12851 if (r != 0 && sbytes == 0) return r;
12852 if (offset) {
12853 *offset += sbytes;
12854 }
12855 else {
12856 lseek(in_fd, sbytes, SEEK_CUR);
12857 }
12858 return (ssize_t)sbytes;
12859}
12860
12861# endif
12862
12863#endif
12864
12865#ifdef USE_SENDFILE
12866static int
12867nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12868{
12869 ssize_t ss;
12870 rb_off_t src_size;
12871 rb_off_t copy_length;
12872 rb_off_t src_offset;
12873 int use_pread;
12874
12875 if (!S_ISREG(stp->src_stat.st_mode))
12876 return 0;
12877
12878 src_size = stp->src_stat.st_size;
12879#ifndef __linux__
12880 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12881 return 0;
12882#endif
12883
12884 src_offset = stp->src_offset;
12885 use_pread = src_offset >= (rb_off_t)0;
12886
12887 copy_length = stp->copy_length;
12888 if (copy_length < (rb_off_t)0) {
12889 if (use_pread)
12890 copy_length = src_size - src_offset;
12891 else {
12892 rb_off_t cur;
12893 errno = 0;
12894 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12895 if (cur < (rb_off_t)0 && errno) {
12896 stp->syserr = "lseek";
12897 stp->error_no = errno;
12898 return (int)cur;
12899 }
12900 copy_length = src_size - cur;
12901 }
12902 }
12903
12904 retry_sendfile:
12905# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12906 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12907 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12908# else
12909 ss = (ssize_t)copy_length;
12910# endif
12911 if (use_pread) {
12912 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12913 }
12914 else {
12915 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12916 }
12917 if (0 < ss) {
12918 stp->total += ss;
12919 copy_length -= ss;
12920 if (0 < copy_length) {
12921 goto retry_sendfile;
12922 }
12923 }
12924 if (ss < 0) {
12925 if (maygvl_copy_stream_continue_p(0, stp))
12926 goto retry_sendfile;
12927 switch (errno) {
12928 case EINVAL:
12929#ifdef ENOSYS
12930 case ENOSYS:
12931#endif
12932#ifdef EOPNOTSUP
12933 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12934 see also: [Feature #16965] */
12935 case EOPNOTSUP:
12936#endif
12937 return 0;
12938 case EAGAIN:
12939#if EWOULDBLOCK != EAGAIN
12940 case EWOULDBLOCK:
12941#endif
12942 {
12943 int ret;
12944#ifndef __linux__
12945 /*
12946 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12947 * select() reports regular files to always be "ready", so
12948 * there is no need to select() on it.
12949 * Other OSes may have the same limitation for sendfile() which
12950 * allow us to bypass maygvl_copy_stream_wait_read()...
12951 */
12952 ret = maygvl_copy_stream_wait_read(0, stp);
12953 if (ret < 0) return ret;
12954#endif
12955 ret = nogvl_copy_stream_wait_write(stp);
12956 if (ret < 0) return ret;
12957 }
12958 goto retry_sendfile;
12959 }
12960 stp->syserr = "sendfile";
12961 stp->error_no = errno;
12962 return (int)ss;
12963 }
12964 return 1;
12965}
12966#endif
12967
12968static ssize_t
12969maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
12970{
12971 if (has_gvl)
12972 return rb_io_read_memory(fptr, buf, count);
12973 else
12974 return read(fptr->fd, buf, count);
12975}
12976
12977static ssize_t
12978maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
12979{
12980 ssize_t ss;
12981 retry_read:
12982 if (offset < (rb_off_t)0) {
12983 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
12984 }
12985 else {
12986 ss = pread(stp->src_fptr->fd, buf, len, offset);
12987 }
12988 if (ss == 0) {
12989 return 0;
12990 }
12991 if (ss < 0) {
12992 if (maygvl_copy_stream_continue_p(has_gvl, stp))
12993 goto retry_read;
12994 switch (errno) {
12995 case EAGAIN:
12996#if EWOULDBLOCK != EAGAIN
12997 case EWOULDBLOCK:
12998#endif
12999 {
13000 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13001 if (ret < 0) return ret;
13002 }
13003 goto retry_read;
13004#ifdef ENOSYS
13005 case ENOSYS:
13006 stp->notimp = "pread";
13007 return ss;
13008#endif
13009 }
13010 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13011 stp->error_no = errno;
13012 }
13013 return ss;
13014}
13015
13016static int
13017nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13018{
13019 ssize_t ss;
13020 int off = 0;
13021 while (len) {
13022 ss = write(stp->dst_fptr->fd, buf+off, len);
13023 if (ss < 0) {
13024 if (maygvl_copy_stream_continue_p(0, stp))
13025 continue;
13026 if (io_again_p(errno)) {
13027 int ret = nogvl_copy_stream_wait_write(stp);
13028 if (ret < 0) return ret;
13029 continue;
13030 }
13031 stp->syserr = "write";
13032 stp->error_no = errno;
13033 return (int)ss;
13034 }
13035 off += (int)ss;
13036 len -= (int)ss;
13037 stp->total += ss;
13038 }
13039 return 0;
13040}
13041
13042static void
13043nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13044{
13045 char buf[1024*16];
13046 size_t len;
13047 ssize_t ss;
13048 int ret;
13049 rb_off_t copy_length;
13050 rb_off_t src_offset;
13051 int use_eof;
13052 int use_pread;
13053
13054 copy_length = stp->copy_length;
13055 use_eof = copy_length < (rb_off_t)0;
13056 src_offset = stp->src_offset;
13057 use_pread = src_offset >= (rb_off_t)0;
13058
13059 if (use_pread && stp->close_src) {
13060 rb_off_t r;
13061 errno = 0;
13062 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13063 if (r < (rb_off_t)0 && errno) {
13064 stp->syserr = "lseek";
13065 stp->error_no = errno;
13066 return;
13067 }
13068 src_offset = (rb_off_t)-1;
13069 use_pread = 0;
13070 }
13071
13072 while (use_eof || 0 < copy_length) {
13073 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13074 len = (size_t)copy_length;
13075 }
13076 else {
13077 len = sizeof(buf);
13078 }
13079 if (use_pread) {
13080 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13081 if (0 < ss)
13082 src_offset += ss;
13083 }
13084 else {
13085 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13086 }
13087 if (ss <= 0) /* EOF or error */
13088 return;
13089
13090 ret = nogvl_copy_stream_write(stp, buf, ss);
13091 if (ret < 0)
13092 return;
13093
13094 if (!use_eof)
13095 copy_length -= ss;
13096 }
13097}
13098
13099static void *
13100nogvl_copy_stream_func(void *arg)
13101{
13102 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13103#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13104 int ret;
13105#endif
13106
13107#ifdef USE_COPY_FILE_RANGE
13108 ret = nogvl_copy_file_range(stp);
13109 if (ret != 0)
13110 goto finish; /* error or success */
13111#endif
13112
13113#ifdef HAVE_FCOPYFILE
13114 ret = nogvl_fcopyfile(stp);
13115 if (ret != 0)
13116 goto finish; /* error or success */
13117#endif
13118
13119#ifdef USE_SENDFILE
13120 ret = nogvl_copy_stream_sendfile(stp);
13121 if (ret != 0)
13122 goto finish; /* error or success */
13123#endif
13124
13125 nogvl_copy_stream_read_write(stp);
13126
13127#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13128 finish:
13129#endif
13130 return 0;
13131}
13132
13133static VALUE
13134copy_stream_fallback_body(VALUE arg)
13135{
13136 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13137 const int buflen = 16*1024;
13138 VALUE n;
13139 VALUE buf = rb_str_buf_new(buflen);
13140 rb_off_t rest = stp->copy_length;
13141 rb_off_t off = stp->src_offset;
13142 ID read_method = id_readpartial;
13143
13144 if (!stp->src_fptr) {
13145 if (!rb_respond_to(stp->src, read_method)) {
13146 read_method = id_read;
13147 }
13148 }
13149
13150 while (1) {
13151 long numwrote;
13152 long l;
13153 rb_str_make_independent(buf);
13154 if (stp->copy_length < (rb_off_t)0) {
13155 l = buflen;
13156 }
13157 else {
13158 if (rest == 0) {
13159 rb_str_resize(buf, 0);
13160 break;
13161 }
13162 l = buflen < rest ? buflen : (long)rest;
13163 }
13164 if (!stp->src_fptr) {
13165 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13166
13167 if (read_method == id_read && NIL_P(rc))
13168 break;
13169 }
13170 else {
13171 ssize_t ss;
13172 rb_str_resize(buf, buflen);
13173 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13174 rb_str_resize(buf, ss > 0 ? ss : 0);
13175 if (ss < 0)
13176 return Qnil;
13177 if (ss == 0)
13178 rb_eof_error();
13179 if (off >= (rb_off_t)0)
13180 off += ss;
13181 }
13182 n = rb_io_write(stp->dst, buf);
13183 numwrote = NUM2LONG(n);
13184 stp->total += numwrote;
13185 rest -= numwrote;
13186 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13187 break;
13188 }
13189 }
13190
13191 return Qnil;
13192}
13193
13194static VALUE
13195copy_stream_fallback(struct copy_stream_struct *stp)
13196{
13197 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13198 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13199 }
13200 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13201 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13202 rb_eEOFError, (VALUE)0);
13203 return Qnil;
13204}
13205
13206static VALUE
13207copy_stream_body(VALUE arg)
13208{
13209 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13210 VALUE src_io = stp->src, dst_io = stp->dst;
13211 const int common_oflags = 0
13212#ifdef O_NOCTTY
13213 | O_NOCTTY
13214#endif
13215 ;
13216
13217 stp->th = rb_thread_current();
13218
13219 stp->total = 0;
13220
13221 if (src_io == argf ||
13222 !(RB_TYPE_P(src_io, T_FILE) ||
13223 RB_TYPE_P(src_io, T_STRING) ||
13224 rb_respond_to(src_io, rb_intern("to_path")))) {
13225 stp->src_fptr = NULL;
13226 }
13227 else {
13228 int stat_ret;
13229 VALUE tmp_io = rb_io_check_io(src_io);
13230 if (!NIL_P(tmp_io)) {
13231 src_io = tmp_io;
13232 }
13233 else if (!RB_TYPE_P(src_io, T_FILE)) {
13234 VALUE args[2];
13235 FilePathValue(src_io);
13236 args[0] = src_io;
13237 args[1] = INT2NUM(O_RDONLY|common_oflags);
13238 src_io = rb_class_new_instance(2, args, rb_cFile);
13239 stp->src = src_io;
13240 stp->close_src = 1;
13241 }
13242 RB_IO_POINTER(src_io, stp->src_fptr);
13243 rb_io_check_byte_readable(stp->src_fptr);
13244
13245 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13246 if (stat_ret < 0) {
13247 stp->syserr = "fstat";
13248 stp->error_no = errno;
13249 return Qnil;
13250 }
13251 }
13252
13253 if (dst_io == argf ||
13254 !(RB_TYPE_P(dst_io, T_FILE) ||
13255 RB_TYPE_P(dst_io, T_STRING) ||
13256 rb_respond_to(dst_io, rb_intern("to_path")))) {
13257 stp->dst_fptr = NULL;
13258 }
13259 else {
13260 int stat_ret;
13261 VALUE tmp_io = rb_io_check_io(dst_io);
13262 if (!NIL_P(tmp_io)) {
13263 dst_io = GetWriteIO(tmp_io);
13264 }
13265 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13266 VALUE args[3];
13267 FilePathValue(dst_io);
13268 args[0] = dst_io;
13269 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13270 args[2] = INT2FIX(0666);
13271 dst_io = rb_class_new_instance(3, args, rb_cFile);
13272 stp->dst = dst_io;
13273 stp->close_dst = 1;
13274 }
13275 else {
13276 dst_io = GetWriteIO(dst_io);
13277 stp->dst = dst_io;
13278 }
13279 RB_IO_POINTER(dst_io, stp->dst_fptr);
13280 rb_io_check_writable(stp->dst_fptr);
13281
13282 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13283 if (stat_ret < 0) {
13284 stp->syserr = "fstat";
13285 stp->error_no = errno;
13286 return Qnil;
13287 }
13288 }
13289
13290#ifdef O_BINARY
13291 if (stp->src_fptr)
13292 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13293#endif
13294 if (stp->dst_fptr)
13295 io_ascii8bit_binmode(stp->dst_fptr);
13296
13297 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13298 size_t len = stp->src_fptr->rbuf.len;
13299 VALUE str;
13300 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13301 len = (size_t)stp->copy_length;
13302 }
13303 str = rb_str_buf_new(len);
13304 rb_str_resize(str,len);
13305 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13306 if (stp->dst_fptr) { /* IO or filename */
13307 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13308 rb_sys_fail_on_write(stp->dst_fptr);
13309 }
13310 else /* others such as StringIO */
13311 rb_io_write(dst_io, str);
13312 rb_str_resize(str, 0);
13313 stp->total += len;
13314 if (stp->copy_length >= (rb_off_t)0)
13315 stp->copy_length -= len;
13316 }
13317
13318 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13319 rb_raise(rb_eIOError, "flush failed");
13320 }
13321
13322 if (stp->copy_length == 0)
13323 return Qnil;
13324
13325 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13326 return copy_stream_fallback(stp);
13327 }
13328
13329 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13330 return Qnil;
13331}
13332
13333static VALUE
13334copy_stream_finalize(VALUE arg)
13335{
13336 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13337
13338#ifdef HAVE_FCOPYFILE
13339 if (stp->copyfile_state) {
13340 copyfile_state_free(stp->copyfile_state);
13341 }
13342#endif
13343
13344 if (stp->close_src) {
13345 rb_io_close_m(stp->src);
13346 }
13347 if (stp->close_dst) {
13348 rb_io_close_m(stp->dst);
13349 }
13350 if (stp->syserr) {
13351 rb_syserr_fail(stp->error_no, stp->syserr);
13352 }
13353 if (stp->notimp) {
13354 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13355 }
13356 return Qnil;
13357}
13358
13359/*
13360 * call-seq:
13361 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13362 *
13363 * Copies from the given +src+ to the given +dst+,
13364 * returning the number of bytes copied.
13365 *
13366 * - The given +src+ must be one of the following:
13367 *
13368 * - The path to a readable file, from which source data is to be read.
13369 * - An \IO-like object, opened for reading and capable of responding
13370 * to method +:readpartial+ or method +:read+.
13371 *
13372 * - The given +dst+ must be one of the following:
13373 *
13374 * - The path to a writable file, to which data is to be written.
13375 * - An \IO-like object, opened for writing and capable of responding
13376 * to method +:write+.
13377 *
13378 * The examples here use file <tt>t.txt</tt> as source:
13379 *
13380 * File.read('t.txt')
13381 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13382 * File.read('t.txt').size # => 47
13383 *
13384 * If only arguments +src+ and +dst+ are given,
13385 * the entire source stream is copied:
13386 *
13387 * # Paths.
13388 * IO.copy_stream('t.txt', 't.tmp') # => 47
13389 *
13390 * # IOs (recall that a File is also an IO).
13391 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13392 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13393 * IO.copy_stream(src_io, dst_io) # => 47
13394 * src_io.close
13395 * dst_io.close
13396 *
13397 * With argument +src_length+ a non-negative integer,
13398 * no more than that many bytes are copied:
13399 *
13400 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13401 * File.read('t.tmp') # => "First line"
13402 *
13403 * With argument +src_offset+ also given,
13404 * the source stream is read beginning at that offset:
13405 *
13406 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13407 * IO.read('t.tmp') # => "Second line"
13408 *
13409 */
13410static VALUE
13411rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13412{
13413 VALUE src, dst, length, src_offset;
13414 struct copy_stream_struct st;
13415
13416 MEMZERO(&st, struct copy_stream_struct, 1);
13417
13418 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13419
13420 st.src = src;
13421 st.dst = dst;
13422
13423 st.src_fptr = NULL;
13424 st.dst_fptr = NULL;
13425
13426 if (NIL_P(length))
13427 st.copy_length = (rb_off_t)-1;
13428 else
13429 st.copy_length = NUM2OFFT(length);
13430
13431 if (NIL_P(src_offset))
13432 st.src_offset = (rb_off_t)-1;
13433 else
13434 st.src_offset = NUM2OFFT(src_offset);
13435
13436 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13437
13438 return OFFT2NUM(st.total);
13439}
13440
13441/*
13442 * call-seq:
13443 * external_encoding -> encoding or nil
13444 *
13445 * Returns the Encoding object that represents the encoding of the stream,
13446 * or +nil+ if the stream is in write mode and no encoding is specified.
13447 *
13448 * See {Encodings}[rdoc-ref:File@Encodings].
13449 *
13450 */
13451
13452static VALUE
13453rb_io_external_encoding(VALUE io)
13454{
13455 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13456
13457 if (fptr->encs.enc2) {
13458 return rb_enc_from_encoding(fptr->encs.enc2);
13459 }
13460 if (fptr->mode & FMODE_WRITABLE) {
13461 if (fptr->encs.enc)
13462 return rb_enc_from_encoding(fptr->encs.enc);
13463 return Qnil;
13464 }
13465 return rb_enc_from_encoding(io_read_encoding(fptr));
13466}
13467
13468/*
13469 * call-seq:
13470 * internal_encoding -> encoding or nil
13471 *
13472 * Returns the Encoding object that represents the encoding of the internal string,
13473 * if conversion is specified,
13474 * or +nil+ otherwise.
13475 *
13476 * See {Encodings}[rdoc-ref:File@Encodings].
13477 *
13478 */
13479
13480static VALUE
13481rb_io_internal_encoding(VALUE io)
13482{
13483 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13484
13485 if (!fptr->encs.enc2) return Qnil;
13486 return rb_enc_from_encoding(io_read_encoding(fptr));
13487}
13488
13489/*
13490 * call-seq:
13491 * set_encoding(ext_enc) -> self
13492 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13493 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13494 *
13495 * See {Encodings}[rdoc-ref:File@Encodings].
13496 *
13497 * Argument +ext_enc+, if given, must be an Encoding object
13498 * or a String with the encoding name;
13499 * it is assigned as the encoding for the stream.
13500 *
13501 * Argument +int_enc+, if given, must be an Encoding object
13502 * or a String with the encoding name;
13503 * it is assigned as the encoding for the internal string.
13504 *
13505 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13506 * containing two colon-separated encoding names;
13507 * corresponding Encoding objects are assigned as the external
13508 * and internal encodings for the stream.
13509 *
13510 * If the external encoding of a string is binary/ASCII-8BIT,
13511 * the internal encoding of the string is set to nil, since no
13512 * transcoding is needed.
13513 *
13514 * Optional keyword arguments +enc_opts+ specify
13515 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13516 *
13517 */
13518
13519static VALUE
13520rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13521{
13522 rb_io_t *fptr;
13523 VALUE v1, v2, opt;
13524
13525 if (!RB_TYPE_P(io, T_FILE)) {
13526 return forward(io, id_set_encoding, argc, argv);
13527 }
13528
13529 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13530 GetOpenFile(io, fptr);
13531 io_encoding_set(fptr, v1, v2, opt);
13532 return io;
13533}
13534
13535void
13536rb_stdio_set_default_encoding(void)
13537{
13538 VALUE val = Qnil;
13539
13540#ifdef _WIN32
13541 if (isatty(fileno(stdin))) {
13542 rb_encoding *external = rb_locale_encoding();
13543 rb_encoding *internal = rb_default_internal_encoding();
13544 if (!internal) internal = rb_default_external_encoding();
13545 io_encoding_set(RFILE(rb_stdin)->fptr,
13546 rb_enc_from_encoding(external),
13547 rb_enc_from_encoding(internal),
13548 Qnil);
13549 }
13550 else
13551#endif
13552 rb_io_set_encoding(1, &val, rb_stdin);
13553 rb_io_set_encoding(1, &val, rb_stdout);
13554 rb_io_set_encoding(1, &val, rb_stderr);
13555}
13556
13557static inline int
13558global_argf_p(VALUE arg)
13559{
13560 return arg == argf;
13561}
13562
13563typedef VALUE (*argf_encoding_func)(VALUE io);
13564
13565static VALUE
13566argf_encoding(VALUE argf, argf_encoding_func func)
13567{
13568 if (!RTEST(ARGF.current_file)) {
13569 return rb_enc_default_external();
13570 }
13571 return func(rb_io_check_io(ARGF.current_file));
13572}
13573
13574/*
13575 * call-seq:
13576 * ARGF.external_encoding -> encoding
13577 *
13578 * Returns the external encoding for files read from ARGF as an Encoding
13579 * object. The external encoding is the encoding of the text as stored in a
13580 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13581 * represent this text within Ruby.
13582 *
13583 * To set the external encoding use ARGF.set_encoding.
13584 *
13585 * For example:
13586 *
13587 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13588 *
13589 */
13590static VALUE
13591argf_external_encoding(VALUE argf)
13592{
13593 return argf_encoding(argf, rb_io_external_encoding);
13594}
13595
13596/*
13597 * call-seq:
13598 * ARGF.internal_encoding -> encoding
13599 *
13600 * Returns the internal encoding for strings read from ARGF as an
13601 * Encoding object.
13602 *
13603 * If ARGF.set_encoding has been called with two encoding names, the second
13604 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13605 * value is returned. Failing that, if a default external encoding was
13606 * specified on the command-line, that value is used. If the encoding is
13607 * unknown, +nil+ is returned.
13608 */
13609static VALUE
13610argf_internal_encoding(VALUE argf)
13611{
13612 return argf_encoding(argf, rb_io_internal_encoding);
13613}
13614
13615/*
13616 * call-seq:
13617 * ARGF.set_encoding(ext_enc) -> ARGF
13618 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13619 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13620 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13621 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13622 *
13623 * If single argument is specified, strings read from ARGF are tagged with
13624 * the encoding specified.
13625 *
13626 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13627 * the read string is converted from the first encoding (external encoding)
13628 * to the second encoding (internal encoding), then tagged with the second
13629 * encoding.
13630 *
13631 * If two arguments are specified, they must be encoding objects or encoding
13632 * names. Again, the first specifies the external encoding; the second
13633 * specifies the internal encoding.
13634 *
13635 * If the external encoding and the internal encoding are specified, the
13636 * optional Hash argument can be used to adjust the conversion process. The
13637 * structure of this hash is explained in the String#encode documentation.
13638 *
13639 * For example:
13640 *
13641 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13642 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13643 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13644 * # to UTF-8.
13645 */
13646static VALUE
13647argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13648{
13649 rb_io_t *fptr;
13650
13651 if (!next_argv()) {
13652 rb_raise(rb_eArgError, "no stream to set encoding");
13653 }
13654 rb_io_set_encoding(argc, argv, ARGF.current_file);
13655 GetOpenFile(ARGF.current_file, fptr);
13656 ARGF.encs = fptr->encs;
13657 return argf;
13658}
13659
13660/*
13661 * call-seq:
13662 * ARGF.tell -> Integer
13663 * ARGF.pos -> Integer
13664 *
13665 * Returns the current offset (in bytes) of the current file in ARGF.
13666 *
13667 * ARGF.pos #=> 0
13668 * ARGF.gets #=> "This is line one\n"
13669 * ARGF.pos #=> 17
13670 *
13671 */
13672static VALUE
13673argf_tell(VALUE argf)
13674{
13675 if (!next_argv()) {
13676 rb_raise(rb_eArgError, "no stream to tell");
13677 }
13678 ARGF_FORWARD(0, 0);
13679 return rb_io_tell(ARGF.current_file);
13680}
13681
13682/*
13683 * call-seq:
13684 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13685 *
13686 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13687 * the value of _whence_. See IO#seek for further details.
13688 */
13689static VALUE
13690argf_seek_m(int argc, VALUE *argv, VALUE argf)
13691{
13692 if (!next_argv()) {
13693 rb_raise(rb_eArgError, "no stream to seek");
13694 }
13695 ARGF_FORWARD(argc, argv);
13696 return rb_io_seek_m(argc, argv, ARGF.current_file);
13697}
13698
13699/*
13700 * call-seq:
13701 * ARGF.pos = position -> Integer
13702 *
13703 * Seeks to the position given by _position_ (in bytes) in ARGF.
13704 *
13705 * For example:
13706 *
13707 * ARGF.pos = 17
13708 * ARGF.gets #=> "This is line two\n"
13709 */
13710static VALUE
13711argf_set_pos(VALUE argf, VALUE offset)
13712{
13713 if (!next_argv()) {
13714 rb_raise(rb_eArgError, "no stream to set position");
13715 }
13716 ARGF_FORWARD(1, &offset);
13717 return rb_io_set_pos(ARGF.current_file, offset);
13718}
13719
13720/*
13721 * call-seq:
13722 * ARGF.rewind -> 0
13723 *
13724 * Positions the current file to the beginning of input, resetting
13725 * ARGF.lineno to zero.
13726 *
13727 * ARGF.readline #=> "This is line one\n"
13728 * ARGF.rewind #=> 0
13729 * ARGF.lineno #=> 0
13730 * ARGF.readline #=> "This is line one\n"
13731 */
13732static VALUE
13733argf_rewind(VALUE argf)
13734{
13735 VALUE ret;
13736 int old_lineno;
13737
13738 if (!next_argv()) {
13739 rb_raise(rb_eArgError, "no stream to rewind");
13740 }
13741 ARGF_FORWARD(0, 0);
13742 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13743 ret = rb_io_rewind(ARGF.current_file);
13744 if (!global_argf_p(argf)) {
13745 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13746 }
13747 return ret;
13748}
13749
13750/*
13751 * call-seq:
13752 * ARGF.fileno -> integer
13753 * ARGF.to_i -> integer
13754 *
13755 * Returns an integer representing the numeric file descriptor for
13756 * the current file. Raises an ArgumentError if there isn't a current file.
13757 *
13758 * ARGF.fileno #=> 3
13759 */
13760static VALUE
13761argf_fileno(VALUE argf)
13762{
13763 if (!next_argv()) {
13764 rb_raise(rb_eArgError, "no stream");
13765 }
13766 ARGF_FORWARD(0, 0);
13767 return rb_io_fileno(ARGF.current_file);
13768}
13769
13770/*
13771 * call-seq:
13772 * ARGF.to_io -> IO
13773 *
13774 * Returns an IO object representing the current file. This will be a
13775 * File object unless the current file is a stream such as STDIN.
13776 *
13777 * For example:
13778 *
13779 * ARGF.to_io #=> #<File:glark.txt>
13780 * ARGF.to_io #=> #<IO:<STDIN>>
13781 */
13782static VALUE
13783argf_to_io(VALUE argf)
13784{
13785 next_argv();
13786 ARGF_FORWARD(0, 0);
13787 return ARGF.current_file;
13788}
13789
13790/*
13791 * call-seq:
13792 * ARGF.eof? -> true or false
13793 * ARGF.eof -> true or false
13794 *
13795 * Returns true if the current file in ARGF is at end of file, i.e. it has
13796 * no data to read. The stream must be opened for reading or an IOError
13797 * will be raised.
13798 *
13799 * $ echo "eof" | ruby argf.rb
13800 *
13801 * ARGF.eof? #=> false
13802 * 3.times { ARGF.readchar }
13803 * ARGF.eof? #=> false
13804 * ARGF.readchar #=> "\n"
13805 * ARGF.eof? #=> true
13806 */
13807
13808static VALUE
13809argf_eof(VALUE argf)
13810{
13811 next_argv();
13812 if (RTEST(ARGF.current_file)) {
13813 if (ARGF.init_p == 0) return Qtrue;
13814 next_argv();
13815 ARGF_FORWARD(0, 0);
13816 if (rb_io_eof(ARGF.current_file)) {
13817 return Qtrue;
13818 }
13819 }
13820 return Qfalse;
13821}
13822
13823/*
13824 * call-seq:
13825 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13826 *
13827 * Reads _length_ bytes from ARGF. The files named on the command line
13828 * are concatenated and treated as a single file by this method, so when
13829 * called without arguments the contents of this pseudo file are returned in
13830 * their entirety.
13831 *
13832 * _length_ must be a non-negative integer or +nil+.
13833 *
13834 * If _length_ is a positive integer, +read+ tries to read
13835 * _length_ bytes without any conversion (binary mode).
13836 * It returns +nil+ if an EOF is encountered before anything can be read.
13837 * Fewer than _length_ bytes are returned if an EOF is encountered during
13838 * the read.
13839 * In the case of an integer _length_, the resulting string is always
13840 * in ASCII-8BIT encoding.
13841 *
13842 * If _length_ is omitted or is +nil+, it reads until EOF
13843 * and the encoding conversion is applied, if applicable.
13844 * A string is returned even if EOF is encountered before any data is read.
13845 *
13846 * If _length_ is zero, it returns an empty string (<code>""</code>).
13847 *
13848 * If the optional _outbuf_ argument is present,
13849 * it must reference a String, which will receive the data.
13850 * The _outbuf_ will contain only the received data after the method call
13851 * even if it is not empty at the beginning.
13852 *
13853 * For example:
13854 *
13855 * $ echo "small" > small.txt
13856 * $ echo "large" > large.txt
13857 * $ ./glark.rb small.txt large.txt
13858 *
13859 * ARGF.read #=> "small\nlarge"
13860 * ARGF.read(200) #=> "small\nlarge"
13861 * ARGF.read(2) #=> "sm"
13862 * ARGF.read(0) #=> ""
13863 *
13864 * Note that this method behaves like the fread() function in C.
13865 * This means it retries to invoke read(2) system calls to read data
13866 * with the specified length.
13867 * If you need the behavior like a single read(2) system call,
13868 * consider ARGF#readpartial or ARGF#read_nonblock.
13869 */
13870
13871static VALUE
13872argf_read(int argc, VALUE *argv, VALUE argf)
13873{
13874 VALUE tmp, str, length;
13875 long len = 0;
13876
13877 rb_scan_args(argc, argv, "02", &length, &str);
13878 if (!NIL_P(length)) {
13879 len = NUM2LONG(argv[0]);
13880 }
13881 if (!NIL_P(str)) {
13882 StringValue(str);
13883 rb_str_resize(str,0);
13884 argv[1] = Qnil;
13885 }
13886
13887 retry:
13888 if (!next_argv()) {
13889 return str;
13890 }
13891 if (ARGF_GENERIC_INPUT_P()) {
13892 tmp = argf_forward(argc, argv, argf);
13893 }
13894 else {
13895 tmp = io_read(argc, argv, ARGF.current_file);
13896 }
13897 if (NIL_P(str)) str = tmp;
13898 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13899 if (NIL_P(tmp) || NIL_P(length)) {
13900 if (ARGF.next_p != -1) {
13901 argf_close(argf);
13902 ARGF.next_p = 1;
13903 goto retry;
13904 }
13905 }
13906 else if (argc >= 1) {
13907 long slen = RSTRING_LEN(str);
13908 if (slen < len) {
13909 argv[0] = LONG2NUM(len - slen);
13910 goto retry;
13911 }
13912 }
13913 return str;
13914}
13915
13917 int argc;
13918 VALUE *argv;
13919 VALUE argf;
13920};
13921
13922static VALUE
13923argf_forward_call(VALUE arg)
13924{
13925 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13926 argf_forward(p->argc, p->argv, p->argf);
13927 return Qnil;
13928}
13929
13930static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13931 int nonblock);
13932
13933/*
13934 * call-seq:
13935 * ARGF.readpartial(maxlen) -> string
13936 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13937 *
13938 * Reads at most _maxlen_ bytes from the ARGF stream.
13939 *
13940 * If the optional _outbuf_ argument is present,
13941 * it must reference a String, which will receive the data.
13942 * The _outbuf_ will contain only the received data after the method call
13943 * even if it is not empty at the beginning.
13944 *
13945 * It raises EOFError on end of ARGF stream.
13946 * Since ARGF stream is a concatenation of multiple files,
13947 * internally EOF is occur for each file.
13948 * ARGF.readpartial returns empty strings for EOFs except the last one and
13949 * raises EOFError for the last one.
13950 *
13951 */
13952
13953static VALUE
13954argf_readpartial(int argc, VALUE *argv, VALUE argf)
13955{
13956 return argf_getpartial(argc, argv, argf, Qnil, 0);
13957}
13958
13959/*
13960 * call-seq:
13961 * ARGF.read_nonblock(maxlen[, options]) -> string
13962 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13963 *
13964 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13965 */
13966
13967static VALUE
13968argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13969{
13970 VALUE opts;
13971
13972 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
13973
13974 if (!NIL_P(opts))
13975 argc--;
13976
13977 return argf_getpartial(argc, argv, argf, opts, 1);
13978}
13979
13980static VALUE
13981argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
13982{
13983 VALUE tmp, str, length;
13984 int no_exception;
13985
13986 rb_scan_args(argc, argv, "11", &length, &str);
13987 if (!NIL_P(str)) {
13988 StringValue(str);
13989 argv[1] = str;
13990 }
13991 no_exception = no_exception_p(opts);
13992
13993 if (!next_argv()) {
13994 if (!NIL_P(str)) {
13995 rb_str_resize(str, 0);
13996 }
13997 rb_eof_error();
13998 }
13999 if (ARGF_GENERIC_INPUT_P()) {
14000 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14001 struct argf_call_arg arg;
14002 arg.argc = argc;
14003 arg.argv = argv;
14004 arg.argf = argf;
14005 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14006 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14007 }
14008 else {
14009 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14010 }
14011 if (NIL_P(tmp)) {
14012 if (ARGF.next_p == -1) {
14013 return io_nonblock_eof(no_exception);
14014 }
14015 argf_close(argf);
14016 ARGF.next_p = 1;
14017 if (RARRAY_LEN(ARGF.argv) == 0) {
14018 return io_nonblock_eof(no_exception);
14019 }
14020 if (NIL_P(str))
14021 str = rb_str_new(NULL, 0);
14022 return str;
14023 }
14024 return tmp;
14025}
14026
14027/*
14028 * call-seq:
14029 * ARGF.getc -> String or nil
14030 *
14031 * Reads the next character from ARGF and returns it as a String. Returns
14032 * +nil+ at the end of the stream.
14033 *
14034 * ARGF treats the files named on the command line as a single file created
14035 * by concatenating their contents. After returning the last character of the
14036 * first file, it returns the first character of the second file, and so on.
14037 *
14038 * For example:
14039 *
14040 * $ echo "foo" > file
14041 * $ ruby argf.rb file
14042 *
14043 * ARGF.getc #=> "f"
14044 * ARGF.getc #=> "o"
14045 * ARGF.getc #=> "o"
14046 * ARGF.getc #=> "\n"
14047 * ARGF.getc #=> nil
14048 * ARGF.getc #=> nil
14049 */
14050static VALUE
14051argf_getc(VALUE argf)
14052{
14053 VALUE ch;
14054
14055 retry:
14056 if (!next_argv()) return Qnil;
14057 if (ARGF_GENERIC_INPUT_P()) {
14058 ch = forward_current(rb_intern("getc"), 0, 0);
14059 }
14060 else {
14061 ch = rb_io_getc(ARGF.current_file);
14062 }
14063 if (NIL_P(ch) && ARGF.next_p != -1) {
14064 argf_close(argf);
14065 ARGF.next_p = 1;
14066 goto retry;
14067 }
14068
14069 return ch;
14070}
14071
14072/*
14073 * call-seq:
14074 * ARGF.getbyte -> Integer or nil
14075 *
14076 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14077 * the end of the stream.
14078 *
14079 * For example:
14080 *
14081 * $ echo "foo" > file
14082 * $ ruby argf.rb file
14083 *
14084 * ARGF.getbyte #=> 102
14085 * ARGF.getbyte #=> 111
14086 * ARGF.getbyte #=> 111
14087 * ARGF.getbyte #=> 10
14088 * ARGF.getbyte #=> nil
14089 */
14090static VALUE
14091argf_getbyte(VALUE argf)
14092{
14093 VALUE ch;
14094
14095 retry:
14096 if (!next_argv()) return Qnil;
14097 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14098 ch = forward_current(rb_intern("getbyte"), 0, 0);
14099 }
14100 else {
14101 ch = rb_io_getbyte(ARGF.current_file);
14102 }
14103 if (NIL_P(ch) && ARGF.next_p != -1) {
14104 argf_close(argf);
14105 ARGF.next_p = 1;
14106 goto retry;
14107 }
14108
14109 return ch;
14110}
14111
14112/*
14113 * call-seq:
14114 * ARGF.readchar -> String or nil
14115 *
14116 * Reads the next character from ARGF and returns it as a String. Raises
14117 * an EOFError after the last character of the last file has been read.
14118 *
14119 * For example:
14120 *
14121 * $ echo "foo" > file
14122 * $ ruby argf.rb file
14123 *
14124 * ARGF.readchar #=> "f"
14125 * ARGF.readchar #=> "o"
14126 * ARGF.readchar #=> "o"
14127 * ARGF.readchar #=> "\n"
14128 * ARGF.readchar #=> end of file reached (EOFError)
14129 */
14130static VALUE
14131argf_readchar(VALUE argf)
14132{
14133 VALUE ch;
14134
14135 retry:
14136 if (!next_argv()) rb_eof_error();
14137 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14138 ch = forward_current(rb_intern("getc"), 0, 0);
14139 }
14140 else {
14141 ch = rb_io_getc(ARGF.current_file);
14142 }
14143 if (NIL_P(ch) && ARGF.next_p != -1) {
14144 argf_close(argf);
14145 ARGF.next_p = 1;
14146 goto retry;
14147 }
14148
14149 return ch;
14150}
14151
14152/*
14153 * call-seq:
14154 * ARGF.readbyte -> Integer
14155 *
14156 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14157 * an EOFError after the last byte of the last file has been read.
14158 *
14159 * For example:
14160 *
14161 * $ echo "foo" > file
14162 * $ ruby argf.rb file
14163 *
14164 * ARGF.readbyte #=> 102
14165 * ARGF.readbyte #=> 111
14166 * ARGF.readbyte #=> 111
14167 * ARGF.readbyte #=> 10
14168 * ARGF.readbyte #=> end of file reached (EOFError)
14169 */
14170static VALUE
14171argf_readbyte(VALUE argf)
14172{
14173 VALUE c;
14174
14175 NEXT_ARGF_FORWARD(0, 0);
14176 c = argf_getbyte(argf);
14177 if (NIL_P(c)) {
14178 rb_eof_error();
14179 }
14180 return c;
14181}
14182
14183#define FOREACH_ARGF() while (next_argv())
14184
14185static VALUE
14186argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14187{
14188 const VALUE current = ARGF.current_file;
14189 rb_yield_values2(argc, argv);
14190 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14192 }
14193 return Qnil;
14194}
14195
14196#define ARGF_block_call(mid, argc, argv, func, argf) \
14197 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14198 func, argf, rb_keyword_given_p())
14199
14200static void
14201argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14202{
14203 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14204 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14205}
14206
14207static VALUE
14208argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14209{
14210 if (!global_argf_p(argf)) {
14211 ARGF.last_lineno = ++ARGF.lineno;
14212 }
14213 return argf_block_call_i(i, argf, argc, argv, blockarg);
14214}
14215
14216static void
14217argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14218{
14219 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14220 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14221}
14222
14223/*
14224 * call-seq:
14225 * ARGF.each(sep=$/) {|line| block } -> ARGF
14226 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14227 * ARGF.each(...) -> an_enumerator
14228 *
14229 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14230 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14231 * ARGF.each_line(...) -> an_enumerator
14232 *
14233 * Returns an enumerator which iterates over each line (separated by _sep_,
14234 * which defaults to your platform's newline character) of each file in
14235 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14236 * block, otherwise an enumerator is returned.
14237 * The optional _limit_ argument is an Integer specifying the maximum
14238 * length of each line; longer lines will be split according to this limit.
14239 *
14240 * This method allows you to treat the files supplied on the command line as
14241 * a single file consisting of the concatenation of each named file. After
14242 * the last line of the first file has been returned, the first line of the
14243 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14244 * used to determine the filename of the current line and line number of the
14245 * whole input, respectively.
14246 *
14247 * For example, the following code prints out each line of each named file
14248 * prefixed with its line number, displaying the filename once per file:
14249 *
14250 * ARGF.each_line do |line|
14251 * puts ARGF.filename if ARGF.file.lineno == 1
14252 * puts "#{ARGF.file.lineno}: #{line}"
14253 * end
14254 *
14255 * While the following code prints only the first file's name at first, and
14256 * the contents with line number counted through all named files.
14257 *
14258 * ARGF.each_line do |line|
14259 * puts ARGF.filename if ARGF.lineno == 1
14260 * puts "#{ARGF.lineno}: #{line}"
14261 * end
14262 */
14263static VALUE
14264argf_each_line(int argc, VALUE *argv, VALUE argf)
14265{
14266 RETURN_ENUMERATOR(argf, argc, argv);
14267 FOREACH_ARGF() {
14268 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14269 }
14270 return argf;
14271}
14272
14273/*
14274 * call-seq:
14275 * ARGF.each_byte {|byte| block } -> ARGF
14276 * ARGF.each_byte -> an_enumerator
14277 *
14278 * Iterates over each byte of each file in +ARGV+.
14279 * A byte is returned as an Integer in the range 0..255.
14280 *
14281 * This method allows you to treat the files supplied on the command line as
14282 * a single file consisting of the concatenation of each named file. After
14283 * the last byte of the first file has been returned, the first byte of the
14284 * second file is returned. The ARGF.filename method can be used to
14285 * determine the filename of the current byte.
14286 *
14287 * If no block is given, an enumerator is returned instead.
14288 *
14289 * For example:
14290 *
14291 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14292 *
14293 */
14294static VALUE
14295argf_each_byte(VALUE argf)
14296{
14297 RETURN_ENUMERATOR(argf, 0, 0);
14298 FOREACH_ARGF() {
14299 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14300 }
14301 return argf;
14302}
14303
14304/*
14305 * call-seq:
14306 * ARGF.each_char {|char| block } -> ARGF
14307 * ARGF.each_char -> an_enumerator
14308 *
14309 * Iterates over each character of each file in ARGF.
14310 *
14311 * This method allows you to treat the files supplied on the command line as
14312 * a single file consisting of the concatenation of each named file. After
14313 * the last character of the first file has been returned, the first
14314 * character of the second file is returned. The ARGF.filename method can
14315 * be used to determine the name of the file in which the current character
14316 * appears.
14317 *
14318 * If no block is given, an enumerator is returned instead.
14319 */
14320static VALUE
14321argf_each_char(VALUE argf)
14322{
14323 RETURN_ENUMERATOR(argf, 0, 0);
14324 FOREACH_ARGF() {
14325 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14326 }
14327 return argf;
14328}
14329
14330/*
14331 * call-seq:
14332 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14333 * ARGF.each_codepoint -> an_enumerator
14334 *
14335 * Iterates over each codepoint of each file in ARGF.
14336 *
14337 * This method allows you to treat the files supplied on the command line as
14338 * a single file consisting of the concatenation of each named file. After
14339 * the last codepoint of the first file has been returned, the first
14340 * codepoint of the second file is returned. The ARGF.filename method can
14341 * be used to determine the name of the file in which the current codepoint
14342 * appears.
14343 *
14344 * If no block is given, an enumerator is returned instead.
14345 */
14346static VALUE
14347argf_each_codepoint(VALUE argf)
14348{
14349 RETURN_ENUMERATOR(argf, 0, 0);
14350 FOREACH_ARGF() {
14351 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14352 }
14353 return argf;
14354}
14355
14356/*
14357 * call-seq:
14358 * ARGF.filename -> String
14359 * ARGF.path -> String
14360 *
14361 * Returns the current filename. "-" is returned when the current file is
14362 * STDIN.
14363 *
14364 * For example:
14365 *
14366 * $ echo "foo" > foo
14367 * $ echo "bar" > bar
14368 * $ echo "glark" > glark
14369 *
14370 * $ ruby argf.rb foo bar glark
14371 *
14372 * ARGF.filename #=> "foo"
14373 * ARGF.read(5) #=> "foo\nb"
14374 * ARGF.filename #=> "bar"
14375 * ARGF.skip
14376 * ARGF.filename #=> "glark"
14377 */
14378static VALUE
14379argf_filename(VALUE argf)
14380{
14381 next_argv();
14382 return ARGF.filename;
14383}
14384
14385static VALUE
14386argf_filename_getter(ID id, VALUE *var)
14387{
14388 return argf_filename(*var);
14389}
14390
14391/*
14392 * call-seq:
14393 * ARGF.file -> IO or File object
14394 *
14395 * Returns the current file as an IO or File object.
14396 * <code>$stdin</code> is returned when the current file is STDIN.
14397 *
14398 * For example:
14399 *
14400 * $ echo "foo" > foo
14401 * $ echo "bar" > bar
14402 *
14403 * $ ruby argf.rb foo bar
14404 *
14405 * ARGF.file #=> #<File:foo>
14406 * ARGF.read(5) #=> "foo\nb"
14407 * ARGF.file #=> #<File:bar>
14408 */
14409static VALUE
14410argf_file(VALUE argf)
14411{
14412 next_argv();
14413 return ARGF.current_file;
14414}
14415
14416/*
14417 * call-seq:
14418 * ARGF.binmode -> ARGF
14419 *
14420 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14421 * be reset to non-binary mode. This option has the following effects:
14422 *
14423 * * Newline conversion is disabled.
14424 * * Encoding conversion is disabled.
14425 * * Content is treated as ASCII-8BIT.
14426 */
14427static VALUE
14428argf_binmode_m(VALUE argf)
14429{
14430 ARGF.binmode = 1;
14431 next_argv();
14432 ARGF_FORWARD(0, 0);
14433 rb_io_ascii8bit_binmode(ARGF.current_file);
14434 return argf;
14435}
14436
14437/*
14438 * call-seq:
14439 * ARGF.binmode? -> true or false
14440 *
14441 * Returns true if ARGF is being read in binary mode; false otherwise.
14442 * To enable binary mode use ARGF.binmode.
14443 *
14444 * For example:
14445 *
14446 * ARGF.binmode? #=> false
14447 * ARGF.binmode
14448 * ARGF.binmode? #=> true
14449 */
14450static VALUE
14451argf_binmode_p(VALUE argf)
14452{
14453 return RBOOL(ARGF.binmode);
14454}
14455
14456/*
14457 * call-seq:
14458 * ARGF.skip -> ARGF
14459 *
14460 * Sets the current file to the next file in ARGV. If there aren't any more
14461 * files it has no effect.
14462 *
14463 * For example:
14464 *
14465 * $ ruby argf.rb foo bar
14466 * ARGF.filename #=> "foo"
14467 * ARGF.skip
14468 * ARGF.filename #=> "bar"
14469 */
14470static VALUE
14471argf_skip(VALUE argf)
14472{
14473 if (ARGF.init_p && ARGF.next_p == 0) {
14474 argf_close(argf);
14475 ARGF.next_p = 1;
14476 }
14477 return argf;
14478}
14479
14480/*
14481 * call-seq:
14482 * ARGF.close -> ARGF
14483 *
14484 * Closes the current file and skips to the next file in ARGV. If there are
14485 * no more files to open, just closes the current file. STDIN will not be
14486 * closed.
14487 *
14488 * For example:
14489 *
14490 * $ ruby argf.rb foo bar
14491 *
14492 * ARGF.filename #=> "foo"
14493 * ARGF.close
14494 * ARGF.filename #=> "bar"
14495 * ARGF.close
14496 */
14497static VALUE
14498argf_close_m(VALUE argf)
14499{
14500 next_argv();
14501 argf_close(argf);
14502 if (ARGF.next_p != -1) {
14503 ARGF.next_p = 1;
14504 }
14505 ARGF.lineno = 0;
14506 return argf;
14507}
14508
14509/*
14510 * call-seq:
14511 * ARGF.closed? -> true or false
14512 *
14513 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14514 * ARGF.close to actually close the current file.
14515 */
14516static VALUE
14517argf_closed(VALUE argf)
14518{
14519 next_argv();
14520 ARGF_FORWARD(0, 0);
14521 return rb_io_closed_p(ARGF.current_file);
14522}
14523
14524/*
14525 * call-seq:
14526 * ARGF.to_s -> String
14527 *
14528 * Returns "ARGF".
14529 */
14530static VALUE
14531argf_to_s(VALUE argf)
14532{
14533 return rb_str_new2("ARGF");
14534}
14535
14536/*
14537 * call-seq:
14538 * ARGF.inplace_mode -> String
14539 *
14540 * Returns the file extension appended to the names of backup copies of
14541 * modified files under in-place edit mode. This value can be set using
14542 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14543 */
14544static VALUE
14545argf_inplace_mode_get(VALUE argf)
14546{
14547 if (!ARGF.inplace) return Qnil;
14548 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14549 return rb_str_dup(ARGF.inplace);
14550}
14551
14552static VALUE
14553opt_i_get(ID id, VALUE *var)
14554{
14555 return argf_inplace_mode_get(*var);
14556}
14557
14558/*
14559 * call-seq:
14560 * ARGF.inplace_mode = ext -> ARGF
14561 *
14562 * Sets the filename extension for in-place editing mode to the given String.
14563 * The backup copy of each file being edited has this value appended to its
14564 * filename.
14565 *
14566 * For example:
14567 *
14568 * $ ruby argf.rb file.txt
14569 *
14570 * ARGF.inplace_mode = '.bak'
14571 * ARGF.each_line do |line|
14572 * print line.sub("foo","bar")
14573 * end
14574 *
14575 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14576 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14577 * "bar".
14578 */
14579static VALUE
14580argf_inplace_mode_set(VALUE argf, VALUE val)
14581{
14582 if (!RTEST(val)) {
14583 ARGF.inplace = Qfalse;
14584 }
14585 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14586 ARGF.inplace = Qnil;
14587 }
14588 else {
14589 ARGF.inplace = rb_str_new_frozen(val);
14590 }
14591 return argf;
14592}
14593
14594static void
14595opt_i_set(VALUE val, ID id, VALUE *var)
14596{
14597 argf_inplace_mode_set(*var, val);
14598}
14599
14600void
14601ruby_set_inplace_mode(const char *suffix)
14602{
14603 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14604}
14605
14606/*
14607 * call-seq:
14608 * ARGF.argv -> ARGV
14609 *
14610 * Returns the +ARGV+ array, which contains the arguments passed to your
14611 * script, one per element.
14612 *
14613 * For example:
14614 *
14615 * $ ruby argf.rb -v glark.txt
14616 *
14617 * ARGF.argv #=> ["-v", "glark.txt"]
14618 *
14619 */
14620static VALUE
14621argf_argv(VALUE argf)
14622{
14623 return ARGF.argv;
14624}
14625
14626static VALUE
14627argf_argv_getter(ID id, VALUE *var)
14628{
14629 return argf_argv(*var);
14630}
14631
14632VALUE
14634{
14635 return ARGF.argv;
14636}
14637
14638/*
14639 * call-seq:
14640 * ARGF.to_write_io -> io
14641 *
14642 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14643 * enabled.
14644 */
14645static VALUE
14646argf_write_io(VALUE argf)
14647{
14648 if (!RTEST(ARGF.current_file)) {
14649 rb_raise(rb_eIOError, "not opened for writing");
14650 }
14651 return GetWriteIO(ARGF.current_file);
14652}
14653
14654/*
14655 * call-seq:
14656 * ARGF.write(*objects) -> integer
14657 *
14658 * Writes each of the given +objects+ if inplace mode.
14659 */
14660static VALUE
14661argf_write(int argc, VALUE *argv, VALUE argf)
14662{
14663 return rb_io_writev(argf_write_io(argf), argc, argv);
14664}
14665
14666void
14667rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14668{
14669 rb_readwrite_syserr_fail(waiting, errno, mesg);
14670}
14671
14672void
14673rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14674{
14675 VALUE arg, c = Qnil;
14676 arg = mesg ? rb_str_new2(mesg) : Qnil;
14677 switch (waiting) {
14678 case RB_IO_WAIT_WRITABLE:
14679 switch (n) {
14680 case EAGAIN:
14681 c = rb_eEAGAINWaitWritable;
14682 break;
14683#if EAGAIN != EWOULDBLOCK
14684 case EWOULDBLOCK:
14685 c = rb_eEWOULDBLOCKWaitWritable;
14686 break;
14687#endif
14688 case EINPROGRESS:
14689 c = rb_eEINPROGRESSWaitWritable;
14690 break;
14691 default:
14693 }
14694 break;
14695 case RB_IO_WAIT_READABLE:
14696 switch (n) {
14697 case EAGAIN:
14698 c = rb_eEAGAINWaitReadable;
14699 break;
14700#if EAGAIN != EWOULDBLOCK
14701 case EWOULDBLOCK:
14702 c = rb_eEWOULDBLOCKWaitReadable;
14703 break;
14704#endif
14705 case EINPROGRESS:
14706 c = rb_eEINPROGRESSWaitReadable;
14707 break;
14708 default:
14710 }
14711 break;
14712 default:
14713 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14714 }
14715 rb_exc_raise(rb_class_new_instance(1, &arg, c));
14716}
14717
14718static VALUE
14719get_LAST_READ_LINE(ID _x, VALUE *_y)
14720{
14721 return rb_lastline_get();
14722}
14723
14724static void
14725set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14726{
14727 rb_lastline_set(val);
14728}
14729
14730/*
14731 * Document-class: IOError
14732 *
14733 * Raised when an IO operation fails.
14734 *
14735 * File.open("/etc/hosts") {|f| f << "example"}
14736 * #=> IOError: not opened for writing
14737 *
14738 * File.open("/etc/hosts") {|f| f.close; f.read }
14739 * #=> IOError: closed stream
14740 *
14741 * Note that some IO failures raise <code>SystemCallError</code>s
14742 * and these are not subclasses of IOError:
14743 *
14744 * File.open("does/not/exist")
14745 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14746 */
14747
14748/*
14749 * Document-class: EOFError
14750 *
14751 * Raised by some IO operations when reaching the end of file. Many IO
14752 * methods exist in two forms,
14753 *
14754 * one that returns +nil+ when the end of file is reached, the other
14755 * raises EOFError.
14756 *
14757 * EOFError is a subclass of IOError.
14758 *
14759 * file = File.open("/etc/hosts")
14760 * file.read
14761 * file.gets #=> nil
14762 * file.readline #=> EOFError: end of file reached
14763 * file.close
14764 */
14765
14766/*
14767 * Document-class: ARGF
14768 *
14769 * == \ARGF and +ARGV+
14770 *
14771 * The \ARGF object works with the array at global variable +ARGV+
14772 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14773 *
14774 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14775 *
14776 * Initially, it contains the command-line arguments and options
14777 * that are passed to the Ruby program;
14778 * the program can modify that array as it likes.
14779 *
14780 * - **ARGF** may be thought of as the <b>argument files</b> object.
14781 *
14782 * It can access file streams and/or the <tt>$stdin</tt> stream,
14783 * based on what it finds in +ARGV+.
14784 * This provides a convenient way for the command line
14785 * to specify streams for a Ruby program to read.
14786 *
14787 * == Reading
14788 *
14789 * \ARGF may read from _source_ streams,
14790 * which at any particular time are determined by the content of +ARGV+.
14791 *
14792 * === Simplest Case
14793 *
14794 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14795 * the source is <tt>$stdin</tt>:
14796 *
14797 * - \File +t.rb+:
14798 *
14799 * p ['ARGV', ARGV]
14800 * p ['ARGF.read', ARGF.read]
14801 *
14802 * - Commands and outputs
14803 * (see below for the content of files +foo.txt+ and +bar.txt+):
14804 *
14805 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14806 * ["ARGV", []]
14807 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14808 *
14809 * $ cat foo.txt bar.txt | ruby t.rb
14810 * ["ARGV", []]
14811 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14812 *
14813 * === About the Examples
14814 *
14815 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14816 *
14817 * $ cat foo.txt
14818 * Foo 0
14819 * Foo 1
14820 * $ cat bar.txt
14821 * Bar 0
14822 * Bar 1
14823 * Bar 2
14824 * Bar 3
14825 *
14826 * === Sources in +ARGV+
14827 *
14828 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14829 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14830 * the sources are found in +ARGV+.
14831 *
14832 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14833 * and is one of:
14834 *
14835 * - The string path to a file that may be opened as a stream.
14836 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14837 *
14838 * Each element that is _not_ one of these
14839 * should be removed from +ARGV+ before \ARGF accesses that source.
14840 *
14841 * In the following example:
14842 *
14843 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14844 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14845 *
14846 * Example:
14847 *
14848 * - \File +t.rb+:
14849 *
14850 * # Print arguments (and options, if any) found on command line.
14851 * p ['ARGV', ARGV]
14852 *
14853 * - Command and output:
14854 *
14855 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14856 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14857 *
14858 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14859 *
14860 * - \File +t.rb+:
14861 *
14862 * p "ARGV: #{ARGV}"
14863 * p "Line: #{ARGF.read}" # Read everything from all specified streams.
14864 *
14865 * - Command and output:
14866 *
14867 * $ ruby t.rb foo.txt bar.txt
14868 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14869 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14870 *
14871 * Because the value at +ARGV+ is an ordinary array,
14872 * you can manipulate it to control which sources \ARGF considers:
14873 *
14874 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14875 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14876 *
14877 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14878 * when all sources have been accessed, the array is empty:
14879 *
14880 * - \File +t.rb+:
14881 *
14882 * until ARGV.empty? && ARGF.eof?
14883 * p "ARGV: #{ARGV}"
14884 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14885 * end
14886 *
14887 * - Command and output:
14888 *
14889 * $ ruby t.rb foo.txt bar.txt
14890 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14891 * "Line: Foo 0\n"
14892 * "ARGV: [\"bar.txt\"]"
14893 * "Line: Foo 1\n"
14894 * "ARGV: [\"bar.txt\"]"
14895 * "Line: Bar 0\n"
14896 * "ARGV: []"
14897 * "Line: Bar 1\n"
14898 * "ARGV: []"
14899 * "Line: Bar 2\n"
14900 * "ARGV: []"
14901 * "Line: Bar 3\n"
14902 *
14903 * ==== Filepaths in +ARGV+
14904 *
14905 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14906 *
14907 * This program prints what it reads from files at the paths specified
14908 * on the command line:
14909 *
14910 * - \File +t.rb+:
14911 *
14912 * p ['ARGV', ARGV]
14913 * # Read and print all content from the specified sources.
14914 * p ['ARGF.read', ARGF.read]
14915 *
14916 * - Command and output:
14917 *
14918 * $ ruby t.rb foo.txt bar.txt
14919 * ["ARGV", [foo.txt, bar.txt]
14920 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14921 *
14922 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14923 *
14924 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14925 *
14926 * - \File +t.rb+:
14927 *
14928 * p ['ARGV', ARGV]
14929 * p ['ARGF.read', ARGF.read]
14930 *
14931 * - Command and output:
14932 *
14933 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14934 * ["ARGV", ["-"]]
14935 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14936 *
14937 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
14938 * (exception:
14939 * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
14940 *
14941 * - Command and output:
14942 *
14943 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
14944 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14945 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14946 *
14947 * ==== Mixtures and Repetitions in +ARGV+
14948 *
14949 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
14950 * and character <tt>'-'</tt>, including repetitions.
14951 *
14952 * ==== Modifications to +ARGV+
14953 *
14954 * The running Ruby program may make any modifications to the +ARGV+ array;
14955 * the current value of +ARGV+ affects \ARGF reading.
14956 *
14957 * ==== Empty +ARGV+
14958 *
14959 * For an empty +ARGV+, an \ARGF read method either returns +nil+
14960 * or raises an exception, depending on the specific method.
14961 *
14962 * === More Read Methods
14963 *
14964 * As seen above, method ARGF#read reads the content of all sources
14965 * into a single string.
14966 * Other \ARGF methods provide other ways to access that content;
14967 * these include:
14968 *
14969 * - Byte access: #each_byte, #getbyte, #readbyte.
14970 * - Character access: #each_char, #getc, #readchar.
14971 * - Codepoint access: #each_codepoint.
14972 * - Line access: #each_line, #gets, #readline, #readlines.
14973 * - Source access: #read, #read_nonblock, #readpartial.
14974 *
14975 * === About \Enumerable
14976 *
14977 * \ARGF includes module Enumerable.
14978 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
14979 *
14980 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
14981 * _not_ from +ARGV+;
14982 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
14983 * not an array of the strings from +ARGV+:
14984 *
14985 * - \File +t.rb+:
14986 *
14987 * p ['ARGV', ARGV]
14988 * p ['ARGF.entries', ARGF.entries]
14989 *
14990 * - Command and output:
14991 *
14992 * $ ruby t.rb foo.txt bar.txt
14993 * ["ARGV", ["foo.txt", "bar.txt"]]
14994 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
14995 *
14996 * == Writing
14997 *
14998 * If <i>inplace mode</i> is in effect,
14999 * \ARGF may write to target streams,
15000 * which at any particular time are determined by the content of ARGV.
15001 *
15002 * Methods about inplace mode:
15003 *
15004 * - #inplace_mode
15005 * - #inplace_mode=
15006 * - #to_write_io
15007 *
15008 * Methods for writing:
15009 *
15010 * - #print
15011 * - #printf
15012 * - #putc
15013 * - #puts
15014 * - #write
15015 *
15016 */
15017
15018/*
15019 * An instance of class \IO (commonly called a _stream_)
15020 * represents an input/output stream in the underlying operating system.
15021 * \Class \IO is the basis for input and output in Ruby.
15022 *
15023 * \Class File is the only class in the Ruby core that is a subclass of \IO.
15024 * Some classes in the Ruby standard library are also subclasses of \IO;
15025 * these include TCPSocket and UDPSocket.
15026 *
15027 * The global constant ARGF (also accessible as <tt>$<</tt>)
15028 * provides an IO-like stream that allows access to all file paths
15029 * found in ARGV (or found in STDIN if ARGV is empty).
15030 * ARGF is not itself a subclass of \IO.
15031 *
15032 * \Class StringIO provides an IO-like stream that handles a String.
15033 * StringIO is not itself a subclass of \IO.
15034 *
15035 * Important objects based on \IO include:
15036 *
15037 * - $stdin.
15038 * - $stdout.
15039 * - $stderr.
15040 * - Instances of class File.
15041 *
15042 * An instance of \IO may be created using:
15043 *
15044 * - IO.new: returns a new \IO object for the given integer file descriptor.
15045 * - IO.open: passes a new \IO object to the given block.
15046 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15047 * of a newly-launched subprocess.
15048 * - Kernel#open: Returns a new \IO object connected to a given source:
15049 * stream, file, or subprocess.
15050 *
15051 * Like a File stream, an \IO stream has:
15052 *
15053 * - A read/write mode, which may be read-only, write-only, or read/write;
15054 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
15055 * - A data mode, which may be text-only or binary;
15056 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15057 * - Internal and external encodings;
15058 * see {Encodings}[rdoc-ref:File@Encodings].
15059 *
15060 * And like other \IO streams, it has:
15061 *
15062 * - A position, which determines where in the stream the next
15063 * read or write is to occur;
15064 * see {Position}[rdoc-ref:IO@Position].
15065 * - A line number, which is a special, line-oriented, "position"
15066 * (different from the position mentioned above);
15067 * see {Line Number}[rdoc-ref:IO@Line+Number].
15068 *
15069 * == Extension <tt>io/console</tt>
15070 *
15071 * Extension <tt>io/console</tt> provides numerous methods
15072 * for interacting with the console;
15073 * requiring it adds numerous methods to class \IO.
15074 *
15075 * == Example Files
15076 *
15077 * Many examples here use these variables:
15078 *
15079 * :include: doc/examples/files.rdoc
15080 *
15081 * == Open Options
15082 *
15083 * A number of \IO methods accept optional keyword arguments
15084 * that determine how a new stream is to be opened:
15085 *
15086 * - +:mode+: Stream mode.
15087 * - +:flags+: Integer file open flags;
15088 * If +mode+ is also given, the two are bitwise-ORed.
15089 * - +:external_encoding+: External encoding for the stream.
15090 * - +:internal_encoding+: Internal encoding for the stream.
15091 * <tt>'-'</tt> is a synonym for the default internal encoding.
15092 * If the value is +nil+ no conversion occurs.
15093 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15094 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15095 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15096 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15097 * when the stream closes; otherwise it remains open.
15098 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15099 * #path method.
15100 *
15101 * Also available are the options offered in String#encode,
15102 * which may control conversion between external and internal encoding.
15103 *
15104 * == Basic \IO
15105 *
15106 * You can perform basic stream \IO with these methods,
15107 * which typically operate on multi-byte strings:
15108 *
15109 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15110 * - IO#write: Writes zero or more strings to the stream;
15111 * each given object that is not already a string is converted via +to_s+.
15112 *
15113 * === Position
15114 *
15115 * An \IO stream has a nonnegative integer _position_,
15116 * which is the byte offset at which the next read or write is to occur.
15117 * A new stream has position zero (and line number zero);
15118 * method +rewind+ resets the position (and line number) to zero.
15119 *
15120 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15121 * Encoding::Converter instances used for that \IO.
15122 *
15123 * The relevant methods:
15124 *
15125 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15126 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15127 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15128 * relative to a given position +whence+
15129 * (indicating the beginning, end, or current position).
15130 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15131 *
15132 * === Open and Closed Streams
15133 *
15134 * A new \IO stream may be open for reading, open for writing, or both.
15135 *
15136 * A stream is automatically closed when claimed by the garbage collector.
15137 *
15138 * Attempted reading or writing on a closed stream raises an exception.
15139 *
15140 * The relevant methods:
15141 *
15142 * - IO#close: Closes the stream for both reading and writing.
15143 * - IO#close_read: Closes the stream for reading.
15144 * - IO#close_write: Closes the stream for writing.
15145 * - IO#closed?: Returns whether the stream is closed.
15146 *
15147 * === End-of-Stream
15148 *
15149 * You can query whether a stream is positioned at its end:
15150 *
15151 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15152 *
15153 * You can reposition to end-of-stream by using method IO#seek:
15154 *
15155 * f = File.new('t.txt')
15156 * f.eof? # => false
15157 * f.seek(0, :END)
15158 * f.eof? # => true
15159 * f.close
15160 *
15161 * Or by reading all stream content (which is slower than using IO#seek):
15162 *
15163 * f.rewind
15164 * f.eof? # => false
15165 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15166 * f.eof? # => true
15167 *
15168 * == Line \IO
15169 *
15170 * \Class \IO supports line-oriented
15171 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15172 *
15173 * === Line Input
15174 *
15175 * \Class \IO supports line-oriented input for
15176 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15177 *
15178 * ==== \File Line Input
15179 *
15180 * You can read lines from a file using these methods:
15181 *
15182 * - IO.foreach: Reads each line and passes it to the given block.
15183 * - IO.readlines: Reads and returns all lines in an array.
15184 *
15185 * For each of these methods:
15186 *
15187 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15188 * - Line parsing depends on the effective <i>line separator</i>;
15189 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15190 * - The length of each returned line depends on the effective <i>line limit</i>;
15191 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15192 *
15193 * ==== Stream Line Input
15194 *
15195 * You can read lines from an \IO stream using these methods:
15196 *
15197 * - IO#each_line: Reads each remaining line, passing it to the given block.
15198 * - IO#gets: Returns the next line.
15199 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15200 * - IO#readlines: Returns all remaining lines in an array.
15201 *
15202 * For each of these methods:
15203 *
15204 * - Reading may begin mid-line,
15205 * depending on the stream's _position_;
15206 * see {Position}[rdoc-ref:IO@Position].
15207 * - Line parsing depends on the effective <i>line separator</i>;
15208 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15209 * - The length of each returned line depends on the effective <i>line limit</i>;
15210 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15211 *
15212 * ===== Line Separator
15213 *
15214 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15215 * the string that determines what is considered a line;
15216 * it is sometimes called the <i>input record separator</i>.
15217 *
15218 * The default line separator is taken from global variable <tt>$/</tt>,
15219 * whose initial value is <tt>"\n"</tt>.
15220 *
15221 * Generally, the line to be read next is all data
15222 * from the current {position}[rdoc-ref:IO@Position]
15223 * to the next line separator
15224 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15225 *
15226 * f = File.new('t.txt')
15227 * # Method gets with no sep argument returns the next line, according to $/.
15228 * f.gets # => "First line\n"
15229 * f.gets # => "Second line\n"
15230 * f.gets # => "\n"
15231 * f.gets # => "Fourth line\n"
15232 * f.gets # => "Fifth line\n"
15233 * f.close
15234 *
15235 * You can use a different line separator by passing argument +sep+:
15236 *
15237 * f = File.new('t.txt')
15238 * f.gets('l') # => "First l"
15239 * f.gets('li') # => "ine\nSecond li"
15240 * f.gets('lin') # => "ne\n\nFourth lin"
15241 * f.gets # => "e\n"
15242 * f.close
15243 *
15244 * Or by setting global variable <tt>$/</tt>:
15245 *
15246 * f = File.new('t.txt')
15247 * $/ = 'l'
15248 * f.gets # => "First l"
15249 * f.gets # => "ine\nSecond l"
15250 * f.gets # => "ine\n\nFourth l"
15251 * f.close
15252 *
15253 * ===== Special Line Separator Values
15254 *
15255 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15256 * accepts two special values for parameter +sep+:
15257 *
15258 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15259 *
15260 * f = File.new('t.txt')
15261 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15262 * f.close
15263 *
15264 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15265 * (paragraphs being separated by two consecutive line separators):
15266 *
15267 * f = File.new('t.txt')
15268 * f.gets('') # => "First line\nSecond line\n\n"
15269 * f.gets('') # => "Fourth line\nFifth line\n"
15270 * f.close
15271 *
15272 * ===== Line Limit
15273 *
15274 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15275 * uses an integer <i>line limit</i>,
15276 * which restricts the number of bytes that may be returned.
15277 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15278 * than the limit).
15279 *
15280 * The default limit value is <tt>-1</tt>;
15281 * any negative limit value means that there is no limit.
15282 *
15283 * If there is no limit, the line is determined only by +sep+.
15284 *
15285 * # Text with 1-byte characters.
15286 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15287 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15288 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15289 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15290 * # No more than one line.
15291 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15292 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15293 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15294 *
15295 * # Text with 2-byte characters, which will not be split.
15296 * File.open('t.rus') {|f| f.gets(1).size } # => 1
15297 * File.open('t.rus') {|f| f.gets(2).size } # => 1
15298 * File.open('t.rus') {|f| f.gets(3).size } # => 2
15299 * File.open('t.rus') {|f| f.gets(4).size } # => 2
15300 *
15301 * ===== Line Separator and Line Limit
15302 *
15303 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15304 *
15305 * - Returns the next line as determined by line separator +sep+.
15306 * - But returns no more bytes than are allowed by the limit +limit+.
15307 *
15308 * Example:
15309 *
15310 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15311 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15312 *
15313 * ===== Line Number
15314 *
15315 * A readable \IO stream has a non-negative integer <i>line number</i>:
15316 *
15317 * - IO#lineno: Returns the line number.
15318 * - IO#lineno=: Resets and returns the line number.
15319 *
15320 * Unless modified by a call to method IO#lineno=,
15321 * the line number is the number of lines read
15322 * by certain line-oriented methods,
15323 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15324 *
15325 * - IO.foreach: Increments the line number on each call to the block.
15326 * - IO#each_line: Increments the line number on each call to the block.
15327 * - IO#gets: Increments the line number.
15328 * - IO#readline: Increments the line number.
15329 * - IO#readlines: Increments the line number for each line read.
15330 *
15331 * A new stream is initially has line number zero (and position zero);
15332 * method +rewind+ resets the line number (and position) to zero:
15333 *
15334 * f = File.new('t.txt')
15335 * f.lineno # => 0
15336 * f.gets # => "First line\n"
15337 * f.lineno # => 1
15338 * f.rewind
15339 * f.lineno # => 0
15340 * f.close
15341 *
15342 * Reading lines from a stream usually changes its line number:
15343 *
15344 * f = File.new('t.txt', 'r')
15345 * f.lineno # => 0
15346 * f.readline # => "This is line one.\n"
15347 * f.lineno # => 1
15348 * f.readline # => "This is the second line.\n"
15349 * f.lineno # => 2
15350 * f.readline # => "Here's the third line.\n"
15351 * f.lineno # => 3
15352 * f.eof? # => true
15353 * f.close
15354 *
15355 * Iterating over lines in a stream usually changes its line number:
15356 *
15357 * File.open('t.txt') do |f|
15358 * f.each_line do |line|
15359 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15360 * end
15361 * end
15362 *
15363 * Output:
15364 *
15365 * "position=11 eof?=false lineno=1"
15366 * "position=23 eof?=false lineno=2"
15367 * "position=24 eof?=false lineno=3"
15368 * "position=36 eof?=false lineno=4"
15369 * "position=47 eof?=true lineno=5"
15370 *
15371 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15372 * the line number does not affect where the next read or write will occur:
15373 *
15374 * f = File.new('t.txt')
15375 * f.lineno = 1000
15376 * f.lineno # => 1000
15377 * f.gets # => "First line\n"
15378 * f.lineno # => 1001
15379 * f.close
15380 *
15381 * Associated with the line number is the global variable <tt>$.</tt>:
15382 *
15383 * - When a stream is opened, <tt>$.</tt> is not set;
15384 * its value is left over from previous activity in the process:
15385 *
15386 * $. = 41
15387 * f = File.new('t.txt')
15388 * $. = 41
15389 * # => 41
15390 * f.close
15391 *
15392 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15393 *
15394 * f0 = File.new('t.txt')
15395 * f1 = File.new('t.dat')
15396 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15397 * $. # => 5
15398 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15399 * $. # => 1
15400 * f0.close
15401 * f1.close
15402 *
15403 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15404 *
15405 * f = File.new('t.txt')
15406 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15407 * $. # => 5
15408 * f.rewind
15409 * f.seek(0, :SET)
15410 * $. # => 5
15411 * f.close
15412 *
15413 * === Line Output
15414 *
15415 * You can write to an \IO stream line-by-line using this method:
15416 *
15417 * - IO#puts: Writes objects to the stream.
15418 *
15419 * == Character \IO
15420 *
15421 * You can process an \IO stream character-by-character using these methods:
15422 *
15423 * - IO#getc: Reads and returns the next character from the stream.
15424 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15425 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15426 * - IO#putc: Writes a character to the stream.
15427 * - IO#each_char: Reads each remaining character in the stream,
15428 * passing the character to the given block.
15429 *
15430 * == Byte \IO
15431 *
15432 * You can process an \IO stream byte-by-byte using these methods:
15433 *
15434 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15435 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15436 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15437 * - IO#each_byte: Reads each remaining byte in the stream,
15438 * passing the byte to the given block.
15439 *
15440 * == Codepoint \IO
15441 *
15442 * You can process an \IO stream codepoint-by-codepoint:
15443 *
15444 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15445 *
15446 * == What's Here
15447 *
15448 * First, what's elsewhere. \Class \IO:
15449 *
15450 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15451 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15452 * which provides dozens of additional methods.
15453 *
15454 * Here, class \IO provides methods that are useful for:
15455 *
15456 * - {Creating}[rdoc-ref:IO@Creating]
15457 * - {Reading}[rdoc-ref:IO@Reading]
15458 * - {Writing}[rdoc-ref:IO@Writing]
15459 * - {Positioning}[rdoc-ref:IO@Positioning]
15460 * - {Iterating}[rdoc-ref:IO@Iterating]
15461 * - {Settings}[rdoc-ref:IO@Settings]
15462 * - {Querying}[rdoc-ref:IO@Querying]
15463 * - {Buffering}[rdoc-ref:IO@Buffering]
15464 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15465 * - {Other}[rdoc-ref:IO@Other]
15466 *
15467 * === Creating
15468 *
15469 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15470 * integer file descriptor.
15471 * - ::open: Creates a new \IO object.
15472 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15473 * - ::popen: Creates an \IO object to interact with a subprocess.
15474 * - ::select: Selects which given \IO instances are ready for reading,
15475 * writing, or have pending exceptions.
15476 *
15477 * === Reading
15478 *
15479 * - ::binread: Returns a binary string with all or a subset of bytes
15480 * from the given file.
15481 * - ::read: Returns a string with all or a subset of bytes from the given file.
15482 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15483 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15484 * - #getc: Returns the next character read from +self+ as a string.
15485 * - #gets: Returns the line read from +self+.
15486 * - #pread: Returns all or the next _n_ bytes read from +self+,
15487 * not updating the receiver's offset.
15488 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15489 * for a given _n_.
15490 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15491 * in non-block mode.
15492 * - #readbyte: Returns the next byte read from +self+;
15493 * same as #getbyte, but raises an exception on end-of-stream.
15494 * - #readchar: Returns the next character read from +self+;
15495 * same as #getc, but raises an exception on end-of-stream.
15496 * - #readline: Returns the next line read from +self+;
15497 * same as #getline, but raises an exception of end-of-stream.
15498 * - #readlines: Returns an array of all lines read read from +self+.
15499 * - #readpartial: Returns up to the given number of bytes from +self+.
15500 *
15501 * === Writing
15502 *
15503 * - ::binwrite: Writes the given string to the file at the given filepath,
15504 * in binary mode.
15505 * - ::write: Writes the given string to +self+.
15506 * - #<<: Appends the given string to +self+.
15507 * - #print: Prints last read line or given objects to +self+.
15508 * - #printf: Writes to +self+ based on the given format string and objects.
15509 * - #putc: Writes a character to +self+.
15510 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15511 * - #pwrite: Writes the given string at the given offset,
15512 * not updating the receiver's offset.
15513 * - #write: Writes one or more given strings to +self+.
15514 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15515 *
15516 * === Positioning
15517 *
15518 * - #lineno: Returns the current line number in +self+.
15519 * - #lineno=: Sets the line number is +self+.
15520 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15521 * - #pos=: Sets the byte offset in +self+.
15522 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15523 * - #rewind: Positions +self+ to the beginning of input.
15524 * - #seek: Sets the offset for +self+ relative to given position.
15525 *
15526 * === Iterating
15527 *
15528 * - ::foreach: Yields each line of given file to the block.
15529 * - #each (aliased as #each_line): Calls the given block
15530 * with each successive line in +self+.
15531 * - #each_byte: Calls the given block with each successive byte in +self+
15532 * as an integer.
15533 * - #each_char: Calls the given block with each successive character in +self+
15534 * as a string.
15535 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15536 * as an integer.
15537 *
15538 * === Settings
15539 *
15540 * - #autoclose=: Sets whether +self+ auto-closes.
15541 * - #binmode: Sets +self+ to binary mode.
15542 * - #close: Closes +self+.
15543 * - #close_on_exec=: Sets the close-on-exec flag.
15544 * - #close_read: Closes +self+ for reading.
15545 * - #close_write: Closes +self+ for writing.
15546 * - #set_encoding: Sets the encoding for +self+.
15547 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15548 * Unicode byte-order-mark.
15549 * - #sync=: Sets the sync-mode to the given value.
15550 *
15551 * === Querying
15552 *
15553 * - #autoclose?: Returns whether +self+ auto-closes.
15554 * - #binmode?: Returns whether +self+ is in binary mode.
15555 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15556 * - #closed?: Returns whether +self+ is closed.
15557 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15558 * - #external_encoding: Returns the external encoding object for +self+.
15559 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15560 * - #internal_encoding: Returns the internal encoding object for +self+.
15561 * - #pid: Returns the process ID of a child process associated with +self+,
15562 * if +self+ was created by ::popen.
15563 * - #stat: Returns the File::Stat object containing status information for +self+.
15564 * - #sync: Returns whether +self+ is in sync-mode.
15565 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15566 *
15567 * === Buffering
15568 *
15569 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15570 * - #flush: Flushes any buffered data within +self+ to the underlying
15571 * operating system.
15572 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15573 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15574 * - #ungetc: Prepends buffer for +self+ with given string.
15575 *
15576 * === Low-Level Access
15577 *
15578 * - ::sysopen: Opens the file given by its path,
15579 * returning the integer file descriptor.
15580 * - #advise: Announces the intention to access data from +self+ in a specific way.
15581 * - #fcntl: Passes a low-level command to the file specified
15582 * by the given file descriptor.
15583 * - #ioctl: Passes a low-level command to the device specified
15584 * by the given file descriptor.
15585 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15586 * - #sysseek: Sets the offset for +self+.
15587 * - #syswrite: Writes the given string to +self+ using a low-level write.
15588 *
15589 * === Other
15590 *
15591 * - ::copy_stream: Copies data from a source to a destination,
15592 * each of which is a filepath or an \IO-like object.
15593 * - ::try_convert: Returns a new \IO object resulting from converting
15594 * the given object.
15595 * - #inspect: Returns the string representation of +self+.
15596 *
15597 */
15598
15599void
15600Init_IO(void)
15601{
15602 VALUE rb_cARGF;
15603#ifdef __CYGWIN__
15604#include <sys/cygwin.h>
15605 static struct __cygwin_perfile pf[] =
15606 {
15607 {"", O_RDONLY | O_BINARY},
15608 {"", O_WRONLY | O_BINARY},
15609 {"", O_RDWR | O_BINARY},
15610 {"", O_APPEND | O_BINARY},
15611 {NULL, 0}
15612 };
15613 cygwin_internal(CW_PERFILE, pf);
15614#endif
15615
15618
15619 id_write = rb_intern_const("write");
15620 id_read = rb_intern_const("read");
15621 id_getc = rb_intern_const("getc");
15622 id_flush = rb_intern_const("flush");
15623 id_readpartial = rb_intern_const("readpartial");
15624 id_set_encoding = rb_intern_const("set_encoding");
15625 id_fileno = rb_intern_const("fileno");
15626
15627 rb_define_global_function("syscall", rb_f_syscall, -1);
15628
15629 rb_define_global_function("open", rb_f_open, -1);
15630 rb_define_global_function("printf", rb_f_printf, -1);
15631 rb_define_global_function("print", rb_f_print, -1);
15632 rb_define_global_function("putc", rb_f_putc, 1);
15633 rb_define_global_function("puts", rb_f_puts, -1);
15634 rb_define_global_function("gets", rb_f_gets, -1);
15635 rb_define_global_function("readline", rb_f_readline, -1);
15636 rb_define_global_function("select", rb_f_select, -1);
15637
15638 rb_define_global_function("readlines", rb_f_readlines, -1);
15639
15640 rb_define_global_function("`", rb_f_backquote, 1);
15641
15642 rb_define_global_function("p", rb_f_p, -1);
15643 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15644
15645 rb_cIO = rb_define_class("IO", rb_cObject);
15647
15648 /* Can be raised by IO operations when IO#timeout= is set. */
15650
15651 /* Readable event mask for IO#wait. */
15653 /* Writable event mask for IO#wait. */
15655 /* Priority event mask for IO#wait. */
15657
15658 /* exception to wait for reading. see IO.select. */
15660 /* exception to wait for writing. see IO.select. */
15662 /* exception to wait for reading by EAGAIN. see IO.select. */
15663 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15664 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15665 /* exception to wait for writing by EAGAIN. see IO.select. */
15666 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15667 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15668#if EAGAIN == EWOULDBLOCK
15669 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15670 /* same as IO::EAGAINWaitReadable */
15671 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15672 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15673 /* same as IO::EAGAINWaitWritable */
15674 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15675#else
15676 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15677 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15678 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15679 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15680 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15681 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15682#endif
15683 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15684 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15685 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15686 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15687 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15688 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15689
15690#if 0
15691 /* This is necessary only for forcing rdoc handle File::open */
15692 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15693#endif
15694
15695 rb_define_alloc_func(rb_cIO, io_alloc);
15696 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15697 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15698 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15699 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15700 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15701 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15702 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15703 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15704 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15705 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15706 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15707 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15708 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15709 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15710 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15711
15712 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15713
15714 rb_output_fs = Qnil;
15715 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15716
15717 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15718 rb_vm_register_global_object(rb_default_rs);
15719 rb_rs = rb_default_rs;
15721 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter);
15722 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_str_setter);
15723 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15724
15725 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15726 rb_gvar_ractor_local("$_");
15727
15728 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15729 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15730
15731 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15732 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15733 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15734 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15735
15736 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15737 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15738 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15739 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15740 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15741
15742 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15743 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15744
15745 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15746 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15747
15748 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15749 rb_define_alias(rb_cIO, "to_i", "fileno");
15750 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15751
15752 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15753 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15754
15755 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15756 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15757 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15758 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15759
15760 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15761 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15762
15763 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15764
15765 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15766 rb_define_method(rb_cIO, "read", io_read, -1);
15767 rb_define_method(rb_cIO, "write", io_write_m, -1);
15768 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15769 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15770 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15771 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15772 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15773 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15774 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15776 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15777 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15778 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15779 /* Set I/O position from the beginning */
15780 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15781 /* Set I/O position from the current position */
15782 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15783 /* Set I/O position from the end */
15784 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15785#ifdef SEEK_DATA
15786 /* Set I/O position to the next location containing data */
15787 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15788#endif
15789#ifdef SEEK_HOLE
15790 /* Set I/O position to the next hole */
15791 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15792#endif
15793 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15794 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15795 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15796 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15797 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15798
15799 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15800 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15801
15802 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15803 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15804 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15805 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15806
15807 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15808 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15809 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15810 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15811 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15812 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15813
15814 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15815 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15816 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15817
15818 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15819 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15820
15821 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15822
15823 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15824 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15825 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15826 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15827
15828 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15829 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15830
15831 rb_define_method(rb_cIO, "wait", io_wait, -1);
15832
15833 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15834 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15835 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15836
15837 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15838 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15839 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15840 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15841
15842 rb_gvar_ractor_local("$stdin");
15843 rb_gvar_ractor_local("$stdout");
15844 rb_gvar_ractor_local("$>");
15845 rb_gvar_ractor_local("$stderr");
15846
15848 rb_stdin = rb_io_prep_stdin();
15850 rb_stdout = rb_io_prep_stdout();
15852 rb_stderr = rb_io_prep_stderr();
15853
15854 orig_stdout = rb_stdout;
15855 orig_stderr = rb_stderr;
15856
15857 /* Holds the original stdin */
15859 /* Holds the original stdout */
15861 /* Holds the original stderr */
15863
15864#if 0
15865 /* Hack to get rdoc to regard ARGF as a class: */
15866 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15867#endif
15868
15869 rb_cARGF = rb_class_new(rb_cObject);
15870 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15871 rb_define_alloc_func(rb_cARGF, argf_alloc);
15872
15874
15875 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15876 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15877 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15878 rb_define_alias(rb_cARGF, "inspect", "to_s");
15879 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15880
15881 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15882 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15883 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15884 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15885 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15886 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15887 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15888 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15889 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15890
15891 rb_define_method(rb_cARGF, "read", argf_read, -1);
15892 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15893 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15894 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15895 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15896 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15897 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15898 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15899 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15900 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15901 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15902 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15903 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15904 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15905 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15906 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15907 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15908 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15909 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15910 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15911
15912 rb_define_method(rb_cARGF, "write", argf_write, -1);
15913 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15914 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15915 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15916 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15917
15918 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15919 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15920 rb_define_method(rb_cARGF, "file", argf_file, 0);
15921 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15922 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15923 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15924
15925 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15926 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15927
15928 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15929 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15930
15931 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15932 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15933 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15934
15935 argf = rb_class_new_instance(0, 0, rb_cARGF);
15936
15938 /*
15939 * ARGF is a stream designed for use in scripts that process files given
15940 * as command-line arguments or passed in via STDIN.
15941 *
15942 * See ARGF (the class) for more details.
15943 */
15945
15946 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15947 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15948 ARGF.filename = rb_str_new2("-");
15949
15950 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15951 rb_gvar_ractor_local("$-i");
15952
15953 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15954
15955#if defined (_WIN32) || defined(__CYGWIN__)
15956 atexit(pipe_atexit);
15957#endif
15958
15959 Init_File();
15960
15961 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
15962
15963 sym_mode = ID2SYM(rb_intern_const("mode"));
15964 sym_perm = ID2SYM(rb_intern_const("perm"));
15965 sym_flags = ID2SYM(rb_intern_const("flags"));
15966 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
15967 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
15968 sym_encoding = ID2SYM(rb_id_encoding());
15969 sym_open_args = ID2SYM(rb_intern_const("open_args"));
15970 sym_textmode = ID2SYM(rb_intern_const("textmode"));
15971 sym_binmode = ID2SYM(rb_intern_const("binmode"));
15972 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
15973 sym_normal = ID2SYM(rb_intern_const("normal"));
15974 sym_sequential = ID2SYM(rb_intern_const("sequential"));
15975 sym_random = ID2SYM(rb_intern_const("random"));
15976 sym_willneed = ID2SYM(rb_intern_const("willneed"));
15977 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
15978 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
15979 sym_SET = ID2SYM(rb_intern_const("SET"));
15980 sym_CUR = ID2SYM(rb_intern_const("CUR"));
15981 sym_END = ID2SYM(rb_intern_const("END"));
15982#ifdef SEEK_DATA
15983 sym_DATA = ID2SYM(rb_intern_const("DATA"));
15984#endif
15985#ifdef SEEK_HOLE
15986 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
15987#endif
15988 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
15989 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
15990}
15991
15992#include "io.rbinc"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:138
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1187
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:980
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:359
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1012
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1119
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2350
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:2653
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:2640
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:937
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2429
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:400
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:135
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
#define ECONV_NEWLINE_DECORATOR_WRITE_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_WRITE_MASK.
Definition transcode.h:531
#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 ECONV_NEWLINE_DECORATOR_READ_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_READ_MASK.
Definition transcode.h:530
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1677
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
void rb_notimplement(void)
Definition error.c:3808
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:476
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:508
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1440
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3877
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:14673
VALUE rb_eIOError
IOError exception.
Definition io.c:189
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1427
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3967
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:3883
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:475
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
VALUE rb_eEOFError
EOFError exception.
Definition io.c:188
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14667
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2091
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1450
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:65
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3198
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:669
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2097
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2138
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:2126
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
VALUE rb_stdin
STDIN constant.
Definition io.c:201
VALUE rb_stderr
STDERR constant.
Definition io.c:201
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:247
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:576
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:680
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:191
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:192
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1260
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:3179
VALUE rb_cFile
File class.
Definition file.c:175
VALUE rb_stdout
STDOUT constant.
Definition io.c:201
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3192
rb_encoding * rb_ascii8bit_encoding(void)
Queries the encoding that represents ASCII-8BIT a.k.a.
Definition encoding.c:1463
rb_encoding * rb_default_internal_encoding(void)
Queries the "default internal" encoding.
Definition encoding.c:1676
int rb_utf8_encindex(void)
Identical to rb_utf8_encoding(), except it returns the encoding's index instead of the encoding itsel...
Definition encoding.c:1481
VALUE rb_enc_default_external(void)
Identical to rb_default_external_encoding(), except it returns the Ruby-level counterpart instance of...
Definition encoding.c:1603
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
rb_encoding * rb_default_external_encoding(void)
Queries the "default external" encoding.
Definition encoding.c:1589
rb_encoding * rb_locale_encoding(void)
Queries the encoding that represents the current locale.
Definition encoding.c:1523
rb_encoding * rb_usascii_encoding(void)
Queries the encoding that represents US-ASCII.
Definition encoding.c:1487
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1290
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3803
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c:789
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
Definition transcode.c:2600
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
Definition transcode.c:2097
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
Definition transcode.c:1475
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
Definition transcode.h:69
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
Definition transcode.h:41
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1770
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1814
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
Definition transcode.c:1931
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
Definition transcode.c:2651
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
Definition transcode.c:1996
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
Definition transcode.c:2914
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4272
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4278
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1731
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1781
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1099
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
Definition vm_eval.c:1066
void rb_gc(void)
Triggers a GC process.
Definition gc.c:3720
VALUE rb_ary_new(void)
Allocates a new, empty array.
Definition array.c:741
#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
ID rb_frame_this_func(void)
Queries the name of the Ruby level method that is calling this function.
Definition eval.c:1115
VALUE rb_hash_new(void)
Creates a new, empty hash object.
Definition hash.c:1477
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8612
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4303
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:8738
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2350
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9167
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:5172
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5078
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:9343
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:2695
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:9147
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:6384
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6338
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5236
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7385
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10412
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:461
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
Definition io.c:7268
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:7275
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5758
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:1853
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:1847
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:2942
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1271
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:3681
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1681
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1532
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:959
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1466
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1921
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3449
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1146
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3273
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:3623
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2855
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3153
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3256
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:2653
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1648
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1514
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1451
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:1603
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
Definition thread.c:5332
void rb_thread_fd_close(int fd)
Notifies a closing of a file descriptor to other threads.
Definition thread.c:2707
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:1434
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:2984
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1597
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1457
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2935
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:433
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:1939
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:492
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:2973
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
Definition vm_eval.c:668
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:284
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
Definition variable.c:3811
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
Definition variable.c:824
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
Definition variable.c:3797
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:270
int 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:6470
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:6603
#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:368
int rb_io_mode(VALUE io)
Get the mode of the IO.
Definition io.c:2918
rb_io_event
Type of events that an IO can wait.
Definition io.h:81
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:82
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition io.h:84
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition io.h:83
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:276
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
Definition io.h:360
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:402
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:300
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:323
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition io.c:1024
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
Definition io.c:6752
int rb_io_oflags_fmode(int oflags)
Converts an oflags (that rb_io_modestr_oflags() returns) to a fmode (that rb_io_mode_flags() returns)...
Definition io.c:6527
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:1591
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:7085
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2898
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:273
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:9389
#define FMODE_APPEND
The IO is opened for appending.
Definition io.h:315
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition io.h:425
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition io.h:308
#define FMODE_BINMODE
The IO is in "binary mode".
Definition io.h:287
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:1650
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:396
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:1609
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:190
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:294
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:2972
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:331
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition io.h:351
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
Definition io.c:5687
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:5866
struct rb_io_internal_buffer rb_io_buffer_t
Just another name of rb_io_buffer_t.
Definition io.h:110
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:2015
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:337
int rb_io_read_pending(rb_io_t *fptr)
Queries if the passed IO has any pending reads.
Definition io.c:1060
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:3424
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, int *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:6877
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1548
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:9260
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:1665
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:796
void rb_eof_error(void)
Utility function to raise rb_eEOFError.
Definition io.c:775
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1514
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7372
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1453
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_stderr(void)
Queries the standard error of the current Ractor that is calling this function.
Definition ractor.c:2763
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:2739
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:2799
VALUE rb_ractor_stdout(void)
Queries the standard output of the current Ractor that is calling this function.
Definition ractor.c:2751
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:2787
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:2775
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:1904
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition sprintf.c:209
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
Definition vm_eval.c:1388
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1354
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition off_t.h:55
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h: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:79
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:197
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:497
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14633
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9046
#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:229
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:662
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:272
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:474
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:638
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:468
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
Definition scheduler.h:70
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:504
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:674
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:234
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:650
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:480
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:4335
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:226
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
Decomposed encoding flags (e.g.
Definition io.h:119
int ecflags
Flags.
Definition io.h:129
VALUE ecopts
Flags as Ruby hash.
Definition io.h:137
rb_encoding * enc2
External encoding.
Definition io.h:123
rb_encoding * enc
Internal encoding.
Definition io.h:121
IO buffers.
Definition io.h:94
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:97
int off
Offset inside of ptr.
Definition io.h:100
int len
Length of the buffer.
Definition io.h:103
int capa
Designed capacity of the buffer.
Definition io.h:106
Ruby's IO, metadata and buffers.
Definition io.h:143
int mode
mode flags: FMODE_XXXs
Definition io.h:158
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:178
void(* finalize)(struct rb_io *, int)
finalize proc
Definition io.h:174
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:200
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:211
struct rb_io_encoding encs
Decomposed encoding flags.
Definition io.h:196
VALUE self
The IO's Ruby level counterpart.
Definition io.h:146
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:248
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:254
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:150
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:238
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:193
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:224
int fd
file descriptor.
Definition io.h:154
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:185
int lineno
number of lines read
Definition io.h:166
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:220
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:207
rb_pid_t pid
child's pid (for pipes)
Definition io.h:162
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:231
VALUE pathv
pathname for file
Definition io.h:170
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_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