Ruby 4.0.0dev (2025-12-13 revision 71dd272506a31f28d216f26b0568028ed600f6ed)
io.c (71dd272506a31f28d216f26b0568028ed600f6ed)
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17#include "ruby/io/buffer.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <stddef.h>
22
23/* non-Linux poll may not work on all FDs */
24#if defined(HAVE_POLL)
25# if defined(__linux__)
26# define USE_POLL 1
27# endif
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29# define USE_POLL 1
30# endif
31#endif
32
33#ifndef USE_POLL
34# define USE_POLL 0
35#endif
36
37#undef free
38#define free(x) xfree(x)
39
40#if defined(DOSISH) || defined(__CYGWIN__)
41#include <io.h>
42#endif
43
44#include <sys/types.h>
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
49#endif
50
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
53#endif
54
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
56# define USE_SETVBUF
57#endif
58
59#ifdef __QNXNTO__
60#include <unix.h>
61#endif
62
63#include <sys/types.h>
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
65#include <sys/ioctl.h>
66#endif
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
68#include <fcntl.h>
69#elif defined(HAVE_SYS_FCNTL_H)
70#include <sys/fcntl.h>
71#endif
72
73#ifdef HAVE_SYS_TIME_H
74# include <sys/time.h>
75#endif
76
77#include <sys/stat.h>
78
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
81#endif
82
83#if !defined NOFILE
84# define NOFILE 64
85#endif
86
87#ifdef HAVE_UNISTD_H
88#include <unistd.h>
89#endif
90
91#ifdef HAVE_SYSCALL_H
92#include <syscall.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
95#endif
96
97#ifdef HAVE_SYS_UIO_H
98#include <sys/uio.h>
99#endif
100
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h> /* for WNOHANG on BSD */
103#endif
104
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
107
108# ifndef COPYFILE_STATE_COPIED
109/*
110 * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
111 * COPYFILE_STATE_COPIED. Since the only use of the former here
112 * requires the latter, we disable the former when the latter is undefined.
113 */
114# undef HAVE_FCOPYFILE
115# endif
116
117#endif
118
120#include "ccan/list/list.h"
121#include "dln.h"
122#include "encindex.h"
123#include "id.h"
124#include "internal.h"
125#include "internal/class.h"
126#include "internal/encoding.h"
127#include "internal/error.h"
128#include "internal/inits.h"
129#include "internal/io.h"
130#include "internal/numeric.h"
131#include "internal/object.h"
132#include "internal/process.h"
133#include "internal/thread.h"
134#include "internal/transcode.h"
135#include "internal/variable.h"
136#include "ruby/io.h"
137#include "ruby/io/buffer.h"
138#include "ruby/missing.h"
139#include "ruby/thread.h"
140#include "ruby/util.h"
141#include "ruby_atomic.h"
142#include "ruby/ractor.h"
143
144#if !USE_POLL
145# include "vm_core.h"
146#endif
147
148#include "builtin.h"
149
150#ifndef O_ACCMODE
151#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
152#endif
153
154#ifndef PIPE_BUF
155# ifdef _POSIX_PIPE_BUF
156# define PIPE_BUF _POSIX_PIPE_BUF
157# else
158# define PIPE_BUF 512 /* is this ok? */
159# endif
160#endif
161
162#ifndef EWOULDBLOCK
163# define EWOULDBLOCK EAGAIN
164#endif
165
166#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
167/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
168off_t __syscall(quad_t number, ...);
169#endif
170
171#define IO_RBUF_CAPA_MIN 8192
172#define IO_CBUF_CAPA_MIN (128*1024)
173#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174#define IO_WBUF_CAPA_MIN 8192
175
176#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
177
178/* define system APIs */
179#ifdef _WIN32
180#undef open
181#define open rb_w32_uopen
182#undef rename
183#define rename(f, t) rb_w32_urename((f), (t))
184#include "win32/file.h"
185#endif
186
193
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196static VALUE rb_eEWOULDBLOCKWaitReadable;
197static VALUE rb_eEWOULDBLOCKWaitWritable;
198static VALUE rb_eEINPROGRESSWaitWritable;
199static VALUE rb_eEINPROGRESSWaitReadable;
200
202static VALUE orig_stdout, orig_stderr;
203
205VALUE rb_rs;
208
209static VALUE argf;
210
211static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
212static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
213static VALUE sym_textmode, sym_binmode, sym_autoclose;
214static VALUE sym_SET, sym_CUR, sym_END;
215static VALUE sym_wait_readable, sym_wait_writable;
216#ifdef SEEK_DATA
217static VALUE sym_DATA;
218#endif
219#ifdef SEEK_HOLE
220static VALUE sym_HOLE;
221#endif
222
223static VALUE prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path);
224
225VALUE
226rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
227{
228 return rb_thread_io_blocking_call(io, function, argument, events);
229}
230
231VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
232{
233 return rb_io_blocking_region_wait(io, function, argument, 0);
234}
235
236struct argf {
237 VALUE filename, current_file;
238 long last_lineno; /* $. */
239 long lineno;
240 VALUE argv;
241 VALUE inplace;
242 struct rb_io_encoding encs;
243 int8_t init_p, next_p, binmode;
244};
245
246static rb_atomic_t max_file_descriptor = NOFILE;
247void
249{
250 rb_atomic_t afd = (rb_atomic_t)fd;
251 rb_atomic_t max_fd = max_file_descriptor;
252 int err;
253
254 if (fd < 0 || afd <= max_fd)
255 return;
256
257#if defined(HAVE_FCNTL) && defined(F_GETFL)
258 err = fcntl(fd, F_GETFL) == -1;
259#else
260 {
261 struct stat buf;
262 err = fstat(fd, &buf) != 0;
263 }
264#endif
265 if (err && errno == EBADF) {
266 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
267 }
268
269 while (max_fd < afd) {
270 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
271 }
272}
273
274void
275rb_maygvl_fd_fix_cloexec(int fd)
276{
277 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
278#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
279 int flags, flags2, ret;
280 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
281 if (flags == -1) {
282 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
283 }
284 if (fd <= 2)
285 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
286 else
287 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
288 if (flags != flags2) {
289 ret = fcntl(fd, F_SETFD, flags2);
290 if (ret != 0) {
291 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
292 }
293 }
294#endif
295}
296
297void
299{
300 rb_maygvl_fd_fix_cloexec(fd);
302}
303
304/* this is only called once */
305static int
306rb_fix_detect_o_cloexec(int fd)
307{
308#if defined(O_CLOEXEC) && defined(F_GETFD)
309 int flags = fcntl(fd, F_GETFD);
310
311 if (flags == -1)
312 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
313
314 if (flags & FD_CLOEXEC)
315 return 1;
316#endif /* fall through if O_CLOEXEC does not work: */
317 rb_maygvl_fd_fix_cloexec(fd);
318 return 0;
319}
320
321static inline bool
322io_again_p(int e)
323{
324 return (e == EWOULDBLOCK) || (e == EAGAIN);
325}
326
327int
328rb_cloexec_open(const char *pathname, int flags, mode_t mode)
329{
330 int ret;
331 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
332
333 static const int retry_interval = 0;
334 static const int retry_max_count = 10000;
335
336 int retry_count = 0;
337
338#ifdef O_CLOEXEC
339 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
340 flags |= O_CLOEXEC;
341#elif defined O_NOINHERIT
342 flags |= O_NOINHERIT;
343#endif
344
345 while ((ret = open(pathname, flags, mode)) == -1) {
346 int e = errno;
347 if (!io_again_p(e)) break;
348 if (retry_count++ >= retry_max_count) break;
349
350 sleep(retry_interval);
351 }
352
353 if (ret < 0) return ret;
354 if (ret <= 2 || o_cloexec_state == 0) {
355 rb_maygvl_fd_fix_cloexec(ret);
356 }
357 else if (o_cloexec_state > 0) {
358 return ret;
359 }
360 else {
361 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
362 }
363 return ret;
364}
365
366int
368{
369 /* Don't allocate standard file descriptors: 0, 1, 2 */
370 return rb_cloexec_fcntl_dupfd(oldfd, 3);
371}
372
373int
374rb_cloexec_dup2(int oldfd, int newfd)
375{
376 int ret;
377
378 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
379 * rb_cloexec_dup2 succeeds as dup2. */
380 if (oldfd == newfd) {
381 ret = newfd;
382 }
383 else {
384#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
385 static int try_dup3 = 1;
386 if (2 < newfd && try_dup3) {
387 ret = dup3(oldfd, newfd, O_CLOEXEC);
388 if (ret != -1)
389 return ret;
390 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
391 if (errno == ENOSYS) {
392 try_dup3 = 0;
393 ret = dup2(oldfd, newfd);
394 }
395 }
396 else {
397 ret = dup2(oldfd, newfd);
398 }
399#else
400 ret = dup2(oldfd, newfd);
401#endif
402 if (ret < 0) return ret;
403 }
404 rb_maygvl_fd_fix_cloexec(ret);
405 return ret;
406}
407
408static int
409rb_fd_set_nonblock(int fd)
410{
411#ifdef _WIN32
412 return rb_w32_set_nonblock(fd);
413#elif defined(F_GETFL)
414 int oflags = fcntl(fd, F_GETFL);
415
416 if (oflags == -1)
417 return -1;
418 if (oflags & O_NONBLOCK)
419 return 0;
420 oflags |= O_NONBLOCK;
421 return fcntl(fd, F_SETFL, oflags);
422#endif
423 return 0;
424}
425
426int
427rb_cloexec_pipe(int descriptors[2])
428{
429#ifdef HAVE_PIPE2
430 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
431#else
432 int result = pipe(descriptors);
433#endif
434
435 if (result < 0)
436 return result;
437
438#ifdef __CYGWIN__
439 if (result == 0 && descriptors[1] == -1) {
440 close(descriptors[0]);
441 descriptors[0] = -1;
442 errno = ENFILE;
443 return -1;
444 }
445#endif
446
447#ifndef HAVE_PIPE2
448 rb_maygvl_fd_fix_cloexec(descriptors[0]);
449 rb_maygvl_fd_fix_cloexec(descriptors[1]);
450
451#ifndef _WIN32
452 rb_fd_set_nonblock(descriptors[0]);
453 rb_fd_set_nonblock(descriptors[1]);
454#endif
455#endif
456
457 return result;
458}
459
460int
461rb_cloexec_fcntl_dupfd(int fd, int minfd)
462{
463 int ret;
464
465#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
466 static int try_dupfd_cloexec = 1;
467 if (try_dupfd_cloexec) {
468 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
469 if (ret != -1) {
470 if (ret <= 2)
471 rb_maygvl_fd_fix_cloexec(ret);
472 return ret;
473 }
474 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
475 if (errno == EINVAL) {
476 ret = fcntl(fd, F_DUPFD, minfd);
477 if (ret != -1) {
478 try_dupfd_cloexec = 0;
479 }
480 }
481 }
482 else {
483 ret = fcntl(fd, F_DUPFD, minfd);
484 }
485#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
486 ret = fcntl(fd, F_DUPFD, minfd);
487#else
488 ret = dup(fd);
489 if (ret >= 0 && ret < minfd) {
490 const int prev_fd = ret;
491 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
492 close(prev_fd);
493 }
494 return ret;
495#endif
496 if (ret < 0) return ret;
497 rb_maygvl_fd_fix_cloexec(ret);
498 return ret;
499}
500
501#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
502#define ARGF argf_of(argf)
503
504#define GetWriteIO(io) rb_io_get_write_io(io)
505
506#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
507#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
508#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
509#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
510
511#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
512#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
513#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
514
515#if defined(_WIN32)
516#define WAIT_FD_IN_WIN32(fptr) \
517 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
518#else
519#define WAIT_FD_IN_WIN32(fptr)
520#endif
521
522#define READ_CHECK(fptr) do {\
523 if (!READ_DATA_PENDING(fptr)) {\
524 WAIT_FD_IN_WIN32(fptr);\
525 rb_io_check_closed(fptr);\
526 }\
527} while(0)
528
529#ifndef S_ISSOCK
530# ifdef _S_ISSOCK
531# define S_ISSOCK(m) _S_ISSOCK(m)
532# else
533# ifdef _S_IFSOCK
534# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
535# else
536# ifdef S_IFSOCK
537# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
538# endif
539# endif
540# endif
541#endif
542
543static int io_fflush(rb_io_t *);
544static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
545static void clear_codeconv(rb_io_t *fptr);
546
547#define FMODE_SIGNAL_ON_EPIPE (1<<17)
548
549#define fptr_signal_on_epipe(fptr) \
550 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
551
552#define fptr_set_signal_on_epipe(fptr, flag) \
553 ((flag) ? \
554 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
555 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
556
557extern ID ruby_static_id_signo;
558
559NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
560static void
561rb_sys_fail_on_write(rb_io_t *fptr)
562{
563 int e = errno;
564 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
565#if defined EPIPE
566 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
567 const VALUE sig =
568# if defined SIGPIPE
569 INT2FIX(SIGPIPE) - INT2FIX(0) +
570# endif
571 INT2FIX(0);
572 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
573 }
574#endif
575 rb_exc_raise(errinfo);
576}
577
578#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
579#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
580#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
581# define RUBY_CRLF_ENVIRONMENT 1
582#else
583# define RUBY_CRLF_ENVIRONMENT 0
584#endif
585
586#if RUBY_CRLF_ENVIRONMENT
587/* Windows */
588# define DEFAULT_TEXTMODE FMODE_TEXTMODE
589# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
590/*
591 * CRLF newline is set as default newline decorator.
592 * If only CRLF newline conversion is needed, we use binary IO process
593 * with OS's text mode for IO performance improvement.
594 * If encoding conversion is needed or a user sets text mode, we use encoding
595 * conversion IO process and universal newline decorator by default.
596 */
597#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
598#define WRITECONV_MASK ( \
599 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
600 ECONV_STATEFUL_DECORATOR_MASK|\
601 0)
602#define NEED_WRITECONV(fptr) ( \
603 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
604 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
605 0)
606#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
607
608#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
609 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
610 if (((fptr)->mode & FMODE_READABLE) &&\
611 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
612 setmode((fptr)->fd, O_BINARY);\
613 }\
614 else {\
615 setmode((fptr)->fd, O_TEXT);\
616 }\
617 }\
618} while(0)
619
620#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
621 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
622 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
623 }\
624} while(0)
625
626/*
627 * IO unread with taking care of removed '\r' in text mode.
628 */
629static void
630io_unread(rb_io_t *fptr, bool discard_rbuf)
631{
632 rb_off_t r, pos;
633 ssize_t read_size;
634 long i;
635 long newlines = 0;
636 long extra_max;
637 char *p;
638 char *buf;
639
640 rb_io_check_closed(fptr);
641 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
642 return;
643 }
644
645 errno = 0;
646 if (!rb_w32_fd_is_text(fptr->fd)) {
647 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
648 if (r < 0 && errno) {
649 if (errno == ESPIPE)
650 fptr->mode |= FMODE_DUPLEX;
651 if (!discard_rbuf) return;
652 }
653
654 goto end;
655 }
656
657 pos = lseek(fptr->fd, 0, SEEK_CUR);
658 if (pos < 0 && errno) {
659 if (errno == ESPIPE)
660 fptr->mode |= FMODE_DUPLEX;
661 if (!discard_rbuf) goto end;
662 }
663
664 /* add extra offset for removed '\r' in rbuf */
665 extra_max = (long)(pos - fptr->rbuf.len);
666 p = fptr->rbuf.ptr + fptr->rbuf.off;
667
668 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
669 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
670 newlines++;
671 }
672
673 for (i = 0; i < fptr->rbuf.len; i++) {
674 if (*p == '\n') newlines++;
675 if (extra_max == newlines) break;
676 p++;
677 }
678
679 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
680 while (newlines >= 0) {
681 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
682 if (newlines == 0) break;
683 if (r < 0) {
684 newlines--;
685 continue;
686 }
687 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
688 if (read_size < 0) {
689 int e = errno;
690 free(buf);
691 rb_syserr_fail_path(e, fptr->pathv);
692 }
693 if (read_size == fptr->rbuf.len) {
694 lseek(fptr->fd, r, SEEK_SET);
695 break;
696 }
697 else {
698 newlines--;
699 }
700 }
701 free(buf);
702 end:
703 fptr->rbuf.off = 0;
704 fptr->rbuf.len = 0;
705 clear_codeconv(fptr);
706 return;
707}
708
709/*
710 * We use io_seek to back cursor position when changing mode from text to binary,
711 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
712 * conversion for working properly with mode change.
713 *
714 * Return previous translation mode.
715 */
716static inline int
717set_binary_mode_with_seek_cur(rb_io_t *fptr)
718{
719 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
720
721 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
722 return setmode(fptr->fd, O_BINARY);
723 }
724 flush_before_seek(fptr, false);
725 return setmode(fptr->fd, O_BINARY);
726}
727#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
728
729#else
730/* Unix */
731# define DEFAULT_TEXTMODE 0
732#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
733#define NEED_WRITECONV(fptr) ( \
734 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
735 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
736 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
737 0)
738#define SET_BINARY_MODE(fptr) (void)(fptr)
739#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
740#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
741#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
742#endif
743
744#if !defined HAVE_SHUTDOWN && !defined shutdown
745#define shutdown(a,b) 0
746#endif
747
748#if defined(_WIN32)
749#define is_socket(fd, path) rb_w32_is_socket(fd)
750#elif !defined(S_ISSOCK)
751#define is_socket(fd, path) 0
752#else
753static int
754is_socket(int fd, VALUE path)
755{
756 struct stat sbuf;
757 if (fstat(fd, &sbuf) < 0)
758 rb_sys_fail_path(path);
759 return S_ISSOCK(sbuf.st_mode);
760}
761#endif
762
763static const char closed_stream[] = "closed stream";
764
765static void
766io_fd_check_closed(int fd)
767{
768 if (fd < 0) {
769 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
770 rb_raise(rb_eIOError, closed_stream);
771 }
772}
773
774void
775rb_eof_error(void)
776{
777 rb_raise(rb_eEOFError, "end of file reached");
778}
779
780VALUE
782{
783 rb_check_frozen(io);
784 return io;
785}
786
787void
789{
790 if (!fptr) {
791 rb_raise(rb_eIOError, "uninitialized stream");
792 }
793}
794
795void
797{
799 io_fd_check_closed(fptr->fd);
800}
801
802static rb_io_t *
803rb_io_get_fptr(VALUE io)
804{
805 rb_io_t *fptr = RFILE(io)->fptr;
807 return fptr;
808}
809
810VALUE
812{
813 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
814}
815
816VALUE
818{
819 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
820}
821
822VALUE
824{
825 VALUE write_io;
826 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
827 if (write_io) {
828 return write_io;
829 }
830 return io;
831}
832
833VALUE
835{
836 VALUE write_io;
837 rb_io_t *fptr = rb_io_get_fptr(io);
838 if (!RTEST(w)) {
839 w = 0;
840 }
841 else {
842 GetWriteIO(w);
843 }
844 write_io = fptr->tied_io_for_writing;
845 fptr->tied_io_for_writing = w;
846 return write_io ? write_io : Qnil;
847}
848
849/*
850 * call-seq:
851 * timeout -> duration or nil
852 *
853 * Get the internal timeout duration or nil if it was not set.
854 *
855 */
856VALUE
858{
859 rb_io_t *fptr = rb_io_get_fptr(self);
860
861 return fptr->timeout;
862}
863
864/*
865 * call-seq:
866 * timeout = duration -> duration
867 * timeout = nil -> nil
868 *
869 * Sets the internal timeout to the specified duration or nil. The timeout
870 * applies to all blocking operations where possible.
871 *
872 * When the operation performs longer than the timeout set, IO::TimeoutError
873 * is raised.
874 *
875 * This affects the following methods (but is not limited to): #gets, #puts,
876 * #read, #write, #wait_readable and #wait_writable. This also affects
877 * blocking socket operations like Socket#accept and Socket#connect.
878 *
879 * Some operations like File#open and IO#close are not affected by the
880 * timeout. A timeout during a write operation may leave the IO in an
881 * inconsistent state, e.g. data was partially written. Generally speaking, a
882 * timeout is a last ditch effort to prevent an application from hanging on
883 * slow I/O operations, such as those that occur during a slowloris attack.
884 */
885VALUE
887{
888 // Validate it:
889 if (RTEST(timeout)) {
890 rb_time_interval(timeout);
891 }
892
893 rb_io_t *fptr = rb_io_get_fptr(self);
894
895 fptr->timeout = timeout;
896
897 return self;
898}
899
900/*
901 * call-seq:
902 * IO.try_convert(object) -> new_io or nil
903 *
904 * Attempts to convert +object+ into an \IO object via method +to_io+;
905 * returns the new \IO object if successful, or +nil+ otherwise:
906 *
907 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
908 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
909 * IO.try_convert('STDOUT') # => nil
910 *
911 */
912static VALUE
913rb_io_s_try_convert(VALUE dummy, VALUE io)
914{
915 return rb_io_check_io(io);
916}
917
918#if !RUBY_CRLF_ENVIRONMENT
919static void
920io_unread(rb_io_t *fptr, bool discard_rbuf)
921{
922 rb_off_t r;
923 rb_io_check_closed(fptr);
924 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
925 return;
926 /* xxx: target position may be negative if buffer is filled by ungetc */
927 errno = 0;
928 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
929 if (r < 0 && errno) {
930 if (errno == ESPIPE)
931 fptr->mode |= FMODE_DUPLEX;
932 if (!discard_rbuf) return;
933 }
934 fptr->rbuf.off = 0;
935 fptr->rbuf.len = 0;
936 clear_codeconv(fptr);
937 return;
938}
939#endif
940
941static rb_encoding *io_input_encoding(rb_io_t *fptr);
942
943static void
944io_ungetbyte(VALUE str, rb_io_t *fptr)
945{
946 long len = RSTRING_LEN(str);
947
948 if (fptr->rbuf.ptr == NULL) {
949 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
950 fptr->rbuf.off = 0;
951 fptr->rbuf.len = 0;
952#if SIZEOF_LONG > SIZEOF_INT
953 if (len > INT_MAX)
954 rb_raise(rb_eIOError, "ungetbyte failed");
955#endif
956 if (len > min_capa)
957 fptr->rbuf.capa = (int)len;
958 else
959 fptr->rbuf.capa = min_capa;
960 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
961 }
962 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
963 rb_raise(rb_eIOError, "ungetbyte failed");
964 }
965 if (fptr->rbuf.off < len) {
966 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
967 fptr->rbuf.ptr+fptr->rbuf.off,
968 char, fptr->rbuf.len);
969 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
970 }
971 fptr->rbuf.off-=(int)len;
972 fptr->rbuf.len+=(int)len;
973 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
974}
975
976static rb_io_t *
977flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
978{
979 if (io_fflush(fptr) < 0)
980 rb_sys_fail_on_write(fptr);
981 io_unread(fptr, discard_rbuf);
982 errno = 0;
983 return fptr;
984}
985
986#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
987#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
988
989#ifndef SEEK_CUR
990# define SEEK_SET 0
991# define SEEK_CUR 1
992# define SEEK_END 2
993#endif
994
995void
997{
998 rb_io_check_closed(fptr);
999 if (!(fptr->mode & FMODE_READABLE)) {
1000 rb_raise(rb_eIOError, "not opened for reading");
1001 }
1002 if (fptr->wbuf.len) {
1003 if (io_fflush(fptr) < 0)
1004 rb_sys_fail_on_write(fptr);
1005 }
1006 if (fptr->tied_io_for_writing) {
1007 rb_io_t *wfptr;
1008 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1009 if (io_fflush(wfptr) < 0)
1010 rb_sys_fail_on_write(wfptr);
1011 }
1012}
1013
1014void
1016{
1018 if (READ_CHAR_PENDING(fptr)) {
1019 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1020 }
1021}
1022
1023void
1028
1029static rb_encoding*
1030io_read_encoding(rb_io_t *fptr)
1031{
1032 if (fptr->encs.enc) {
1033 return fptr->encs.enc;
1034 }
1035 return rb_default_external_encoding();
1036}
1037
1038static rb_encoding*
1039io_input_encoding(rb_io_t *fptr)
1040{
1041 if (fptr->encs.enc2) {
1042 return fptr->encs.enc2;
1043 }
1044 return io_read_encoding(fptr);
1045}
1046
1047void
1049{
1050 rb_io_check_closed(fptr);
1051 if (!(fptr->mode & FMODE_WRITABLE)) {
1052 rb_raise(rb_eIOError, "not opened for writing");
1053 }
1054 if (fptr->rbuf.len) {
1055 io_unread(fptr, true);
1056 }
1057}
1058
1059int
1060rb_io_read_pending(rb_io_t *fptr)
1061{
1062 /* This function is used for bytes and chars. Confusing. */
1063 if (READ_CHAR_PENDING(fptr))
1064 return 1; /* should raise? */
1065 return READ_DATA_PENDING(fptr);
1066}
1067
1068void
1070{
1071 if (!READ_DATA_PENDING(fptr)) {
1072 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1073 }
1074 return;
1075}
1076
1077int
1078rb_gc_for_fd(int err)
1079{
1080 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1081 rb_gc();
1082 return 1;
1083 }
1084 return 0;
1085}
1086
1087/* try `expr` upto twice while it returns false and `errno`
1088 * is to GC. Each `errno`s are available as `first_errno` and
1089 * `retried_errno` respectively */
1090#define TRY_WITH_GC(expr) \
1091 for (int first_errno, retried_errno = 0, retried = 0; \
1092 (!retried && \
1093 !(expr) && \
1094 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1095 (retried_errno = errno, 1)); \
1096 (void)retried_errno, retried = 1)
1097
1098static int
1099ruby_dup(int orig)
1100{
1101 int fd = -1;
1102
1103 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1104 rb_syserr_fail(first_errno, 0);
1105 }
1106 rb_update_max_fd(fd);
1107 return fd;
1108}
1109
1110static VALUE
1111io_alloc(VALUE klass)
1112{
1113 NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
1114
1115 io->fptr = 0;
1116
1117 return (VALUE)io;
1118}
1119
1120#ifndef S_ISREG
1121# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1122#endif
1123
1125 VALUE th;
1126 rb_io_t *fptr;
1127 int nonblock;
1128 int fd;
1129
1130 void *buf;
1131 size_t capa;
1132 struct timeval *timeout;
1133};
1134
1136 VALUE th;
1137 rb_io_t *fptr;
1138 int nonblock;
1139 int fd;
1140
1141 const void *buf;
1142 size_t capa;
1143 struct timeval *timeout;
1144};
1145
1146#ifdef HAVE_WRITEV
1147struct io_internal_writev_struct {
1148 VALUE th;
1149 rb_io_t *fptr;
1150 int nonblock;
1151 int fd;
1152
1153 int iovcnt;
1154 const struct iovec *iov;
1155 struct timeval *timeout;
1156};
1157#endif
1158
1159static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1160
1166static inline int
1167io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1168{
1169 if (!timeout && rb_thread_mn_schedulable(thread)) {
1170 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1171 return -1;
1172 }
1173
1174 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1175
1176 if (ready > 0) {
1177 return ready;
1178 }
1179 else if (ready == 0) {
1180 errno = ETIMEDOUT;
1181 return -1;
1182 }
1183
1184 // If there was an error BEFORE we started waiting, return it:
1185 if (error) {
1186 errno = error;
1187 return -1;
1188 }
1189 else {
1190 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1191 return ready;
1192 }
1193}
1194
1195static VALUE
1196internal_read_func(void *ptr)
1197{
1198 struct io_internal_read_struct *iis = ptr;
1199 ssize_t result;
1200
1201 if (iis->timeout && !iis->nonblock) {
1202 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1203 return -1;
1204 }
1205 }
1206
1207 retry:
1208 result = read(iis->fd, iis->buf, iis->capa);
1209
1210 if (result < 0 && !iis->nonblock) {
1211 if (io_again_p(errno)) {
1212 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1213 return -1;
1214 }
1215 else {
1216 goto retry;
1217 }
1218 }
1219 }
1220
1221 return result;
1222}
1223
1224#if defined __APPLE__
1225# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1226#else
1227# define do_write_retry(code) result = code
1228#endif
1229
1230static VALUE
1231internal_write_func(void *ptr)
1232{
1233 struct io_internal_write_struct *iis = ptr;
1234 ssize_t result;
1235
1236 if (iis->timeout && !iis->nonblock) {
1237 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1238 return -1;
1239 }
1240 }
1241
1242 retry:
1243 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1244
1245 if (result < 0 && !iis->nonblock) {
1246 int e = errno;
1247 if (io_again_p(e)) {
1248 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1249 return -1;
1250 }
1251 else {
1252 goto retry;
1253 }
1254 }
1255 }
1256
1257 return result;
1258}
1259
1260#ifdef HAVE_WRITEV
1261static VALUE
1262internal_writev_func(void *ptr)
1263{
1264 struct io_internal_writev_struct *iis = ptr;
1265 ssize_t result;
1266
1267 if (iis->timeout && !iis->nonblock) {
1268 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1269 return -1;
1270 }
1271 }
1272
1273 retry:
1274 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1275
1276 if (result < 0 && !iis->nonblock) {
1277 if (io_again_p(errno)) {
1278 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1279 return -1;
1280 }
1281 else {
1282 goto retry;
1283 }
1284 }
1285 }
1286
1287 return result;
1288}
1289#endif
1290
1291static ssize_t
1292rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1293{
1294 rb_thread_t *th = GET_THREAD();
1296 if (scheduler != Qnil) {
1297 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1298
1299 if (!UNDEF_P(result)) {
1301 }
1302 }
1303
1304 struct io_internal_read_struct iis = {
1305 .th = th->self,
1306 .fptr = fptr,
1307 .nonblock = 0,
1308 .fd = fptr->fd,
1309
1310 .buf = buf,
1311 .capa = count,
1312 .timeout = NULL,
1313 };
1314
1315 struct timeval timeout_storage;
1316
1317 if (fptr->timeout != Qnil) {
1318 timeout_storage = rb_time_interval(fptr->timeout);
1319 iis.timeout = &timeout_storage;
1320 }
1321
1322 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1323}
1324
1325static ssize_t
1326rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1327{
1328 rb_thread_t *th = GET_THREAD();
1330 if (scheduler != Qnil) {
1331 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1332
1333 if (!UNDEF_P(result)) {
1335 }
1336 }
1337
1338 struct io_internal_write_struct iis = {
1339 .th = th->self,
1340 .fptr = fptr,
1341 .nonblock = 0,
1342 .fd = fptr->fd,
1343
1344 .buf = buf,
1345 .capa = count,
1346 .timeout = NULL
1347 };
1348
1349 struct timeval timeout_storage;
1350
1351 if (fptr->timeout != Qnil) {
1352 timeout_storage = rb_time_interval(fptr->timeout);
1353 iis.timeout = &timeout_storage;
1354 }
1355
1356 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1357}
1358
1359#ifdef HAVE_WRITEV
1360static ssize_t
1361rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1362{
1363 if (!iovcnt) return 0;
1364
1365 rb_thread_t *th = GET_THREAD();
1366
1368 if (scheduler != Qnil) {
1369 // This path assumes at least one `iov`:
1370 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1371
1372 if (!UNDEF_P(result)) {
1374 }
1375 }
1376
1377 struct io_internal_writev_struct iis = {
1378 .th = th->self,
1379 .fptr = fptr,
1380 .nonblock = 0,
1381 .fd = fptr->fd,
1382
1383 .iov = iov,
1384 .iovcnt = iovcnt,
1385 .timeout = NULL
1386 };
1387
1388 struct timeval timeout_storage;
1389
1390 if (fptr->timeout != Qnil) {
1391 timeout_storage = rb_time_interval(fptr->timeout);
1392 iis.timeout = &timeout_storage;
1393 }
1394
1395 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1396}
1397#endif
1398
1399static VALUE
1400io_flush_buffer_sync(void *arg)
1401{
1402 rb_io_t *fptr = arg;
1403 long l = fptr->wbuf.len;
1404 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1405
1406 if (fptr->wbuf.len <= r) {
1407 fptr->wbuf.off = 0;
1408 fptr->wbuf.len = 0;
1409 return 0;
1410 }
1411
1412 if (0 <= r) {
1413 fptr->wbuf.off += (int)r;
1414 fptr->wbuf.len -= (int)r;
1415 errno = EAGAIN;
1416 }
1417
1418 return (VALUE)-1;
1419}
1420
1421static VALUE
1422io_flush_buffer_async(VALUE arg)
1423{
1424 rb_io_t *fptr = (rb_io_t *)arg;
1425 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1426}
1427
1428static inline int
1429io_flush_buffer(rb_io_t *fptr)
1430{
1431 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1432 return (int)io_flush_buffer_async((VALUE)fptr);
1433 }
1434 else {
1435 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1436 }
1437}
1438
1439static int
1440io_fflush(rb_io_t *fptr)
1441{
1442 rb_io_check_closed(fptr);
1443
1444 if (fptr->wbuf.len == 0)
1445 return 0;
1446
1447 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1448 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1449 return -1;
1450
1451 rb_io_check_closed(fptr);
1452 }
1453
1454 return 0;
1455}
1456
1457VALUE
1458rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1459{
1460 rb_thread_t *th = GET_THREAD();
1462
1463 if (scheduler != Qnil) {
1464 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1465 }
1466
1467 rb_io_t * fptr = NULL;
1468 RB_IO_POINTER(io, fptr);
1469
1470 struct timeval tv_storage;
1471 struct timeval *tv = NULL;
1472
1473 if (NIL_OR_UNDEF_P(timeout)) {
1474 timeout = fptr->timeout;
1475 }
1476
1477 if (timeout != Qnil) {
1478 tv_storage = rb_time_interval(timeout);
1479 tv = &tv_storage;
1480 }
1481
1482 int ready = rb_thread_io_wait(th, fptr, RB_NUM2INT(events), tv);
1483
1484 if (ready < 0) {
1485 rb_sys_fail(0);
1486 }
1487
1488 // Not sure if this is necessary:
1489 rb_io_check_closed(fptr);
1490
1491 if (ready) {
1492 return RB_INT2NUM(ready);
1493 }
1494 else {
1495 return Qfalse;
1496 }
1497}
1498
1499static VALUE
1500io_from_fd(int fd)
1501{
1502 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1503}
1504
1505static int
1506io_wait_for_single_fd(int fd, int events, struct timeval *timeout, rb_thread_t *th, VALUE scheduler)
1507{
1508 if (scheduler != Qnil) {
1509 return RTEST(
1510 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1511 );
1512 }
1513
1514 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1515}
1516
1517int
1519{
1520 io_fd_check_closed(f);
1521
1522 rb_thread_t *th = GET_THREAD();
1524
1525 switch (errno) {
1526 case EINTR:
1527#if defined(ERESTART)
1528 case ERESTART:
1529#endif
1531 return TRUE;
1532
1533 case EAGAIN:
1534#if EWOULDBLOCK != EAGAIN
1535 case EWOULDBLOCK:
1536#endif
1537 if (scheduler != Qnil) {
1538 return RTEST(
1539 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1540 );
1541 }
1542 else {
1543 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL, th, scheduler);
1544 }
1545 return TRUE;
1546
1547 default:
1548 return FALSE;
1549 }
1550}
1551
1552int
1554{
1555 io_fd_check_closed(f);
1556
1557 rb_thread_t *th = GET_THREAD();
1559
1560 switch (errno) {
1561 case EINTR:
1562#if defined(ERESTART)
1563 case ERESTART:
1564#endif
1565 /*
1566 * In old Linux, several special files under /proc and /sys don't handle
1567 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1568 * Otherwise, we face nasty hang up. Sigh.
1569 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1570 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1571 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1572 * Then rb_thread_check_ints() is enough.
1573 */
1575 return TRUE;
1576
1577 case EAGAIN:
1578#if EWOULDBLOCK != EAGAIN
1579 case EWOULDBLOCK:
1580#endif
1581 if (scheduler != Qnil) {
1582 return RTEST(
1583 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1584 );
1585 }
1586 else {
1587 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL, th, scheduler);
1588 }
1589 return TRUE;
1590
1591 default:
1592 return FALSE;
1593 }
1594}
1595
1596int
1597rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1598{
1599 rb_thread_t *th = GET_THREAD();
1601 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1602}
1603
1604int
1606{
1607 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1608}
1609
1610int
1612{
1613 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1614}
1615
1616VALUE
1617rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1618{
1619 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1620 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1621 // instead relies on `read(-1) -> -1` which causes this code path. We then
1622 // check here whether the IO was in fact closed. Probably it's better to
1623 // check that `fptr->fd != -1` before using it in syscall.
1624 rb_io_check_closed(RFILE(io)->fptr);
1625
1626 switch (error) {
1627 // In old Linux, several special files under /proc and /sys don't handle
1628 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1629 // Otherwise, we face nasty hang up. Sigh.
1630 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1631 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1632 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1633 // Then rb_thread_check_ints() is enough.
1634 case EINTR:
1635#if defined(ERESTART)
1636 case ERESTART:
1637#endif
1638 // We might have pending interrupts since the previous syscall was interrupted:
1640
1641 // The operation was interrupted, so retry it immediately:
1642 return events;
1643
1644 case EAGAIN:
1645#if EWOULDBLOCK != EAGAIN
1646 case EWOULDBLOCK:
1647#endif
1648 // The operation would block, so wait for the specified events:
1649 return rb_io_wait(io, events, timeout);
1650
1651 default:
1652 // Non-specific error, no event is ready:
1653 return Qnil;
1654 }
1655}
1656
1657int
1659{
1660 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1661
1662 if (RTEST(result)) {
1663 return RB_NUM2INT(result);
1664 }
1665 else if (result == RUBY_Qfalse) {
1666 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1667 }
1668
1669 return 0;
1670}
1671
1672int
1674{
1675 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1676
1677 if (RTEST(result)) {
1678 return RB_NUM2INT(result);
1679 }
1680 else if (result == RUBY_Qfalse) {
1681 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1682 }
1683
1684 return 0;
1685}
1686
1687static void
1688make_writeconv(rb_io_t *fptr)
1689{
1690 if (!fptr->writeconv_initialized) {
1691 const char *senc, *denc;
1692 rb_encoding *enc;
1693 int ecflags;
1694 VALUE ecopts;
1695
1696 fptr->writeconv_initialized = 1;
1697
1698 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1699 ecopts = fptr->encs.ecopts;
1700
1701 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1702 /* no encoding conversion */
1703 fptr->writeconv_pre_ecflags = 0;
1704 fptr->writeconv_pre_ecopts = Qnil;
1705 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1706 if (!fptr->writeconv)
1707 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1709 }
1710 else {
1711 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1712 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1713 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1714 /* single conversion */
1715 fptr->writeconv_pre_ecflags = ecflags;
1716 fptr->writeconv_pre_ecopts = ecopts;
1717 fptr->writeconv = NULL;
1719 }
1720 else {
1721 /* double conversion */
1722 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1723 fptr->writeconv_pre_ecopts = ecopts;
1724 if (senc) {
1725 denc = rb_enc_name(enc);
1726 fptr->writeconv_asciicompat = rb_str_new2(senc);
1727 }
1728 else {
1729 senc = denc = "";
1730 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1731 }
1733 ecopts = fptr->encs.ecopts;
1734 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1735 if (!fptr->writeconv)
1736 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1737 }
1738 }
1739 }
1740}
1741
1742/* writing functions */
1744 rb_io_t *fptr;
1745 const char *ptr;
1746 long length;
1747};
1748
1750 VALUE io;
1751 VALUE str;
1752 int nosync;
1753};
1754
1755#ifdef HAVE_WRITEV
1756static ssize_t
1757io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1758{
1759 if (fptr->wbuf.len) {
1760 struct iovec iov[2];
1761
1762 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1763 iov[0].iov_len = fptr->wbuf.len;
1764 iov[1].iov_base = (void*)ptr;
1765 iov[1].iov_len = length;
1766
1767 ssize_t result = rb_writev_internal(fptr, iov, 2);
1768
1769 if (result < 0)
1770 return result;
1771
1772 if (result >= fptr->wbuf.len) {
1773 // We wrote more than the internal buffer:
1774 result -= fptr->wbuf.len;
1775 fptr->wbuf.off = 0;
1776 fptr->wbuf.len = 0;
1777 }
1778 else {
1779 // We only wrote less data than the internal buffer:
1780 fptr->wbuf.off += (int)result;
1781 fptr->wbuf.len -= (int)result;
1782
1783 result = 0;
1784 }
1785
1786 return result;
1787 }
1788 else {
1789 return rb_io_write_memory(fptr, ptr, length);
1790 }
1791}
1792#else
1793static ssize_t
1794io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1795{
1796 long remaining = length;
1797
1798 if (fptr->wbuf.len) {
1799 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1800 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1801 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1802 fptr->wbuf.off = 0;
1803 }
1804
1805 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1806 fptr->wbuf.len += (int)length;
1807
1808 // We copied the entire incoming data to the internal buffer:
1809 remaining = 0;
1810 }
1811
1812 // Flush the internal buffer:
1813 if (io_fflush(fptr) < 0) {
1814 return -1;
1815 }
1816
1817 // If all the data was buffered, we are done:
1818 if (remaining == 0) {
1819 return length;
1820 }
1821 }
1822
1823 // Otherwise, we should write the data directly:
1824 return rb_io_write_memory(fptr, ptr, length);
1825}
1826#endif
1827
1828static VALUE
1829io_binwrite_string(VALUE arg)
1830{
1831 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1832
1833 const char *ptr = p->ptr;
1834 size_t remaining = p->length;
1835
1836 while (remaining) {
1837 // Write as much as possible:
1838 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1839
1840 if (result == 0) {
1841 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1842 // should try again immediately.
1843 }
1844 else if (result > 0) {
1845 if ((size_t)result == remaining) break;
1846 ptr += result;
1847 remaining -= result;
1848 }
1849 // Wait for it to become writable:
1850 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1851 rb_io_check_closed(p->fptr);
1852 }
1853 else {
1854 // The error was unrelated to waiting for it to become writable, so we fail:
1855 return -1;
1856 }
1857 }
1858
1859 return p->length;
1860}
1861
1862inline static void
1863io_allocate_write_buffer(rb_io_t *fptr, int sync)
1864{
1865 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1866 fptr->wbuf.off = 0;
1867 fptr->wbuf.len = 0;
1868 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1869 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1870 }
1871
1872 if (NIL_P(fptr->write_lock)) {
1873 fptr->write_lock = rb_mutex_new();
1874 rb_mutex_allow_trap(fptr->write_lock, 1);
1875 }
1876}
1877
1878static inline int
1879io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1880{
1881 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1882 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1883 return 1;
1884
1885 // If the amount of data we want to write exceeds the internal buffer:
1886 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1887 return 1;
1888
1889 // Otherwise, we can append to the internal buffer:
1890 return 0;
1891}
1892
1893static long
1894io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1895{
1896 if (len <= 0) return len;
1897
1898 // Don't write anything if current thread has a pending interrupt:
1900
1901 io_allocate_write_buffer(fptr, !nosync);
1902
1903 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1904 struct binwrite_arg arg;
1905
1906 arg.fptr = fptr;
1907 arg.ptr = ptr;
1908 arg.length = len;
1909
1910 if (!NIL_P(fptr->write_lock)) {
1911 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1912 }
1913 else {
1914 return io_binwrite_string((VALUE)&arg);
1915 }
1916 }
1917 else {
1918 if (fptr->wbuf.off) {
1919 if (fptr->wbuf.len)
1920 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1921 fptr->wbuf.off = 0;
1922 }
1923
1924 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1925 fptr->wbuf.len += (int)len;
1926
1927 return len;
1928 }
1929}
1930
1931# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1932 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1933
1934#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1935 MODE_BTMODE(d, e, f) : \
1936 MODE_BTMODE(a, b, c))
1937
1938static VALUE
1939do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1940{
1941 if (NEED_WRITECONV(fptr)) {
1942 VALUE common_encoding = Qnil;
1943 SET_BINARY_MODE(fptr);
1944
1945 make_writeconv(fptr);
1946
1947 if (fptr->writeconv) {
1948#define fmode (fptr->mode)
1949 if (!NIL_P(fptr->writeconv_asciicompat))
1950 common_encoding = fptr->writeconv_asciicompat;
1951 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1952 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1953 rb_enc_name(rb_enc_get(str)));
1954 }
1955#undef fmode
1956 }
1957 else {
1958 if (fptr->encs.enc2)
1959 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1960 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1961 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1962 }
1963
1964 if (!NIL_P(common_encoding)) {
1965 str = rb_str_encode(str, common_encoding,
1967 *converted = 1;
1968 }
1969
1970 if (fptr->writeconv) {
1972 *converted = 1;
1973 }
1974 }
1975#if RUBY_CRLF_ENVIRONMENT
1976#define fmode (fptr->mode)
1977 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1978 if ((fptr->mode & FMODE_READABLE) &&
1980 setmode(fptr->fd, O_BINARY);
1981 }
1982 else {
1983 setmode(fptr->fd, O_TEXT);
1984 }
1985 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1986 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1987 rb_enc_name(rb_enc_get(str)));
1988 }
1989 }
1990#undef fmode
1991#endif
1992 return str;
1993}
1994
1995static long
1996io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1997{
1998 int converted = 0;
1999 VALUE tmp;
2000 long n, len;
2001 const char *ptr;
2002
2003#ifdef _WIN32
2004 if (fptr->mode & FMODE_TTY) {
2005 long len = rb_w32_write_console(str, fptr->fd);
2006 if (len > 0) return len;
2007 }
2008#endif
2009
2010 str = do_writeconv(str, fptr, &converted);
2011 if (converted)
2012 OBJ_FREEZE(str);
2013
2014 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2015 RSTRING_GETMEM(tmp, ptr, len);
2016 n = io_binwrite(ptr, len, fptr, nosync);
2017 rb_str_tmp_frozen_release(str, tmp);
2018
2019 return n;
2020}
2021
2022ssize_t
2023rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2024{
2025 rb_io_t *fptr;
2026
2027 GetOpenFile(io, fptr);
2029 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2030}
2031
2032static VALUE
2033io_write(VALUE io, VALUE str, int nosync)
2034{
2035 rb_io_t *fptr;
2036 long n;
2037 VALUE tmp;
2038
2039 io = GetWriteIO(io);
2040 str = rb_obj_as_string(str);
2041 tmp = rb_io_check_io(io);
2042
2043 if (NIL_P(tmp)) {
2044 /* port is not IO, call write method for it. */
2045 return rb_funcall(io, id_write, 1, str);
2046 }
2047
2048 io = tmp;
2049 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2050
2051 GetOpenFile(io, fptr);
2053
2054 n = io_fwrite(str, fptr, nosync);
2055 if (n < 0L) rb_sys_fail_on_write(fptr);
2056
2057 return LONG2FIX(n);
2058}
2059
2060#ifdef HAVE_WRITEV
2061struct binwritev_arg {
2062 rb_io_t *fptr;
2063 struct iovec *iov;
2064 int iovcnt;
2065 size_t total;
2066};
2067
2068static VALUE
2069io_binwritev_internal(VALUE arg)
2070{
2071 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2072
2073 size_t remaining = p->total;
2074 size_t offset = 0;
2075
2076 rb_io_t *fptr = p->fptr;
2077 struct iovec *iov = p->iov;
2078 int iovcnt = p->iovcnt;
2079
2080 while (remaining) {
2081 long result = rb_writev_internal(fptr, iov, iovcnt);
2082
2083 if (result >= 0) {
2084 offset += result;
2085 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2086 if (offset < (size_t)fptr->wbuf.len) {
2087 fptr->wbuf.off += result;
2088 fptr->wbuf.len -= result;
2089 }
2090 else {
2091 offset -= (size_t)fptr->wbuf.len;
2092 fptr->wbuf.off = 0;
2093 fptr->wbuf.len = 0;
2094 }
2095 }
2096
2097 if (offset == p->total) {
2098 return p->total;
2099 }
2100
2101 while (result >= (ssize_t)iov->iov_len) {
2102 /* iovcnt > 0 */
2103 result -= iov->iov_len;
2104 iov->iov_len = 0;
2105 iov++;
2106
2107 if (!--iovcnt) {
2108 // I don't believe this code path can ever occur.
2109 return offset;
2110 }
2111 }
2112
2113 iov->iov_base = (char *)iov->iov_base + result;
2114 iov->iov_len -= result;
2115 }
2116 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2117 rb_io_check_closed(fptr);
2118 }
2119 else {
2120 return -1;
2121 }
2122 }
2123
2124 return offset;
2125}
2126
2127static long
2128io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2129{
2130 // Don't write anything if current thread has a pending interrupt:
2132
2133 if (iovcnt == 0) return 0;
2134
2135 size_t total = 0;
2136 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2137
2138 io_allocate_write_buffer(fptr, 1);
2139
2140 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2141 // The end of the buffered data:
2142 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2143
2144 if (offset + total <= (size_t)fptr->wbuf.capa) {
2145 for (int i = 1; i < iovcnt; i++) {
2146 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2147 offset += iov[i].iov_len;
2148 }
2149
2150 fptr->wbuf.len += total;
2151
2152 return total;
2153 }
2154 else {
2155 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2156 iov[0].iov_len = fptr->wbuf.len;
2157 }
2158 }
2159 else {
2160 // The first iov is reserved for the internal buffer, and it's empty.
2161 iov++;
2162
2163 if (!--iovcnt) {
2164 // If there are no other io vectors we are done.
2165 return 0;
2166 }
2167 }
2168
2169 struct binwritev_arg arg;
2170 arg.fptr = fptr;
2171 arg.iov = iov;
2172 arg.iovcnt = iovcnt;
2173 arg.total = total;
2174
2175 if (!NIL_P(fptr->write_lock)) {
2176 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2177 }
2178 else {
2179 return io_binwritev_internal((VALUE)&arg);
2180 }
2181}
2182
2183static long
2184io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2185{
2186 int i, converted, iovcnt = argc + 1;
2187 long n;
2188 VALUE v1, v2, str, tmp, *tmp_array;
2189 struct iovec *iov;
2190
2191 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2192 tmp_array = ALLOCV_N(VALUE, v2, argc);
2193
2194 for (i = 0; i < argc; i++) {
2195 str = rb_obj_as_string(argv[i]);
2196 converted = 0;
2197 str = do_writeconv(str, fptr, &converted);
2198
2199 if (converted)
2200 OBJ_FREEZE(str);
2201
2202 tmp = rb_str_tmp_frozen_acquire(str);
2203 tmp_array[i] = tmp;
2204
2205 /* iov[0] is reserved for buffer of fptr */
2206 iov[i+1].iov_base = RSTRING_PTR(tmp);
2207 iov[i+1].iov_len = RSTRING_LEN(tmp);
2208 }
2209
2210 n = io_binwritev(iov, iovcnt, fptr);
2211 if (v1) ALLOCV_END(v1);
2212
2213 for (i = 0; i < argc; i++) {
2214 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2215 }
2216
2217 if (v2) ALLOCV_END(v2);
2218
2219 return n;
2220}
2221
2222static int
2223iovcnt_ok(int iovcnt)
2224{
2225#ifdef IOV_MAX
2226 return iovcnt < IOV_MAX;
2227#else /* GNU/Hurd has writev, but no IOV_MAX */
2228 return 1;
2229#endif
2230}
2231#endif /* HAVE_WRITEV */
2232
2233static VALUE
2234io_writev(int argc, const VALUE *argv, VALUE io)
2235{
2236 rb_io_t *fptr;
2237 long n;
2238 VALUE tmp, total = INT2FIX(0);
2239 int i, cnt = 1;
2240
2241 io = GetWriteIO(io);
2242 tmp = rb_io_check_io(io);
2243
2244 if (NIL_P(tmp)) {
2245 /* port is not IO, call write method for it. */
2246 return rb_funcallv(io, id_write, argc, argv);
2247 }
2248
2249 io = tmp;
2250
2251 GetOpenFile(io, fptr);
2253
2254 for (i = 0; i < argc; i += cnt) {
2255#ifdef HAVE_WRITEV
2256 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2257 n = io_fwritev(cnt, &argv[i], fptr);
2258 }
2259 else
2260#endif
2261 {
2262 cnt = 1;
2263 /* sync at last item */
2264 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2265 }
2266
2267 if (n < 0L)
2268 rb_sys_fail_on_write(fptr);
2269
2270 total = rb_fix_plus(LONG2FIX(n), total);
2271 }
2272
2273 return total;
2274}
2275
2276/*
2277 * call-seq:
2278 * write(*objects) -> integer
2279 *
2280 * Writes each of the given +objects+ to +self+,
2281 * which must be opened for writing
2282 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2283 * returns the total number bytes written;
2284 * each of +objects+ that is not a string is converted via method +to_s+:
2285 *
2286 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2287 * $stdout.write('foo', :bar, 2, "\n") # => 8
2288 *
2289 * Output:
2290 *
2291 * Hello, World!
2292 * foobar2
2293 *
2294 * Related: IO#read.
2295 */
2296
2297static VALUE
2298io_write_m(int argc, VALUE *argv, VALUE io)
2299{
2300 if (argc != 1) {
2301 return io_writev(argc, argv, io);
2302 }
2303 else {
2304 VALUE str = argv[0];
2305 return io_write(io, str, 0);
2306 }
2307}
2308
2309VALUE
2310rb_io_write(VALUE io, VALUE str)
2311{
2312 return rb_funcallv(io, id_write, 1, &str);
2313}
2314
2315static VALUE
2316rb_io_writev(VALUE io, int argc, const VALUE *argv)
2317{
2318 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2319 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2320 VALUE klass = CLASS_OF(io);
2321 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2323 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2324 " which accepts just one argument",
2325 klass, sep
2326 );
2327 }
2328
2329 do rb_io_write(io, *argv++); while (--argc);
2330
2331 return Qnil;
2332 }
2333
2334 return rb_funcallv(io, id_write, argc, argv);
2335}
2336
2337/*
2338 * call-seq:
2339 * self << object -> self
2340 *
2341 * Writes the given +object+ to +self+,
2342 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2343 * returns +self+;
2344 * if +object+ is not a string, it is converted via method +to_s+:
2345 *
2346 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2347 * $stdout << 'foo' << :bar << 2 << "\n"
2348 *
2349 * Output:
2350 *
2351 * Hello, World!
2352 * foobar2
2353 *
2354 */
2355
2356
2357VALUE
2359{
2360 rb_io_write(io, str);
2361 return io;
2362}
2363
2364#ifdef HAVE_FSYNC
2365static VALUE
2366nogvl_fsync(void *ptr)
2367{
2368 rb_io_t *fptr = ptr;
2369
2370#ifdef _WIN32
2371 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2372 return 0;
2373#endif
2374 return (VALUE)fsync(fptr->fd);
2375}
2376#endif
2377
2378VALUE
2379rb_io_flush_raw(VALUE io, int sync)
2380{
2381 rb_io_t *fptr;
2382
2383 if (!RB_TYPE_P(io, T_FILE)) {
2384 return rb_funcall(io, id_flush, 0);
2385 }
2386
2387 io = GetWriteIO(io);
2388 GetOpenFile(io, fptr);
2389
2390 if (fptr->mode & FMODE_WRITABLE) {
2391 if (io_fflush(fptr) < 0)
2392 rb_sys_fail_on_write(fptr);
2393 }
2394 if (fptr->mode & FMODE_READABLE) {
2395 io_unread(fptr, true);
2396 }
2397
2398 return io;
2399}
2400
2401/*
2402 * call-seq:
2403 * flush -> self
2404 *
2405 * Flushes data buffered in +self+ to the operating system
2406 * (but does not necessarily flush data buffered in the operating system):
2407 *
2408 * $stdout.print 'no newline' # Not necessarily flushed.
2409 * $stdout.flush # Flushed.
2410 *
2411 */
2412
2413VALUE
2414rb_io_flush(VALUE io)
2415{
2416 return rb_io_flush_raw(io, 1);
2417}
2418
2419/*
2420 * call-seq:
2421 * tell -> integer
2422 *
2423 * Returns the current position (in bytes) in +self+
2424 * (see {Position}[rdoc-ref:IO@Position]):
2425 *
2426 * f = File.open('t.txt')
2427 * f.tell # => 0
2428 * f.gets # => "First line\n"
2429 * f.tell # => 12
2430 * f.close
2431 *
2432 * Related: IO#pos=, IO#seek.
2433 */
2434
2435static VALUE
2436rb_io_tell(VALUE io)
2437{
2438 rb_io_t *fptr;
2439 rb_off_t pos;
2440
2441 GetOpenFile(io, fptr);
2442 pos = io_tell(fptr);
2443 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2444 pos -= fptr->rbuf.len;
2445 return OFFT2NUM(pos);
2446}
2447
2448static VALUE
2449rb_io_seek(VALUE io, VALUE offset, int whence)
2450{
2451 rb_io_t *fptr;
2452 rb_off_t pos;
2453
2454 pos = NUM2OFFT(offset);
2455 GetOpenFile(io, fptr);
2456 pos = io_seek(fptr, pos, whence);
2457 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2458
2459 return INT2FIX(0);
2460}
2461
2462static int
2463interpret_seek_whence(VALUE vwhence)
2464{
2465 if (vwhence == sym_SET)
2466 return SEEK_SET;
2467 if (vwhence == sym_CUR)
2468 return SEEK_CUR;
2469 if (vwhence == sym_END)
2470 return SEEK_END;
2471#ifdef SEEK_DATA
2472 if (vwhence == sym_DATA)
2473 return SEEK_DATA;
2474#endif
2475#ifdef SEEK_HOLE
2476 if (vwhence == sym_HOLE)
2477 return SEEK_HOLE;
2478#endif
2479 return NUM2INT(vwhence);
2480}
2481
2482/*
2483 * call-seq:
2484 * seek(offset, whence = IO::SEEK_SET) -> 0
2485 *
2486 * Seeks to the position given by integer +offset+
2487 * (see {Position}[rdoc-ref:IO@Position])
2488 * and constant +whence+, which is one of:
2489 *
2490 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2491 * Repositions the stream to its current position plus the given +offset+:
2492 *
2493 * f = File.open('t.txt')
2494 * f.tell # => 0
2495 * f.seek(20, :CUR) # => 0
2496 * f.tell # => 20
2497 * f.seek(-10, :CUR) # => 0
2498 * f.tell # => 10
2499 * f.close
2500 *
2501 * - +:END+ or <tt>IO::SEEK_END</tt>:
2502 * Repositions the stream to its end plus the given +offset+:
2503 *
2504 * f = File.open('t.txt')
2505 * f.tell # => 0
2506 * f.seek(0, :END) # => 0 # Repositions to stream end.
2507 * f.tell # => 52
2508 * f.seek(-20, :END) # => 0
2509 * f.tell # => 32
2510 * f.seek(-40, :END) # => 0
2511 * f.tell # => 12
2512 * f.close
2513 *
2514 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2515 * Repositions the stream to the given +offset+:
2516 *
2517 * f = File.open('t.txt')
2518 * f.tell # => 0
2519 * f.seek(20, :SET) # => 0
2520 * f.tell # => 20
2521 * f.seek(40, :SET) # => 0
2522 * f.tell # => 40
2523 * f.close
2524 *
2525 * Related: IO#pos=, IO#tell.
2526 *
2527 */
2528
2529static VALUE
2530rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2531{
2532 VALUE offset, ptrname;
2533 int whence = SEEK_SET;
2534
2535 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2536 whence = interpret_seek_whence(ptrname);
2537 }
2538
2539 return rb_io_seek(io, offset, whence);
2540}
2541
2542/*
2543 * call-seq:
2544 * pos = new_position -> new_position
2545 *
2546 * Seeks to the given +new_position+ (in bytes);
2547 * see {Position}[rdoc-ref:IO@Position]:
2548 *
2549 * f = File.open('t.txt')
2550 * f.tell # => 0
2551 * f.pos = 20 # => 20
2552 * f.tell # => 20
2553 * f.close
2554 *
2555 * Related: IO#seek, IO#tell.
2556 *
2557 */
2558
2559static VALUE
2560rb_io_set_pos(VALUE io, VALUE offset)
2561{
2562 rb_io_t *fptr;
2563 rb_off_t pos;
2564
2565 pos = NUM2OFFT(offset);
2566 GetOpenFile(io, fptr);
2567 pos = io_seek(fptr, pos, SEEK_SET);
2568 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2569
2570 return OFFT2NUM(pos);
2571}
2572
2573static void clear_readconv(rb_io_t *fptr);
2574
2575/*
2576 * call-seq:
2577 * rewind -> 0
2578 *
2579 * Repositions the stream to its beginning,
2580 * setting both the position and the line number to zero;
2581 * see {Position}[rdoc-ref:IO@Position]
2582 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2583 *
2584 * f = File.open('t.txt')
2585 * f.tell # => 0
2586 * f.lineno # => 0
2587 * f.gets # => "First line\n"
2588 * f.tell # => 12
2589 * f.lineno # => 1
2590 * f.rewind # => 0
2591 * f.tell # => 0
2592 * f.lineno # => 0
2593 * f.close
2594 *
2595 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2596 *
2597 */
2598
2599static VALUE
2600rb_io_rewind(VALUE io)
2601{
2602 rb_io_t *fptr;
2603
2604 GetOpenFile(io, fptr);
2605 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2606 if (io == ARGF.current_file) {
2607 ARGF.lineno -= fptr->lineno;
2608 }
2609 fptr->lineno = 0;
2610 if (fptr->readconv) {
2611 clear_readconv(fptr);
2612 }
2613
2614 return INT2FIX(0);
2615}
2616
2617static int
2618fptr_wait_readable(rb_io_t *fptr)
2619{
2620 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2621
2622 if (result)
2623 rb_io_check_closed(fptr);
2624
2625 return result;
2626}
2627
2628static int
2629io_fillbuf(rb_io_t *fptr)
2630{
2631 ssize_t r;
2632
2633 if (fptr->rbuf.ptr == NULL) {
2634 fptr->rbuf.off = 0;
2635 fptr->rbuf.len = 0;
2636 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2637 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2638#ifdef _WIN32
2639 fptr->rbuf.capa--;
2640#endif
2641 }
2642 if (fptr->rbuf.len == 0) {
2643 retry:
2644 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2645
2646 if (r < 0) {
2647 if (fptr_wait_readable(fptr))
2648 goto retry;
2649
2650 int e = errno;
2651 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2652 if (!NIL_P(fptr->pathv)) {
2653 rb_str_append(path, fptr->pathv);
2654 }
2655
2656 rb_syserr_fail_path(e, path);
2657 }
2658 if (r > 0) rb_io_check_closed(fptr);
2659 fptr->rbuf.off = 0;
2660 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2661 if (r == 0)
2662 return -1; /* EOF */
2663 }
2664 return 0;
2665}
2666
2667/*
2668 * call-seq:
2669 * eof -> true or false
2670 *
2671 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2672 * see {Position}[rdoc-ref:IO@Position]:
2673 *
2674 * f = File.open('t.txt')
2675 * f.eof # => false
2676 * f.seek(0, :END) # => 0
2677 * f.eof # => true
2678 * f.close
2679 *
2680 * Raises an exception unless the stream is opened for reading;
2681 * see {Mode}[rdoc-ref:File@Access+Modes].
2682 *
2683 * If +self+ is a stream such as pipe or socket, this method
2684 * blocks until the other end sends some data or closes it:
2685 *
2686 * r, w = IO.pipe
2687 * Thread.new { sleep 1; w.close }
2688 * r.eof? # => true # After 1-second wait.
2689 *
2690 * r, w = IO.pipe
2691 * Thread.new { sleep 1; w.puts "a" }
2692 * r.eof? # => false # After 1-second wait.
2693 *
2694 * r, w = IO.pipe
2695 * r.eof? # blocks forever
2696 *
2697 * Note that this method reads data to the input byte buffer. So
2698 * IO#sysread may not behave as you intend with IO#eof?, unless you
2699 * call IO#rewind first (which is not available for some streams).
2700 */
2701
2702VALUE
2704{
2705 rb_io_t *fptr;
2706
2707 GetOpenFile(io, fptr);
2709
2710 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2711 if (READ_DATA_PENDING(fptr)) return Qfalse;
2712 READ_CHECK(fptr);
2713#if RUBY_CRLF_ENVIRONMENT
2714 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2715 return RBOOL(eof(fptr->fd));
2716 }
2717#endif
2718 return RBOOL(io_fillbuf(fptr) < 0);
2719}
2720
2721/*
2722 * call-seq:
2723 * sync -> true or false
2724 *
2725 * Returns the current sync mode of the stream.
2726 * When sync mode is true, all output is immediately flushed to the underlying
2727 * operating system and is not buffered by Ruby internally. See also #fsync.
2728 *
2729 * f = File.open('t.tmp', 'w')
2730 * f.sync # => false
2731 * f.sync = true
2732 * f.sync # => true
2733 * f.close
2734 *
2735 */
2736
2737static VALUE
2738rb_io_sync(VALUE io)
2739{
2740 rb_io_t *fptr;
2741
2742 io = GetWriteIO(io);
2743 GetOpenFile(io, fptr);
2744 return RBOOL(fptr->mode & FMODE_SYNC);
2745}
2746
2747#ifdef HAVE_FSYNC
2748
2749/*
2750 * call-seq:
2751 * sync = boolean -> boolean
2752 *
2753 * Sets the _sync_ _mode_ for the stream to the given value;
2754 * returns the given value.
2755 *
2756 * Values for the sync mode:
2757 *
2758 * - +true+: All output is immediately flushed to the
2759 * underlying operating system and is not buffered internally.
2760 * - +false+: Output may be buffered internally.
2761 *
2762 * Example;
2763 *
2764 * f = File.open('t.tmp', 'w')
2765 * f.sync # => false
2766 * f.sync = true
2767 * f.sync # => true
2768 * f.close
2769 *
2770 * Related: IO#fsync.
2771 *
2772 */
2773
2774static VALUE
2775rb_io_set_sync(VALUE io, VALUE sync)
2776{
2777 rb_io_t *fptr;
2778
2779 io = GetWriteIO(io);
2780 GetOpenFile(io, fptr);
2781 if (RTEST(sync)) {
2782 fptr->mode |= FMODE_SYNC;
2783 }
2784 else {
2785 fptr->mode &= ~FMODE_SYNC;
2786 }
2787 return sync;
2788}
2789
2790/*
2791 * call-seq:
2792 * fsync -> 0
2793 *
2794 * Immediately writes to disk all data buffered in the stream,
2795 * via the operating system's <tt>fsync(2)</tt>.
2796
2797 * Note this difference:
2798 *
2799 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2800 * but does not guarantee that the operating system actually writes the data to disk.
2801 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2802 * and that data is written to disk.
2803 *
2804 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2805 *
2806 */
2807
2808static VALUE
2809rb_io_fsync(VALUE io)
2810{
2811 rb_io_t *fptr;
2812
2813 io = GetWriteIO(io);
2814 GetOpenFile(io, fptr);
2815
2816 if (io_fflush(fptr) < 0)
2817 rb_sys_fail_on_write(fptr);
2818
2819 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2820 rb_sys_fail_path(fptr->pathv);
2821
2822 return INT2FIX(0);
2823}
2824#else
2825# define rb_io_fsync rb_f_notimplement
2826# define rb_io_sync rb_f_notimplement
2827static VALUE
2828rb_io_set_sync(VALUE io, VALUE sync)
2829{
2832}
2833#endif
2834
2835#ifdef HAVE_FDATASYNC
2836static VALUE
2837nogvl_fdatasync(void *ptr)
2838{
2839 rb_io_t *fptr = ptr;
2840
2841#ifdef _WIN32
2842 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2843 return 0;
2844#endif
2845 return (VALUE)fdatasync(fptr->fd);
2846}
2847
2848/*
2849 * call-seq:
2850 * fdatasync -> 0
2851 *
2852 * Immediately writes to disk all data buffered in the stream,
2853 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2854 * otherwise via <tt>fsync(2)</tt>, if supported;
2855 * otherwise raises an exception.
2856 *
2857 */
2858
2859static VALUE
2860rb_io_fdatasync(VALUE io)
2861{
2862 rb_io_t *fptr;
2863
2864 io = GetWriteIO(io);
2865 GetOpenFile(io, fptr);
2866
2867 if (io_fflush(fptr) < 0)
2868 rb_sys_fail_on_write(fptr);
2869
2870 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2871 return INT2FIX(0);
2872
2873 /* fall back */
2874 return rb_io_fsync(io);
2875}
2876#else
2877#define rb_io_fdatasync rb_io_fsync
2878#endif
2879
2880/*
2881 * call-seq:
2882 * fileno -> integer
2883 *
2884 * Returns the integer file descriptor for the stream:
2885 *
2886 * $stdin.fileno # => 0
2887 * $stdout.fileno # => 1
2888 * $stderr.fileno # => 2
2889 * File.open('t.txt').fileno # => 10
2890 * f.close
2891 *
2892 */
2893
2894static VALUE
2895rb_io_fileno(VALUE io)
2896{
2897 rb_io_t *fptr = RFILE(io)->fptr;
2898 int fd;
2899
2900 rb_io_check_closed(fptr);
2901 fd = fptr->fd;
2902 return INT2FIX(fd);
2903}
2904
2905int
2907{
2908 if (RB_TYPE_P(io, T_FILE)) {
2909 rb_io_t *fptr = RFILE(io)->fptr;
2910 rb_io_check_closed(fptr);
2911 return fptr->fd;
2912 }
2913 else {
2914 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2915 if (!UNDEF_P(fileno)) {
2916 return RB_NUM2INT(fileno);
2917 }
2918 }
2919
2920 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2921
2923}
2924
2925int
2926rb_io_mode(VALUE io)
2927{
2928 rb_io_t *fptr;
2929 GetOpenFile(io, fptr);
2930 return fptr->mode;
2931}
2932
2933/*
2934 * call-seq:
2935 * pid -> integer or nil
2936 *
2937 * Returns the process ID of a child process associated with the stream,
2938 * which will have been set by IO#popen, or +nil+ if the stream was not
2939 * created by IO#popen:
2940 *
2941 * pipe = IO.popen("-")
2942 * if pipe
2943 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2944 * else
2945 * $stderr.puts "In child, pid is #{$$}"
2946 * end
2947 *
2948 * Output:
2949 *
2950 * In child, pid is 26209
2951 * In parent, child pid is 26209
2952 *
2953 */
2954
2955static VALUE
2956rb_io_pid(VALUE io)
2957{
2958 rb_io_t *fptr;
2959
2960 GetOpenFile(io, fptr);
2961 if (!fptr->pid)
2962 return Qnil;
2963 return PIDT2NUM(fptr->pid);
2964}
2965
2966/*
2967 * call-seq:
2968 * path -> string or nil
2969 *
2970 * Returns the path associated with the IO, or +nil+ if there is no path
2971 * associated with the IO. It is not guaranteed that the path exists on
2972 * the filesystem.
2973 *
2974 * $stdin.path # => "<STDIN>"
2975 *
2976 * File.open("testfile") {|f| f.path} # => "testfile"
2977 */
2978
2979VALUE
2981{
2982 rb_io_t *fptr = RFILE(io)->fptr;
2983
2984 if (!fptr)
2985 return Qnil;
2986
2987 return rb_obj_dup(fptr->pathv);
2988}
2989
2990/*
2991 * call-seq:
2992 * inspect -> string
2993 *
2994 * Returns a string representation of +self+:
2995 *
2996 * f = File.open('t.txt')
2997 * f.inspect # => "#<File:t.txt>"
2998 * f.close
2999 *
3000 */
3001
3002static VALUE
3003rb_io_inspect(VALUE obj)
3004{
3005 rb_io_t *fptr;
3006 VALUE result;
3007 static const char closed[] = " (closed)";
3008
3009 fptr = RFILE(obj)->fptr;
3010 if (!fptr) return rb_any_to_s(obj);
3011 result = rb_str_new_cstr("#<");
3012 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3013 rb_str_cat2(result, ":");
3014 if (NIL_P(fptr->pathv)) {
3015 if (fptr->fd < 0) {
3016 rb_str_cat(result, closed+1, strlen(closed)-1);
3017 }
3018 else {
3019 rb_str_catf(result, "fd %d", fptr->fd);
3020 }
3021 }
3022 else {
3023 rb_str_append(result, fptr->pathv);
3024 if (fptr->fd < 0) {
3025 rb_str_cat(result, closed, strlen(closed));
3026 }
3027 }
3028 return rb_str_cat2(result, ">");
3029}
3030
3031/*
3032 * call-seq:
3033 * to_io -> self
3034 *
3035 * Returns +self+.
3036 *
3037 */
3038
3039static VALUE
3040rb_io_to_io(VALUE io)
3041{
3042 return io;
3043}
3044
3045/* reading functions */
3046static long
3047read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3048{
3049 int n;
3050
3051 n = READ_DATA_PENDING_COUNT(fptr);
3052 if (n <= 0) return 0;
3053 if (n > len) n = (int)len;
3054 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3055 fptr->rbuf.off += n;
3056 fptr->rbuf.len -= n;
3057 return n;
3058}
3059
3060static long
3061io_bufread(char *ptr, long len, rb_io_t *fptr)
3062{
3063 long offset = 0;
3064 long n = len;
3065 long c;
3066
3067 if (READ_DATA_PENDING(fptr) == 0) {
3068 while (n > 0) {
3069 again:
3070 rb_io_check_closed(fptr);
3071 c = rb_io_read_memory(fptr, ptr+offset, n);
3072 if (c == 0) break;
3073 if (c < 0) {
3074 if (fptr_wait_readable(fptr))
3075 goto again;
3076 return -1;
3077 }
3078 offset += c;
3079 if ((n -= c) <= 0) break;
3080 }
3081 return len - n;
3082 }
3083
3084 while (n > 0) {
3085 c = read_buffered_data(ptr+offset, n, fptr);
3086 if (c > 0) {
3087 offset += c;
3088 if ((n -= c) <= 0) break;
3089 }
3090 rb_io_check_closed(fptr);
3091 if (io_fillbuf(fptr) < 0) {
3092 break;
3093 }
3094 }
3095 return len - n;
3096}
3097
3098static int io_setstrbuf(VALUE *str, long len);
3099
3101 char *str_ptr;
3102 long len;
3103 rb_io_t *fptr;
3104};
3105
3106static VALUE
3107bufread_call(VALUE arg)
3108{
3109 struct bufread_arg *p = (struct bufread_arg *)arg;
3110 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3111 return Qundef;
3112}
3113
3114static long
3115io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3116{
3117 long len;
3118 struct bufread_arg arg;
3119
3120 io_setstrbuf(&str, offset + size);
3121 arg.str_ptr = RSTRING_PTR(str) + offset;
3122 arg.len = size;
3123 arg.fptr = fptr;
3124 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3125 len = arg.len;
3126 if (len < 0) rb_sys_fail_path(fptr->pathv);
3127 return len;
3128}
3129
3130static long
3131remain_size(rb_io_t *fptr)
3132{
3133 struct stat st;
3134 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3135 rb_off_t pos;
3136
3137 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3138#if defined(__HAIKU__)
3139 && (st.st_dev > 3)
3140#endif
3141 )
3142 {
3143 if (io_fflush(fptr) < 0)
3144 rb_sys_fail_on_write(fptr);
3145 pos = lseek(fptr->fd, 0, SEEK_CUR);
3146 if (st.st_size >= pos && pos >= 0) {
3147 siz += st.st_size - pos;
3148 if (siz > LONG_MAX) {
3149 rb_raise(rb_eIOError, "file too big for single read");
3150 }
3151 }
3152 }
3153 else {
3154 siz += BUFSIZ;
3155 }
3156 return (long)siz;
3157}
3158
3159static VALUE
3160io_enc_str(VALUE str, rb_io_t *fptr)
3161{
3162 rb_enc_associate(str, io_read_encoding(fptr));
3163 return str;
3164}
3165
3166static void
3167make_readconv(rb_io_t *fptr, int size)
3168{
3169 if (!fptr->readconv) {
3170 int ecflags;
3171 VALUE ecopts;
3172 const char *sname, *dname;
3173 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3174 ecopts = fptr->encs.ecopts;
3175 if (fptr->encs.enc2) {
3176 sname = rb_enc_name(fptr->encs.enc2);
3177 dname = rb_enc_name(io_read_encoding(fptr));
3178 }
3179 else {
3180 sname = dname = "";
3181 }
3182 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3183 if (!fptr->readconv)
3184 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3185 fptr->cbuf.off = 0;
3186 fptr->cbuf.len = 0;
3187 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3188 fptr->cbuf.capa = size;
3189 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3190 }
3191}
3192
3193#define MORE_CHAR_SUSPENDED Qtrue
3194#define MORE_CHAR_FINISHED Qnil
3195static VALUE
3196fill_cbuf(rb_io_t *fptr, int ec_flags)
3197{
3198 const unsigned char *ss, *sp, *se;
3199 unsigned char *ds, *dp, *de;
3201 int putbackable;
3202 int cbuf_len0;
3203 VALUE exc;
3204
3205 ec_flags |= ECONV_PARTIAL_INPUT;
3206
3207 if (fptr->cbuf.len == fptr->cbuf.capa)
3208 return MORE_CHAR_SUSPENDED; /* cbuf full */
3209 if (fptr->cbuf.len == 0)
3210 fptr->cbuf.off = 0;
3211 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3212 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3213 fptr->cbuf.off = 0;
3214 }
3215
3216 cbuf_len0 = fptr->cbuf.len;
3217
3218 while (1) {
3219 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3220 se = sp + fptr->rbuf.len;
3221 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3222 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3223 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3224 fptr->rbuf.off += (int)(sp - ss);
3225 fptr->rbuf.len -= (int)(sp - ss);
3226 fptr->cbuf.len += (int)(dp - ds);
3227
3228 putbackable = rb_econv_putbackable(fptr->readconv);
3229 if (putbackable) {
3230 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3231 fptr->rbuf.off -= putbackable;
3232 fptr->rbuf.len += putbackable;
3233 }
3234
3235 exc = rb_econv_make_exception(fptr->readconv);
3236 if (!NIL_P(exc))
3237 return exc;
3238
3239 if (cbuf_len0 != fptr->cbuf.len)
3240 return MORE_CHAR_SUSPENDED;
3241
3242 if (res == econv_finished) {
3243 return MORE_CHAR_FINISHED;
3244 }
3245
3246 if (res == econv_source_buffer_empty) {
3247 if (fptr->rbuf.len == 0) {
3248 READ_CHECK(fptr);
3249 if (io_fillbuf(fptr) < 0) {
3250 if (!fptr->readconv) {
3251 return MORE_CHAR_FINISHED;
3252 }
3253 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3254 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3255 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3256 fptr->cbuf.len += (int)(dp - ds);
3258 break;
3259 }
3260 }
3261 }
3262 }
3263 if (cbuf_len0 != fptr->cbuf.len)
3264 return MORE_CHAR_SUSPENDED;
3265
3266 return MORE_CHAR_FINISHED;
3267}
3268
3269static VALUE
3270more_char(rb_io_t *fptr)
3271{
3272 VALUE v;
3273 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3274 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3275 rb_exc_raise(v);
3276 return v;
3277}
3278
3279static VALUE
3280io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3281{
3282 VALUE str = Qnil;
3283 if (strp) {
3284 str = *strp;
3285 if (NIL_P(str)) {
3286 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3287 }
3288 else {
3289 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3290 }
3291 rb_enc_associate(str, fptr->encs.enc);
3292 }
3293 fptr->cbuf.off += len;
3294 fptr->cbuf.len -= len;
3295 /* xxx: set coderange */
3296 if (fptr->cbuf.len == 0)
3297 fptr->cbuf.off = 0;
3298 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3299 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3300 fptr->cbuf.off = 0;
3301 }
3302 return str;
3303}
3304
3305static int
3306io_setstrbuf(VALUE *str, long len)
3307{
3308#ifdef _WIN32
3309 if (len > 0)
3310 len = (len + 1) & ~1L; /* round up for wide char */
3311#endif
3312 if (NIL_P(*str)) {
3313 *str = rb_str_new(0, len);
3314 return TRUE;
3315 }
3316 else {
3317 VALUE s = StringValue(*str);
3318 rb_str_modify(s);
3319
3320 long clen = RSTRING_LEN(s);
3321 if (clen >= len) {
3322 return FALSE;
3323 }
3324 len -= clen;
3325 }
3326 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3328 }
3329 return FALSE;
3330}
3331
3332#define MAX_REALLOC_GAP 4096
3333static void
3334io_shrink_read_string(VALUE str, long n)
3335{
3336 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3337 rb_str_resize(str, n);
3338 }
3339}
3340
3341static void
3342io_set_read_length(VALUE str, long n, int shrinkable)
3343{
3344 if (RSTRING_LEN(str) != n) {
3345 rb_str_modify(str);
3346 rb_str_set_len(str, n);
3347 if (shrinkable) io_shrink_read_string(str, n);
3348 }
3349}
3350
3351static VALUE
3352read_all(rb_io_t *fptr, long siz, VALUE str)
3353{
3354 long bytes;
3355 long n;
3356 long pos;
3357 rb_encoding *enc;
3358 int cr;
3359 int shrinkable;
3360
3361 if (NEED_READCONV(fptr)) {
3362 int first = !NIL_P(str);
3363 SET_BINARY_MODE(fptr);
3364 shrinkable = io_setstrbuf(&str,0);
3365 make_readconv(fptr, 0);
3366 while (1) {
3367 VALUE v;
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 v = fill_cbuf(fptr, 0);
3373 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3374 if (fptr->cbuf.len) {
3375 if (first) rb_str_set_len(str, first = 0);
3376 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3377 }
3378 rb_exc_raise(v);
3379 }
3380 if (v == MORE_CHAR_FINISHED) {
3381 clear_readconv(fptr);
3382 if (first) rb_str_set_len(str, first = 0);
3383 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3384 return io_enc_str(str, fptr);
3385 }
3386 }
3387 }
3388
3389 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3390 bytes = 0;
3391 pos = 0;
3392
3393 enc = io_read_encoding(fptr);
3394 cr = 0;
3395
3396 if (siz == 0) siz = BUFSIZ;
3397 shrinkable = io_setstrbuf(&str, siz);
3398 for (;;) {
3399 READ_CHECK(fptr);
3400 n = io_fread(str, bytes, siz - bytes, fptr);
3401 if (n == 0 && bytes == 0) {
3402 rb_str_set_len(str, 0);
3403 break;
3404 }
3405 bytes += n;
3406 rb_str_set_len(str, bytes);
3407 if (cr != ENC_CODERANGE_BROKEN)
3408 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3409 if (bytes < siz) break;
3410 siz += BUFSIZ;
3411
3412 size_t capa = rb_str_capacity(str);
3413 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3414 if (capa < BUFSIZ) {
3415 capa = BUFSIZ;
3416 }
3417 else if (capa > IO_MAX_BUFFER_GROWTH) {
3418 capa = IO_MAX_BUFFER_GROWTH;
3419 }
3421 }
3422 }
3423 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3424 str = io_enc_str(str, fptr);
3425 ENC_CODERANGE_SET(str, cr);
3426 return str;
3427}
3428
3429void
3431{
3432 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3433 rb_sys_fail_path(fptr->pathv);
3434 }
3435}
3436
3437static VALUE
3438io_read_memory_call(VALUE arg)
3439{
3440 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3441
3442 VALUE scheduler = rb_fiber_scheduler_current();
3443 if (scheduler != Qnil) {
3444 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3445
3446 if (!UNDEF_P(result)) {
3447 // This is actually returned as a pseudo-VALUE and later cast to a long:
3449 }
3450 }
3451
3452 if (iis->nonblock) {
3453 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3454 }
3455 else {
3456 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3457 }
3458}
3459
3460static long
3461io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3462{
3463 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3464}
3465
3466#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3467
3468static VALUE
3469io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3470{
3471 rb_io_t *fptr;
3472 VALUE length, str;
3473 long n, len;
3474 struct io_internal_read_struct iis;
3475 int shrinkable;
3476
3477 rb_scan_args(argc, argv, "11", &length, &str);
3478
3479 if ((len = NUM2LONG(length)) < 0) {
3480 rb_raise(rb_eArgError, "negative length %ld given", len);
3481 }
3482
3483 shrinkable = io_setstrbuf(&str, len);
3484
3485 GetOpenFile(io, fptr);
3487
3488 if (len == 0) {
3489 io_set_read_length(str, 0, shrinkable);
3490 return str;
3491 }
3492
3493 if (!nonblock)
3494 READ_CHECK(fptr);
3495 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3496 if (n <= 0) {
3497 again:
3498 if (nonblock) {
3499 rb_io_set_nonblock(fptr);
3500 }
3501 io_setstrbuf(&str, len);
3502 iis.th = rb_thread_current();
3503 iis.fptr = fptr;
3504 iis.nonblock = nonblock;
3505 iis.fd = fptr->fd;
3506 iis.buf = RSTRING_PTR(str);
3507 iis.capa = len;
3508 iis.timeout = NULL;
3509 n = io_read_memory_locktmp(str, &iis);
3510 if (n < 0) {
3511 int e = errno;
3512 if (!nonblock && fptr_wait_readable(fptr))
3513 goto again;
3514 if (nonblock && (io_again_p(e))) {
3515 if (no_exception)
3516 return sym_wait_readable;
3517 else
3518 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3519 e, "read would block");
3520 }
3521 rb_syserr_fail_path(e, fptr->pathv);
3522 }
3523 }
3524 io_set_read_length(str, n, shrinkable);
3525
3526 if (n == 0)
3527 return Qnil;
3528 else
3529 return str;
3530}
3531
3532/*
3533 * call-seq:
3534 * readpartial(maxlen) -> string
3535 * readpartial(maxlen, out_string) -> out_string
3536 *
3537 * Reads up to +maxlen+ bytes from the stream;
3538 * returns a string (either a new string or the given +out_string+).
3539 * Its encoding is:
3540 *
3541 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3542 * - ASCII-8BIT, otherwise.
3543 *
3544 * - Contains +maxlen+ bytes from the stream, if available.
3545 * - Otherwise contains all available bytes, if any available.
3546 * - Otherwise is an empty string.
3547 *
3548 * With the single non-negative integer argument +maxlen+ given,
3549 * returns a new string:
3550 *
3551 * f = File.new('t.txt')
3552 * f.readpartial(20) # => "First line\nSecond l"
3553 * f.readpartial(20) # => "ine\n\nFourth line\n"
3554 * f.readpartial(20) # => "Fifth line\n"
3555 * f.readpartial(20) # Raises EOFError.
3556 * f.close
3557 *
3558 * With both argument +maxlen+ and string argument +out_string+ given,
3559 * returns modified +out_string+:
3560 *
3561 * f = File.new('t.txt')
3562 * s = 'foo'
3563 * f.readpartial(20, s) # => "First line\nSecond l"
3564 * s = 'bar'
3565 * f.readpartial(0, s) # => ""
3566 * f.close
3567 *
3568 * This method is useful for a stream such as a pipe, a socket, or a tty.
3569 * It blocks only when no data is immediately available.
3570 * This means that it blocks only when _all_ of the following are true:
3571 *
3572 * - The byte buffer in the stream is empty.
3573 * - The content of the stream is empty.
3574 * - The stream is not at EOF.
3575 *
3576 * When blocked, the method waits for either more data or EOF on the stream:
3577 *
3578 * - If more data is read, the method returns the data.
3579 * - If EOF is reached, the method raises EOFError.
3580 *
3581 * When not blocked, the method responds immediately:
3582 *
3583 * - Returns data from the buffer if there is any.
3584 * - Otherwise returns data from the stream if there is any.
3585 * - Otherwise raises EOFError if the stream has reached EOF.
3586 *
3587 * Note that this method is similar to sysread. The differences are:
3588 *
3589 * - If the byte buffer is not empty, read from the byte buffer
3590 * instead of "sysread for buffered IO (IOError)".
3591 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3592 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3593 * readpartial retries the system call.
3594 *
3595 * The latter means that readpartial is non-blocking-flag insensitive.
3596 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3597 * if the fd is blocking mode.
3598 *
3599 * Examples:
3600 *
3601 * # # Returned Buffer Content Pipe Content
3602 * r, w = IO.pipe #
3603 * w << 'abc' # "" "abc".
3604 * r.readpartial(4096) # => "abc" "" ""
3605 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3606 *
3607 * # # Returned Buffer Content Pipe Content
3608 * r, w = IO.pipe #
3609 * w << 'abc' # "" "abc"
3610 * w.close # "" "abc" EOF
3611 * r.readpartial(4096) # => "abc" "" EOF
3612 * r.readpartial(4096) # raises EOFError
3613 *
3614 * # # Returned Buffer Content Pipe Content
3615 * r, w = IO.pipe #
3616 * w << "abc\ndef\n" # "" "abc\ndef\n"
3617 * r.gets # => "abc\n" "def\n" ""
3618 * w << "ghi\n" # "def\n" "ghi\n"
3619 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3620 * r.readpartial(4096) # => "ghi\n" "" ""
3621 *
3622 */
3623
3624static VALUE
3625io_readpartial(int argc, VALUE *argv, VALUE io)
3626{
3627 VALUE ret;
3628
3629 ret = io_getpartial(argc, argv, io, Qnil, 0);
3630 if (NIL_P(ret))
3631 rb_eof_error();
3632 return ret;
3633}
3634
3635static VALUE
3636io_nonblock_eof(int no_exception)
3637{
3638 if (!no_exception) {
3639 rb_eof_error();
3640 }
3641 return Qnil;
3642}
3643
3644/* :nodoc: */
3645static VALUE
3646io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3647{
3648 rb_io_t *fptr;
3649 long n, len;
3650 struct io_internal_read_struct iis;
3651 int shrinkable;
3652
3653 if ((len = NUM2LONG(length)) < 0) {
3654 rb_raise(rb_eArgError, "negative length %ld given", len);
3655 }
3656
3657 shrinkable = io_setstrbuf(&str, len);
3658 rb_bool_expected(ex, "exception", TRUE);
3659
3660 GetOpenFile(io, fptr);
3662
3663 if (len == 0) {
3664 io_set_read_length(str, 0, shrinkable);
3665 return str;
3666 }
3667
3668 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3669 if (n <= 0) {
3670 rb_fd_set_nonblock(fptr->fd);
3671 shrinkable |= io_setstrbuf(&str, len);
3672 iis.fptr = fptr;
3673 iis.nonblock = 1;
3674 iis.fd = fptr->fd;
3675 iis.buf = RSTRING_PTR(str);
3676 iis.capa = len;
3677 iis.timeout = NULL;
3678 n = io_read_memory_locktmp(str, &iis);
3679 if (n < 0) {
3680 int e = errno;
3681 if (io_again_p(e)) {
3682 if (!ex) return sym_wait_readable;
3683 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3684 e, "read would block");
3685 }
3686 rb_syserr_fail_path(e, fptr->pathv);
3687 }
3688 }
3689 io_set_read_length(str, n, shrinkable);
3690
3691 if (n == 0) {
3692 if (!ex) return Qnil;
3693 rb_eof_error();
3694 }
3695
3696 return str;
3697}
3698
3699/* :nodoc: */
3700static VALUE
3701io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3702{
3703 rb_io_t *fptr;
3704 long n;
3705
3706 if (!RB_TYPE_P(str, T_STRING))
3707 str = rb_obj_as_string(str);
3708 rb_bool_expected(ex, "exception", TRUE);
3709
3710 io = GetWriteIO(io);
3711 GetOpenFile(io, fptr);
3713
3714 if (io_fflush(fptr) < 0)
3715 rb_sys_fail_on_write(fptr);
3716
3717 rb_fd_set_nonblock(fptr->fd);
3718 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3719 RB_GC_GUARD(str);
3720
3721 if (n < 0) {
3722 int e = errno;
3723 if (io_again_p(e)) {
3724 if (!ex) {
3725 return sym_wait_writable;
3726 }
3727 else {
3728 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3729 }
3730 }
3731 rb_syserr_fail_path(e, fptr->pathv);
3732 }
3733
3734 return LONG2FIX(n);
3735}
3736
3737/*
3738 * call-seq:
3739 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3740 *
3741 * Reads bytes from the stream; the stream must be opened for reading
3742 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3743 *
3744 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3745 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3746 *
3747 * Returns a string (either a new string or the given +out_string+)
3748 * containing the bytes read.
3749 * The encoding of the string depends on both +maxLen+ and +out_string+:
3750 *
3751 * - +maxlen+ is +nil+: uses internal encoding of +self+
3752 * (regardless of whether +out_string+ was given).
3753 * - +maxlen+ not +nil+:
3754 *
3755 * - +out_string+ given: encoding of +out_string+ not modified.
3756 * - +out_string+ not given: ASCII-8BIT is used.
3757 *
3758 * <b>Without Argument +out_string+</b>
3759 *
3760 * When argument +out_string+ is omitted,
3761 * the returned value is a new string:
3762 *
3763 * f = File.new('t.txt')
3764 * f.read
3765 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3766 * f.rewind
3767 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3768 * f.read(30) # => "rth line\r\nFifth line\r\n"
3769 * f.read(30) # => nil
3770 * f.close
3771 *
3772 * If +maxlen+ is zero, returns an empty string.
3773 *
3774 * <b> With Argument +out_string+</b>
3775 *
3776 * When argument +out_string+ is given,
3777 * the returned value is +out_string+, whose content is replaced:
3778 *
3779 * f = File.new('t.txt')
3780 * s = 'foo' # => "foo"
3781 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3782 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3783 * f.rewind
3784 * s = 'bar'
3785 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3786 * s # => "First line\r\nSecond line\r\n\r\nFou"
3787 * s = 'baz'
3788 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3789 * s # => "rth line\r\nFifth line\r\n"
3790 * s = 'bat'
3791 * f.read(30, s) # => nil
3792 * s # => ""
3793 * f.close
3794 *
3795 * Note that this method behaves like the fread() function in C.
3796 * This means it retries to invoke read(2) system calls to read data
3797 * with the specified maxlen (or until EOF).
3798 *
3799 * This behavior is preserved even if the stream is in non-blocking mode.
3800 * (This method is non-blocking-flag insensitive as other methods.)
3801 *
3802 * If you need the behavior like a single read(2) system call,
3803 * consider #readpartial, #read_nonblock, and #sysread.
3804 *
3805 * Related: IO#write.
3806 */
3807
3808static VALUE
3809io_read(int argc, VALUE *argv, VALUE io)
3810{
3811 rb_io_t *fptr;
3812 long n, len;
3813 VALUE length, str;
3814 int shrinkable;
3815#if RUBY_CRLF_ENVIRONMENT
3816 int previous_mode;
3817#endif
3818
3819 rb_scan_args(argc, argv, "02", &length, &str);
3820
3821 if (NIL_P(length)) {
3822 GetOpenFile(io, fptr);
3824 return read_all(fptr, remain_size(fptr), str);
3825 }
3826 len = NUM2LONG(length);
3827 if (len < 0) {
3828 rb_raise(rb_eArgError, "negative length %ld given", len);
3829 }
3830
3831 shrinkable = io_setstrbuf(&str,len);
3832
3833 GetOpenFile(io, fptr);
3835 if (len == 0) {
3836 io_set_read_length(str, 0, shrinkable);
3837 return str;
3838 }
3839
3840 READ_CHECK(fptr);
3841#if RUBY_CRLF_ENVIRONMENT
3842 previous_mode = set_binary_mode_with_seek_cur(fptr);
3843#endif
3844 n = io_fread(str, 0, len, fptr);
3845 io_set_read_length(str, n, shrinkable);
3846#if RUBY_CRLF_ENVIRONMENT
3847 if (previous_mode == O_TEXT) {
3848 setmode(fptr->fd, O_TEXT);
3849 }
3850#endif
3851 if (n == 0) return Qnil;
3852
3853 return str;
3854}
3855
3856static void
3857rscheck(const char *rsptr, long rslen, VALUE rs)
3858{
3859 if (!rs) return;
3860 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3861 rb_raise(rb_eRuntimeError, "rs modified");
3862}
3863
3864static const char *
3865search_delim(const char *p, long len, int delim, rb_encoding *enc)
3866{
3867 if (rb_enc_mbminlen(enc) == 1) {
3868 p = memchr(p, delim, len);
3869 if (p) return p + 1;
3870 }
3871 else {
3872 const char *end = p + len;
3873 while (p < end) {
3874 int r = rb_enc_precise_mbclen(p, end, enc);
3875 if (!MBCLEN_CHARFOUND_P(r)) {
3876 p += rb_enc_mbminlen(enc);
3877 continue;
3878 }
3879 int n = MBCLEN_CHARFOUND_LEN(r);
3880 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3881 return p + n;
3882 }
3883 p += n;
3884 }
3885 }
3886 return NULL;
3887}
3888
3889static int
3890appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3891{
3892 VALUE str = *strp;
3893 long limit = *lp;
3894
3895 if (NEED_READCONV(fptr)) {
3896 SET_BINARY_MODE(fptr);
3897 make_readconv(fptr, 0);
3898 do {
3899 const char *p, *e;
3900 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3901 if (searchlen) {
3902 p = READ_CHAR_PENDING_PTR(fptr);
3903 if (0 < limit && limit < searchlen)
3904 searchlen = (int)limit;
3905 e = search_delim(p, searchlen, delim, enc);
3906 if (e) {
3907 int len = (int)(e-p);
3908 if (NIL_P(str))
3909 *strp = str = rb_str_new(p, len);
3910 else
3911 rb_str_buf_cat(str, p, len);
3912 fptr->cbuf.off += len;
3913 fptr->cbuf.len -= len;
3914 limit -= len;
3915 *lp = limit;
3916 return delim;
3917 }
3918
3919 if (NIL_P(str))
3920 *strp = str = rb_str_new(p, searchlen);
3921 else
3922 rb_str_buf_cat(str, p, searchlen);
3923 fptr->cbuf.off += searchlen;
3924 fptr->cbuf.len -= searchlen;
3925 limit -= searchlen;
3926
3927 if (limit == 0) {
3928 *lp = limit;
3929 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3930 }
3931 }
3932 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3933 clear_readconv(fptr);
3934 *lp = limit;
3935 return EOF;
3936 }
3937
3938 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3939 do {
3940 long pending = READ_DATA_PENDING_COUNT(fptr);
3941 if (pending > 0) {
3942 const char *p = READ_DATA_PENDING_PTR(fptr);
3943 const char *e;
3944 long last;
3945
3946 if (limit > 0 && pending > limit) pending = limit;
3947 e = search_delim(p, pending, delim, enc);
3948 if (e) pending = e - p;
3949 if (!NIL_P(str)) {
3950 last = RSTRING_LEN(str);
3951 rb_str_resize(str, last + pending);
3952 }
3953 else {
3954 last = 0;
3955 *strp = str = rb_str_buf_new(pending);
3956 rb_str_set_len(str, pending);
3957 }
3958 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3959 limit -= pending;
3960 *lp = limit;
3961 if (e) return delim;
3962 if (limit == 0)
3963 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3964 }
3965 READ_CHECK(fptr);
3966 } while (io_fillbuf(fptr) >= 0);
3967 *lp = limit;
3968 return EOF;
3969}
3970
3971static inline int
3972swallow(rb_io_t *fptr, int term)
3973{
3974 if (NEED_READCONV(fptr)) {
3975 rb_encoding *enc = io_read_encoding(fptr);
3976 int needconv = rb_enc_mbminlen(enc) != 1;
3977 SET_BINARY_MODE(fptr);
3978 make_readconv(fptr, 0);
3979 do {
3980 size_t cnt;
3981 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3982 const char *p = READ_CHAR_PENDING_PTR(fptr);
3983 int i;
3984 if (!needconv) {
3985 if (*p != term) return TRUE;
3986 i = (int)cnt;
3987 while (--i && *++p == term);
3988 }
3989 else {
3990 const char *e = p + cnt;
3991 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3992 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3993 i = (int)(e - p);
3994 }
3995 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3996 }
3997 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3998 return FALSE;
3999 }
4000
4001 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4002 do {
4003 size_t cnt;
4004 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4005 char buf[1024];
4006 const char *p = READ_DATA_PENDING_PTR(fptr);
4007 int i;
4008 if (cnt > sizeof buf) cnt = sizeof buf;
4009 if (*p != term) return TRUE;
4010 i = (int)cnt;
4011 while (--i && *++p == term);
4012 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4013 rb_sys_fail_path(fptr->pathv);
4014 }
4015 READ_CHECK(fptr);
4016 } while (io_fillbuf(fptr) == 0);
4017 return FALSE;
4018}
4019
4020static VALUE
4021rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4022{
4023 VALUE str = Qnil;
4024 int len = 0;
4025 long pos = 0;
4026 int cr = 0;
4027
4028 do {
4029 int pending = READ_DATA_PENDING_COUNT(fptr);
4030
4031 if (pending > 0) {
4032 const char *p = READ_DATA_PENDING_PTR(fptr);
4033 const char *e;
4034 int chomplen = 0;
4035
4036 e = memchr(p, '\n', pending);
4037 if (e) {
4038 pending = (int)(e - p + 1);
4039 if (chomp) {
4040 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4041 }
4042 }
4043 if (NIL_P(str)) {
4044 str = rb_str_new(p, pending - chomplen);
4045 fptr->rbuf.off += pending;
4046 fptr->rbuf.len -= pending;
4047 }
4048 else {
4049 rb_str_resize(str, len + pending - chomplen);
4050 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4051 fptr->rbuf.off += chomplen;
4052 fptr->rbuf.len -= chomplen;
4053 if (pending == 1 && chomplen == 1 && len > 0) {
4054 if (RSTRING_PTR(str)[len-1] == '\r') {
4055 rb_str_resize(str, --len);
4056 break;
4057 }
4058 }
4059 }
4060 len += pending - chomplen;
4061 if (cr != ENC_CODERANGE_BROKEN)
4062 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4063 if (e) break;
4064 }
4065 READ_CHECK(fptr);
4066 } while (io_fillbuf(fptr) >= 0);
4067 if (NIL_P(str)) return Qnil;
4068
4069 str = io_enc_str(str, fptr);
4070 ENC_CODERANGE_SET(str, cr);
4071 fptr->lineno++;
4072
4073 return str;
4074}
4075
4077 VALUE io;
4078 VALUE rs;
4079 long limit;
4080 unsigned int chomp: 1;
4081};
4082
4083static void
4084extract_getline_opts(VALUE opts, struct getline_arg *args)
4085{
4086 int chomp = FALSE;
4087 if (!NIL_P(opts)) {
4088 static ID kwds[1];
4089 VALUE vchomp;
4090 if (!kwds[0]) {
4091 kwds[0] = rb_intern_const("chomp");
4092 }
4093 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4094 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4095 }
4096 args->chomp = chomp;
4097}
4098
4099static void
4100extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4101{
4102 VALUE rs = rb_rs, lim = Qnil;
4103
4104 if (argc == 1) {
4105 VALUE tmp = Qnil;
4106
4107 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4108 rs = tmp;
4109 }
4110 else {
4111 lim = argv[0];
4112 }
4113 }
4114 else if (2 <= argc) {
4115 rs = argv[0], lim = argv[1];
4116 if (!NIL_P(rs))
4117 StringValue(rs);
4118 }
4119 args->rs = rs;
4120 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4121}
4122
4123static void
4124check_getline_args(VALUE *rsp, long *limit, VALUE io)
4125{
4126 rb_io_t *fptr;
4127 VALUE rs = *rsp;
4128
4129 if (!NIL_P(rs)) {
4130 rb_encoding *enc_rs, *enc_io;
4131
4132 GetOpenFile(io, fptr);
4133 enc_rs = rb_enc_get(rs);
4134 enc_io = io_read_encoding(fptr);
4135 if (enc_io != enc_rs &&
4136 (!is_ascii_string(rs) ||
4137 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4138 if (rs == rb_default_rs) {
4139 rs = rb_enc_str_new(0, 0, enc_io);
4140 rb_str_buf_cat_ascii(rs, "\n");
4141 *rsp = rs;
4142 }
4143 else {
4144 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4145 rb_enc_name(enc_io),
4146 rb_enc_name(enc_rs));
4147 }
4148 }
4149 }
4150}
4151
4152static void
4153prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4154{
4155 VALUE opts;
4156 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4157 extract_getline_args(argc, argv, args);
4158 extract_getline_opts(opts, args);
4159 check_getline_args(&args->rs, &args->limit, io);
4160}
4161
4162static VALUE
4163rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4164{
4165 VALUE str = Qnil;
4166 int nolimit = 0;
4167 rb_encoding *enc;
4168
4170 if (NIL_P(rs) && limit < 0) {
4171 str = read_all(fptr, 0, Qnil);
4172 if (RSTRING_LEN(str) == 0) return Qnil;
4173 }
4174 else if (limit == 0) {
4175 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4176 }
4177 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4178 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4179 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4180 return rb_io_getline_fast(fptr, enc, chomp);
4181 }
4182 else {
4183 int c, newline = -1;
4184 const char *rsptr = 0;
4185 long rslen = 0;
4186 int rspara = 0;
4187 int extra_limit = 16;
4188 int chomp_cr = chomp;
4189
4190 SET_BINARY_MODE(fptr);
4191 enc = io_read_encoding(fptr);
4192
4193 if (!NIL_P(rs)) {
4194 rslen = RSTRING_LEN(rs);
4195 if (rslen == 0) {
4196 rsptr = "\n\n";
4197 rslen = 2;
4198 rspara = 1;
4199 swallow(fptr, '\n');
4200 rs = 0;
4201 if (!rb_enc_asciicompat(enc)) {
4202 rs = rb_usascii_str_new(rsptr, rslen);
4203 rs = rb_str_conv_enc(rs, 0, enc);
4204 OBJ_FREEZE(rs);
4205 rsptr = RSTRING_PTR(rs);
4206 rslen = RSTRING_LEN(rs);
4207 }
4208 newline = '\n';
4209 }
4210 else if (rb_enc_mbminlen(enc) == 1) {
4211 rsptr = RSTRING_PTR(rs);
4212 newline = (unsigned char)rsptr[rslen - 1];
4213 }
4214 else {
4215 rs = rb_str_conv_enc(rs, 0, enc);
4216 rsptr = RSTRING_PTR(rs);
4217 const char *e = rsptr + rslen;
4218 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4219 int n;
4220 newline = rb_enc_codepoint_len(last, e, &n, enc);
4221 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4222 }
4223 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4224 }
4225
4226 /* MS - Optimization */
4227 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4228 const char *s, *p, *pp, *e;
4229
4230 if (c == newline) {
4231 if (RSTRING_LEN(str) < rslen) continue;
4232 s = RSTRING_PTR(str);
4233 e = RSTRING_END(str);
4234 p = e - rslen;
4235 if (!at_char_boundary(s, p, e, enc)) continue;
4236 if (!rspara) rscheck(rsptr, rslen, rs);
4237 if (memcmp(p, rsptr, rslen) == 0) {
4238 if (chomp) {
4239 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4240 rb_str_set_len(str, p - s);
4241 }
4242 break;
4243 }
4244 }
4245 if (limit == 0) {
4246 s = RSTRING_PTR(str);
4247 p = RSTRING_END(str);
4248 pp = rb_enc_prev_char(s, p, p, enc);
4249 if (extra_limit && pp &&
4250 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4251 /* relax the limit while incomplete character.
4252 * extra_limit limits the relax length */
4253 limit = 1;
4254 extra_limit--;
4255 }
4256 else {
4257 nolimit = 1;
4258 break;
4259 }
4260 }
4261 }
4262
4263 if (rspara && c != EOF)
4264 swallow(fptr, '\n');
4265 if (!NIL_P(str))
4266 str = io_enc_str(str, fptr);
4267 }
4268
4269 if (!NIL_P(str) && !nolimit) {
4270 fptr->lineno++;
4271 }
4272
4273 return str;
4274}
4275
4276static VALUE
4277rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4278{
4279 rb_io_t *fptr;
4280 int old_lineno, new_lineno;
4281 VALUE str;
4282
4283 GetOpenFile(io, fptr);
4284 old_lineno = fptr->lineno;
4285 str = rb_io_getline_0(rs, limit, chomp, fptr);
4286 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4287 if (io == ARGF.current_file) {
4288 ARGF.lineno += new_lineno - old_lineno;
4289 ARGF.last_lineno = ARGF.lineno;
4290 }
4291 else {
4292 ARGF.last_lineno = new_lineno;
4293 }
4294 }
4295
4296 return str;
4297}
4298
4299static VALUE
4300rb_io_getline(int argc, VALUE *argv, VALUE io)
4301{
4302 struct getline_arg args;
4303
4304 prepare_getline_args(argc, argv, &args, io);
4305 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4306}
4307
4308VALUE
4310{
4311 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4312}
4313
4314VALUE
4315rb_io_gets_limit_internal(VALUE io, long limit)
4316{
4317 rb_io_t *fptr;
4318 GetOpenFile(io, fptr);
4319 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4320}
4321
4322VALUE
4323rb_io_gets_internal(VALUE io)
4324{
4325 return rb_io_gets_limit_internal(io, -1);
4326}
4327
4328/*
4329 * call-seq:
4330 * gets(sep = $/, chomp: false) -> string or nil
4331 * gets(limit, chomp: false) -> string or nil
4332 * gets(sep, limit, chomp: false) -> string or nil
4333 *
4334 * Reads and returns a line from the stream;
4335 * assigns the return value to <tt>$_</tt>.
4336 * See {Line IO}[rdoc-ref:IO@Line+IO].
4337 *
4338 * With no arguments given, returns the next line
4339 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4340 *
4341 * f = File.open('t.txt')
4342 * f.gets # => "First line\n"
4343 * $_ # => "First line\n"
4344 * f.gets # => "\n"
4345 * f.gets # => "Fourth line\n"
4346 * f.gets # => "Fifth line\n"
4347 * f.gets # => nil
4348 * f.close
4349 *
4350 * With only string argument +sep+ given,
4351 * returns the next line as determined by line separator +sep+,
4352 * or +nil+ if none;
4353 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4354 *
4355 * f = File.new('t.txt')
4356 * f.gets('l') # => "First l"
4357 * f.gets('li') # => "ine\nSecond li"
4358 * f.gets('lin') # => "ne\n\nFourth lin"
4359 * f.gets # => "e\n"
4360 * f.close
4361 *
4362 * The two special values for +sep+ are honored:
4363 *
4364 * f = File.new('t.txt')
4365 * # Get all.
4366 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4367 * f.rewind
4368 * # Get paragraph (up to two line separators).
4369 * f.gets('') # => "First line\nSecond line\n\n"
4370 * f.close
4371 *
4372 * With only integer argument +limit+ given,
4373 * limits the number of bytes in the line;
4374 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4375 *
4376 * # No more than one line.
4377 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4378 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4379 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4380 *
4381 * With arguments +sep+ and +limit+ given,
4382 * combines the two behaviors
4383 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4384 *
4385 * Optional keyword argument +chomp+ specifies whether line separators
4386 * are to be omitted:
4387 *
4388 * f = File.open('t.txt')
4389 * # Chomp the lines.
4390 * f.gets(chomp: true) # => "First line"
4391 * f.gets(chomp: true) # => "Second line"
4392 * f.gets(chomp: true) # => ""
4393 * f.gets(chomp: true) # => "Fourth line"
4394 * f.gets(chomp: true) # => "Fifth line"
4395 * f.gets(chomp: true) # => nil
4396 * f.close
4397 *
4398 */
4399
4400static VALUE
4401rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4402{
4403 VALUE str;
4404
4405 str = rb_io_getline(argc, argv, io);
4406 rb_lastline_set(str);
4407
4408 return str;
4409}
4410
4411/*
4412 * call-seq:
4413 * lineno -> integer
4414 *
4415 * Returns the current line number for the stream;
4416 * see {Line Number}[rdoc-ref:IO@Line+Number].
4417 *
4418 */
4419
4420static VALUE
4421rb_io_lineno(VALUE io)
4422{
4423 rb_io_t *fptr;
4424
4425 GetOpenFile(io, fptr);
4427 return INT2NUM(fptr->lineno);
4428}
4429
4430/*
4431 * call-seq:
4432 * lineno = integer -> integer
4433 *
4434 * Sets and returns the line number for the stream;
4435 * see {Line Number}[rdoc-ref:IO@Line+Number].
4436 *
4437 */
4438
4439static VALUE
4440rb_io_set_lineno(VALUE io, VALUE lineno)
4441{
4442 rb_io_t *fptr;
4443
4444 GetOpenFile(io, fptr);
4446 fptr->lineno = NUM2INT(lineno);
4447 return lineno;
4448}
4449
4450/* :nodoc: */
4451static VALUE
4452io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4453{
4454 long limit = -1;
4455 if (NIL_P(lim)) {
4456 VALUE tmp = Qnil;
4457 // If sep is specified, but it's not a string and not nil, then assume
4458 // it's the limit (it should be an integer)
4459 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4460 // If the user has specified a non-nil / non-string value
4461 // for the separator, we assume it's the limit and set the
4462 // separator to default: rb_rs.
4463 lim = sep;
4464 limit = NUM2LONG(lim);
4465 sep = rb_rs;
4466 }
4467 else {
4468 sep = tmp;
4469 }
4470 }
4471 else {
4472 if (!NIL_P(sep)) StringValue(sep);
4473 limit = NUM2LONG(lim);
4474 }
4475
4476 check_getline_args(&sep, &limit, io);
4477
4478 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4479 rb_lastline_set_up(line, 1);
4480
4481 if (NIL_P(line)) {
4482 rb_eof_error();
4483 }
4484 return line;
4485}
4486
4487static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4488
4489/*
4490 * call-seq:
4491 * readlines(sep = $/, chomp: false) -> array
4492 * readlines(limit, chomp: false) -> array
4493 * readlines(sep, limit, chomp: false) -> array
4494 *
4495 * Reads and returns all remaining line from the stream;
4496 * does not modify <tt>$_</tt>.
4497 * See {Line IO}[rdoc-ref:IO@Line+IO].
4498 *
4499 * With no arguments given, returns lines
4500 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4501 *
4502 * f = File.new('t.txt')
4503 * f.readlines
4504 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4505 * f.readlines # => []
4506 * f.close
4507 *
4508 * With only string argument +sep+ given,
4509 * returns lines as determined by line separator +sep+,
4510 * or +nil+ if none;
4511 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4512 *
4513 * f = File.new('t.txt')
4514 * f.readlines('li')
4515 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4516 * f.close
4517 *
4518 * The two special values for +sep+ are honored:
4519 *
4520 * f = File.new('t.txt')
4521 * # Get all into one string.
4522 * f.readlines(nil)
4523 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4524 * # Get paragraphs (up to two line separators).
4525 * f.rewind
4526 * f.readlines('')
4527 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4528 * f.close
4529 *
4530 * With only integer argument +limit+ given,
4531 * limits the number of bytes in each line;
4532 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4533 *
4534 * f = File.new('t.txt')
4535 * f.readlines(8)
4536 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4537 * f.close
4538 *
4539 * With arguments +sep+ and +limit+ given,
4540 * combines the two behaviors
4541 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4542 *
4543 * Optional keyword argument +chomp+ specifies whether line separators
4544 * are to be omitted:
4545 *
4546 * f = File.new('t.txt')
4547 * f.readlines(chomp: true)
4548 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4549 * f.close
4550 *
4551 */
4552
4553static VALUE
4554rb_io_readlines(int argc, VALUE *argv, VALUE io)
4555{
4556 struct getline_arg args;
4557
4558 prepare_getline_args(argc, argv, &args, io);
4559 return io_readlines(&args, io);
4560}
4561
4562static VALUE
4563io_readlines(const struct getline_arg *arg, VALUE io)
4564{
4565 VALUE line, ary;
4566
4567 if (arg->limit == 0)
4568 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4569 ary = rb_ary_new();
4570 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4571 rb_ary_push(ary, line);
4572 }
4573 return ary;
4574}
4575
4576/*
4577 * call-seq:
4578 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4579 * each_line(limit, chomp: false) {|line| ... } -> self
4580 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4581 * each_line -> enumerator
4582 *
4583 * Calls the block with each remaining line read from the stream;
4584 * returns +self+.
4585 * Does nothing if already at end-of-stream;
4586 * See {Line IO}[rdoc-ref:IO@Line+IO].
4587 *
4588 * With no arguments given, reads lines
4589 * as determined by line separator <tt>$/</tt>:
4590 *
4591 * f = File.new('t.txt')
4592 * f.each_line {|line| p line }
4593 * f.each_line {|line| fail 'Cannot happen' }
4594 * f.close
4595 *
4596 * Output:
4597 *
4598 * "First line\n"
4599 * "Second line\n"
4600 * "\n"
4601 * "Fourth line\n"
4602 * "Fifth line\n"
4603 *
4604 * With only string argument +sep+ given,
4605 * reads lines as determined by line separator +sep+;
4606 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4607 *
4608 * f = File.new('t.txt')
4609 * f.each_line('li') {|line| p line }
4610 * f.close
4611 *
4612 * Output:
4613 *
4614 * "First li"
4615 * "ne\nSecond li"
4616 * "ne\n\nFourth li"
4617 * "ne\nFifth li"
4618 * "ne\n"
4619 *
4620 * The two special values for +sep+ are honored:
4621 *
4622 * f = File.new('t.txt')
4623 * # Get all into one string.
4624 * f.each_line(nil) {|line| p line }
4625 * f.close
4626 *
4627 * Output:
4628 *
4629 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4630 *
4631 * f.rewind
4632 * # Get paragraphs (up to two line separators).
4633 * f.each_line('') {|line| p line }
4634 *
4635 * Output:
4636 *
4637 * "First line\nSecond line\n\n"
4638 * "Fourth line\nFifth line\n"
4639 *
4640 * With only integer argument +limit+ given,
4641 * limits the number of bytes in each line;
4642 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4643 *
4644 * f = File.new('t.txt')
4645 * f.each_line(8) {|line| p line }
4646 * f.close
4647 *
4648 * Output:
4649 *
4650 * "First li"
4651 * "ne\n"
4652 * "Second l"
4653 * "ine\n"
4654 * "\n"
4655 * "Fourth l"
4656 * "ine\n"
4657 * "Fifth li"
4658 * "ne\n"
4659 *
4660 * With arguments +sep+ and +limit+ given,
4661 * combines the two behaviors
4662 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4663 *
4664 * Optional keyword argument +chomp+ specifies whether line separators
4665 * are to be omitted:
4666 *
4667 * f = File.new('t.txt')
4668 * f.each_line(chomp: true) {|line| p line }
4669 * f.close
4670 *
4671 * Output:
4672 *
4673 * "First line"
4674 * "Second line"
4675 * ""
4676 * "Fourth line"
4677 * "Fifth line"
4678 *
4679 * Returns an Enumerator if no block is given.
4680 */
4681
4682static VALUE
4683rb_io_each_line(int argc, VALUE *argv, VALUE io)
4684{
4685 VALUE str;
4686 struct getline_arg args;
4687
4688 RETURN_ENUMERATOR(io, argc, argv);
4689 prepare_getline_args(argc, argv, &args, io);
4690 if (args.limit == 0)
4691 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4692 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4693 rb_yield(str);
4694 }
4695 return io;
4696}
4697
4698/*
4699 * call-seq:
4700 * each_byte {|byte| ... } -> self
4701 * each_byte -> enumerator
4702 *
4703 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4704 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4705 *
4706 * f = File.new('t.rus')
4707 * a = []
4708 * f.each_byte {|b| a << b }
4709 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4710 * f.close
4711 *
4712 * Returns an Enumerator if no block is given.
4713 *
4714 * Related: IO#each_char, IO#each_codepoint.
4715 *
4716 */
4717
4718static VALUE
4719rb_io_each_byte(VALUE io)
4720{
4721 rb_io_t *fptr;
4722
4723 RETURN_ENUMERATOR(io, 0, 0);
4724 GetOpenFile(io, fptr);
4725
4726 do {
4727 while (fptr->rbuf.len > 0) {
4728 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4729 fptr->rbuf.len--;
4730 rb_yield(INT2FIX(*p & 0xff));
4732 errno = 0;
4733 }
4734 READ_CHECK(fptr);
4735 } while (io_fillbuf(fptr) >= 0);
4736 return io;
4737}
4738
4739static VALUE
4740io_getc(rb_io_t *fptr, rb_encoding *enc)
4741{
4742 int r, n, cr = 0;
4743 VALUE str;
4744
4745 if (NEED_READCONV(fptr)) {
4746 rb_encoding *read_enc = io_read_encoding(fptr);
4747
4748 str = Qnil;
4749 SET_BINARY_MODE(fptr);
4750 make_readconv(fptr, 0);
4751
4752 while (1) {
4753 if (fptr->cbuf.len) {
4754 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4755 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4756 read_enc);
4757 if (!MBCLEN_NEEDMORE_P(r))
4758 break;
4759 if (fptr->cbuf.len == fptr->cbuf.capa) {
4760 rb_raise(rb_eIOError, "too long character");
4761 }
4762 }
4763
4764 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4765 if (fptr->cbuf.len == 0) {
4766 clear_readconv(fptr);
4767 return Qnil;
4768 }
4769 /* return an unit of an incomplete character just before EOF */
4770 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4771 fptr->cbuf.off += 1;
4772 fptr->cbuf.len -= 1;
4773 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4775 return str;
4776 }
4777 }
4778 if (MBCLEN_INVALID_P(r)) {
4779 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4780 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4781 read_enc);
4782 io_shift_cbuf(fptr, r, &str);
4784 }
4785 else {
4786 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4788 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4789 ISASCII(RSTRING_PTR(str)[0])) {
4790 cr = ENC_CODERANGE_7BIT;
4791 }
4792 }
4793 str = io_enc_str(str, fptr);
4794 ENC_CODERANGE_SET(str, cr);
4795 return str;
4796 }
4797
4798 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4799 if (io_fillbuf(fptr) < 0) {
4800 return Qnil;
4801 }
4802 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4803 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4804 fptr->rbuf.off += 1;
4805 fptr->rbuf.len -= 1;
4806 cr = ENC_CODERANGE_7BIT;
4807 }
4808 else {
4809 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4810 if (MBCLEN_CHARFOUND_P(r) &&
4811 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4812 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4813 fptr->rbuf.off += n;
4814 fptr->rbuf.len -= n;
4816 }
4817 else if (MBCLEN_NEEDMORE_P(r)) {
4818 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4819 fptr->rbuf.len = 0;
4820 getc_needmore:
4821 if (io_fillbuf(fptr) != -1) {
4822 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4823 fptr->rbuf.off++;
4824 fptr->rbuf.len--;
4825 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4826 if (MBCLEN_NEEDMORE_P(r)) {
4827 goto getc_needmore;
4828 }
4829 else if (MBCLEN_CHARFOUND_P(r)) {
4831 }
4832 }
4833 }
4834 else {
4835 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4836 fptr->rbuf.off++;
4837 fptr->rbuf.len--;
4838 }
4839 }
4840 if (!cr) cr = ENC_CODERANGE_BROKEN;
4841 str = io_enc_str(str, fptr);
4842 ENC_CODERANGE_SET(str, cr);
4843 return str;
4844}
4845
4846/*
4847 * call-seq:
4848 * each_char {|c| ... } -> self
4849 * each_char -> enumerator
4850 *
4851 * Calls the given block with each character in the stream; returns +self+.
4852 * See {Character IO}[rdoc-ref:IO@Character+IO].
4853 *
4854 * f = File.new('t.rus')
4855 * a = []
4856 * f.each_char {|c| a << c.ord }
4857 * a # => [1090, 1077, 1089, 1090]
4858 * f.close
4859 *
4860 * Returns an Enumerator if no block is given.
4861 *
4862 * Related: IO#each_byte, IO#each_codepoint.
4863 *
4864 */
4865
4866static VALUE
4867rb_io_each_char(VALUE io)
4868{
4869 rb_io_t *fptr;
4870 rb_encoding *enc;
4871 VALUE c;
4872
4873 RETURN_ENUMERATOR(io, 0, 0);
4874 GetOpenFile(io, fptr);
4876
4877 enc = io_input_encoding(fptr);
4878 READ_CHECK(fptr);
4879 while (!NIL_P(c = io_getc(fptr, enc))) {
4880 rb_yield(c);
4881 }
4882 return io;
4883}
4884
4885/*
4886 * call-seq:
4887 * each_codepoint {|c| ... } -> self
4888 * each_codepoint -> enumerator
4889 *
4890 * Calls the given block with each codepoint in the stream; returns +self+:
4891 *
4892 * f = File.new('t.rus')
4893 * a = []
4894 * f.each_codepoint {|c| a << c }
4895 * a # => [1090, 1077, 1089, 1090]
4896 * f.close
4897 *
4898 * Returns an Enumerator if no block is given.
4899 *
4900 * Related: IO#each_byte, IO#each_char.
4901 *
4902 */
4903
4904static VALUE
4905rb_io_each_codepoint(VALUE io)
4906{
4907 rb_io_t *fptr;
4908 rb_encoding *enc;
4909 unsigned int c;
4910 int r, n;
4911
4912 RETURN_ENUMERATOR(io, 0, 0);
4913 GetOpenFile(io, fptr);
4915
4916 READ_CHECK(fptr);
4917 enc = io_read_encoding(fptr);
4918 if (NEED_READCONV(fptr)) {
4919 SET_BINARY_MODE(fptr);
4920 r = 1; /* no invalid char yet */
4921 for (;;) {
4922 make_readconv(fptr, 0);
4923 for (;;) {
4924 if (fptr->cbuf.len) {
4925 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4926 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4927 enc);
4928 if (!MBCLEN_NEEDMORE_P(r))
4929 break;
4930 if (fptr->cbuf.len == fptr->cbuf.capa) {
4931 rb_raise(rb_eIOError, "too long character");
4932 }
4933 }
4934 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4935 clear_readconv(fptr);
4936 if (!MBCLEN_CHARFOUND_P(r)) {
4937 goto invalid;
4938 }
4939 return io;
4940 }
4941 }
4942 if (MBCLEN_INVALID_P(r)) {
4943 goto invalid;
4944 }
4945 n = MBCLEN_CHARFOUND_LEN(r);
4946 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4947 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4948 enc);
4949 fptr->cbuf.off += n;
4950 fptr->cbuf.len -= n;
4951 rb_yield(UINT2NUM(c));
4953 }
4954 }
4955 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4956 while (io_fillbuf(fptr) >= 0) {
4957 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4958 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4959 if (MBCLEN_CHARFOUND_P(r) &&
4960 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4961 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4962 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4963 fptr->rbuf.off += n;
4964 fptr->rbuf.len -= n;
4965 rb_yield(UINT2NUM(c));
4966 }
4967 else if (MBCLEN_INVALID_P(r)) {
4968 goto invalid;
4969 }
4970 else if (MBCLEN_NEEDMORE_P(r)) {
4971 char cbuf[8], *p = cbuf;
4972 int more = MBCLEN_NEEDMORE_LEN(r);
4973 if (more > numberof(cbuf)) goto invalid;
4974 more += n = fptr->rbuf.len;
4975 if (more > numberof(cbuf)) goto invalid;
4976 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4977 (p += n, (more -= n) > 0)) {
4978 if (io_fillbuf(fptr) < 0) goto invalid;
4979 if ((n = fptr->rbuf.len) > more) n = more;
4980 }
4981 r = rb_enc_precise_mbclen(cbuf, p, enc);
4982 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4983 c = rb_enc_codepoint(cbuf, p, enc);
4984 rb_yield(UINT2NUM(c));
4985 }
4986 else {
4987 continue;
4988 }
4990 }
4991 return io;
4992
4993 invalid:
4994 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4996}
4997
4998/*
4999 * call-seq:
5000 * getc -> character or nil
5001 *
5002 * Reads and returns the next 1-character string from the stream;
5003 * returns +nil+ if already at end-of-stream.
5004 * See {Character IO}[rdoc-ref:IO@Character+IO].
5005 *
5006 * f = File.open('t.txt')
5007 * f.getc # => "F"
5008 * f.close
5009 * f = File.open('t.rus')
5010 * f.getc.ord # => 1090
5011 * f.close
5012 *
5013 * Related: IO#readchar (may raise EOFError).
5014 *
5015 */
5016
5017static VALUE
5018rb_io_getc(VALUE io)
5019{
5020 rb_io_t *fptr;
5021 rb_encoding *enc;
5022
5023 GetOpenFile(io, fptr);
5025
5026 enc = io_input_encoding(fptr);
5027 READ_CHECK(fptr);
5028 return io_getc(fptr, enc);
5029}
5030
5031/*
5032 * call-seq:
5033 * readchar -> string
5034 *
5035 * Reads and returns the next 1-character string from the stream;
5036 * raises EOFError if already at end-of-stream.
5037 * See {Character IO}[rdoc-ref:IO@Character+IO].
5038 *
5039 * f = File.open('t.txt')
5040 * f.readchar # => "F"
5041 * f.close
5042 * f = File.open('t.rus')
5043 * f.readchar.ord # => 1090
5044 * f.close
5045 *
5046 * Related: IO#getc (will not raise EOFError).
5047 *
5048 */
5049
5050static VALUE
5051rb_io_readchar(VALUE io)
5052{
5053 VALUE c = rb_io_getc(io);
5054
5055 if (NIL_P(c)) {
5056 rb_eof_error();
5057 }
5058 return c;
5059}
5060
5061/*
5062 * call-seq:
5063 * getbyte -> integer or nil
5064 *
5065 * Reads and returns the next byte (in range 0..255) from the stream;
5066 * returns +nil+ if already at end-of-stream.
5067 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5068 *
5069 * f = File.open('t.txt')
5070 * f.getbyte # => 70
5071 * f.close
5072 * f = File.open('t.rus')
5073 * f.getbyte # => 209
5074 * f.close
5075 *
5076 * Related: IO#readbyte (may raise EOFError).
5077 */
5078
5079VALUE
5081{
5082 rb_io_t *fptr;
5083 int c;
5084
5085 GetOpenFile(io, fptr);
5087 READ_CHECK(fptr);
5088 VALUE r_stdout = rb_ractor_stdout();
5089 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5090 rb_io_t *ofp;
5091 GetOpenFile(r_stdout, ofp);
5092 if (ofp->mode & FMODE_TTY) {
5093 rb_io_flush(r_stdout);
5094 }
5095 }
5096 if (io_fillbuf(fptr) < 0) {
5097 return Qnil;
5098 }
5099 fptr->rbuf.off++;
5100 fptr->rbuf.len--;
5101 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5102 return INT2FIX(c & 0xff);
5103}
5104
5105/*
5106 * call-seq:
5107 * readbyte -> integer
5108 *
5109 * Reads and returns the next byte (in range 0..255) from the stream;
5110 * raises EOFError if already at end-of-stream.
5111 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5112 *
5113 * f = File.open('t.txt')
5114 * f.readbyte # => 70
5115 * f.close
5116 * f = File.open('t.rus')
5117 * f.readbyte # => 209
5118 * f.close
5119 *
5120 * Related: IO#getbyte (will not raise EOFError).
5121 *
5122 */
5123
5124static VALUE
5125rb_io_readbyte(VALUE io)
5126{
5127 VALUE c = rb_io_getbyte(io);
5128
5129 if (NIL_P(c)) {
5130 rb_eof_error();
5131 }
5132 return c;
5133}
5134
5135/*
5136 * call-seq:
5137 * ungetbyte(integer) -> nil
5138 * ungetbyte(string) -> nil
5139 *
5140 * Pushes back ("unshifts") the given data onto the stream's buffer,
5141 * placing the data so that it is next to be read; returns +nil+.
5142 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5143 *
5144 * Note that:
5145 *
5146 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5147 * - Calling #rewind on the stream discards the pushed-back data.
5148 *
5149 * When argument +integer+ is given, uses only its low-order byte:
5150 *
5151 * File.write('t.tmp', '012')
5152 * f = File.open('t.tmp')
5153 * f.ungetbyte(0x41) # => nil
5154 * f.read # => "A012"
5155 * f.rewind
5156 * f.ungetbyte(0x4243) # => nil
5157 * f.read # => "C012"
5158 * f.close
5159 *
5160 * When argument +string+ is given, uses all bytes:
5161 *
5162 * File.write('t.tmp', '012')
5163 * f = File.open('t.tmp')
5164 * f.ungetbyte('A') # => nil
5165 * f.read # => "A012"
5166 * f.rewind
5167 * f.ungetbyte('BCDE') # => nil
5168 * f.read # => "BCDE012"
5169 * f.close
5170 *
5171 */
5172
5173VALUE
5175{
5176 rb_io_t *fptr;
5177
5178 GetOpenFile(io, fptr);
5180 switch (TYPE(b)) {
5181 case T_NIL:
5182 return Qnil;
5183 case T_FIXNUM:
5184 case T_BIGNUM: ;
5185 VALUE v = rb_int_modulo(b, INT2FIX(256));
5186 unsigned char c = NUM2INT(v) & 0xFF;
5187 b = rb_str_new((const char *)&c, 1);
5188 break;
5189 default:
5190 StringValue(b);
5191 }
5192 io_ungetbyte(b, fptr);
5193 return Qnil;
5194}
5195
5196/*
5197 * call-seq:
5198 * ungetc(integer) -> nil
5199 * ungetc(string) -> nil
5200 *
5201 * Pushes back ("unshifts") the given data onto the stream's buffer,
5202 * placing the data so that it is next to be read; returns +nil+.
5203 * See {Character IO}[rdoc-ref:IO@Character+IO].
5204 *
5205 * Note that:
5206 *
5207 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5208 * - Calling #rewind on the stream discards the pushed-back data.
5209 *
5210 * When argument +integer+ is given, interprets the integer as a character:
5211 *
5212 * File.write('t.tmp', '012')
5213 * f = File.open('t.tmp')
5214 * f.ungetc(0x41) # => nil
5215 * f.read # => "A012"
5216 * f.rewind
5217 * f.ungetc(0x0442) # => nil
5218 * f.getc.ord # => 1090
5219 * f.close
5220 *
5221 * When argument +string+ is given, uses all characters:
5222 *
5223 * File.write('t.tmp', '012')
5224 * f = File.open('t.tmp')
5225 * f.ungetc('A') # => nil
5226 * f.read # => "A012"
5227 * f.rewind
5228 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5229 * f.getc.ord # => 1090
5230 * f.getc.ord # => 1077
5231 * f.getc.ord # => 1089
5232 * f.getc.ord # => 1090
5233 * f.close
5234 *
5235 */
5236
5237VALUE
5239{
5240 rb_io_t *fptr;
5241 long len;
5242
5243 GetOpenFile(io, fptr);
5245 if (FIXNUM_P(c)) {
5246 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5247 }
5248 else if (RB_BIGNUM_TYPE_P(c)) {
5249 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5250 }
5251 else {
5252 StringValue(c);
5253 }
5254 if (NEED_READCONV(fptr)) {
5255 SET_BINARY_MODE(fptr);
5256 len = RSTRING_LEN(c);
5257#if SIZEOF_LONG > SIZEOF_INT
5258 if (len > INT_MAX)
5259 rb_raise(rb_eIOError, "ungetc failed");
5260#endif
5261 make_readconv(fptr, (int)len);
5262 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5263 rb_raise(rb_eIOError, "ungetc failed");
5264 if (fptr->cbuf.off < len) {
5265 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5266 fptr->cbuf.ptr+fptr->cbuf.off,
5267 char, fptr->cbuf.len);
5268 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5269 }
5270 fptr->cbuf.off -= (int)len;
5271 fptr->cbuf.len += (int)len;
5272 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5273 }
5274 else {
5275 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5276 io_ungetbyte(c, fptr);
5277 }
5278 return Qnil;
5279}
5280
5281/*
5282 * call-seq:
5283 * isatty -> true or false
5284 *
5285 * Returns +true+ if the stream is associated with a terminal device (tty),
5286 * +false+ otherwise:
5287 *
5288 * f = File.new('t.txt').isatty #=> false
5289 * f.close
5290 * f = File.new('/dev/tty').isatty #=> true
5291 * f.close
5292 *
5293 */
5294
5295static VALUE
5296rb_io_isatty(VALUE io)
5297{
5298 rb_io_t *fptr;
5299
5300 GetOpenFile(io, fptr);
5301 return RBOOL(isatty(fptr->fd) != 0);
5302}
5303
5304#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5305/*
5306 * call-seq:
5307 * close_on_exec? -> true or false
5308 *
5309 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5310 *
5311 * f = File.open('t.txt')
5312 * f.close_on_exec? # => true
5313 * f.close_on_exec = false
5314 * f.close_on_exec? # => false
5315 * f.close
5316 *
5317 */
5318
5319static VALUE
5320rb_io_close_on_exec_p(VALUE io)
5321{
5322 rb_io_t *fptr;
5323 VALUE write_io;
5324 int fd, ret;
5325
5326 write_io = GetWriteIO(io);
5327 if (io != write_io) {
5328 GetOpenFile(write_io, fptr);
5329 if (fptr && 0 <= (fd = fptr->fd)) {
5330 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5331 if (!(ret & FD_CLOEXEC)) return Qfalse;
5332 }
5333 }
5334
5335 GetOpenFile(io, fptr);
5336 if (fptr && 0 <= (fd = fptr->fd)) {
5337 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5338 if (!(ret & FD_CLOEXEC)) return Qfalse;
5339 }
5340 return Qtrue;
5341}
5342#else
5343#define rb_io_close_on_exec_p rb_f_notimplement
5344#endif
5345
5346#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5347/*
5348 * call-seq:
5349 * self.close_on_exec = bool -> true or false
5350 *
5351 * Sets a close-on-exec flag.
5352 *
5353 * f = File.open(File::NULL)
5354 * f.close_on_exec = true
5355 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5356 * f.closed? #=> false
5357 *
5358 * Ruby sets close-on-exec flags of all file descriptors by default
5359 * since Ruby 2.0.0.
5360 * So you don't need to set by yourself.
5361 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5362 * if another thread use fork() and exec() (via system() method for example).
5363 * If you really needs file descriptor inheritance to child process,
5364 * use spawn()'s argument such as fd=>fd.
5365 */
5366
5367static VALUE
5368rb_io_set_close_on_exec(VALUE io, VALUE arg)
5369{
5370 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5371 rb_io_t *fptr;
5372 VALUE write_io;
5373 int fd, ret;
5374
5375 write_io = GetWriteIO(io);
5376 if (io != write_io) {
5377 GetOpenFile(write_io, fptr);
5378 if (fptr && 0 <= (fd = fptr->fd)) {
5379 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5380 if ((ret & FD_CLOEXEC) != flag) {
5381 ret = (ret & ~FD_CLOEXEC) | flag;
5382 ret = fcntl(fd, F_SETFD, ret);
5383 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5384 }
5385 }
5386
5387 }
5388
5389 GetOpenFile(io, fptr);
5390 if (fptr && 0 <= (fd = fptr->fd)) {
5391 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5392 if ((ret & FD_CLOEXEC) != flag) {
5393 ret = (ret & ~FD_CLOEXEC) | flag;
5394 ret = fcntl(fd, F_SETFD, ret);
5395 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5396 }
5397 }
5398 return Qnil;
5399}
5400#else
5401#define rb_io_set_close_on_exec rb_f_notimplement
5402#endif
5403
5404#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5405#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5406
5407static VALUE
5408finish_writeconv(rb_io_t *fptr, int noalloc)
5409{
5410 unsigned char *ds, *dp, *de;
5412
5413 if (!fptr->wbuf.ptr) {
5414 unsigned char buf[1024];
5415
5417 while (res == econv_destination_buffer_full) {
5418 ds = dp = buf;
5419 de = buf + sizeof(buf);
5420 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5421 while (dp-ds) {
5422 size_t remaining = dp-ds;
5423 long result = rb_io_write_memory(fptr, ds, remaining);
5424
5425 if (result > 0) {
5426 ds += result;
5427 if ((size_t)result == remaining) break;
5428 }
5429 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5430 if (fptr->fd < 0)
5431 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5432 }
5433 else {
5434 return noalloc ? Qtrue : INT2NUM(errno);
5435 }
5436 }
5437 if (res == econv_invalid_byte_sequence ||
5438 res == econv_incomplete_input ||
5440 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5441 }
5442 }
5443
5444 return Qnil;
5445 }
5446
5448 while (res == econv_destination_buffer_full) {
5449 if (fptr->wbuf.len == fptr->wbuf.capa) {
5450 if (io_fflush(fptr) < 0) {
5451 return noalloc ? Qtrue : INT2NUM(errno);
5452 }
5453 }
5454
5455 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5456 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5457 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5458 fptr->wbuf.len += (int)(dp - ds);
5459 if (res == econv_invalid_byte_sequence ||
5460 res == econv_incomplete_input ||
5462 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5463 }
5464 }
5465 return Qnil;
5466}
5467
5469 rb_io_t *fptr;
5470 int noalloc;
5471};
5472
5473static VALUE
5474finish_writeconv_sync(VALUE arg)
5475{
5476 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5477 return finish_writeconv(p->fptr, p->noalloc);
5478}
5479
5480static void*
5481nogvl_close(void *ptr)
5482{
5483 int *fd = ptr;
5484
5485 return (void*)(intptr_t)close(*fd);
5486}
5487
5488static int
5489maygvl_close(int fd, int keepgvl)
5490{
5491 if (keepgvl)
5492 return close(fd);
5493
5494 /*
5495 * close() may block for certain file types (NFS, SO_LINGER sockets,
5496 * inotify), so let other threads run.
5497 */
5498 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5499}
5500
5501static void*
5502nogvl_fclose(void *ptr)
5503{
5504 FILE *file = ptr;
5505
5506 return (void*)(intptr_t)fclose(file);
5507}
5508
5509static int
5510maygvl_fclose(FILE *file, int keepgvl)
5511{
5512 if (keepgvl)
5513 return fclose(file);
5514
5515 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5516}
5517
5518static void free_io_buffer(rb_io_buffer_t *buf);
5519
5520static void
5521fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5522{
5523 VALUE error = Qnil;
5524 int fd = fptr->fd;
5525 FILE *stdio_file = fptr->stdio_file;
5526 int mode = fptr->mode;
5527
5528 if (fptr->writeconv) {
5529 if (!NIL_P(fptr->write_lock) && !noraise) {
5530 struct finish_writeconv_arg arg;
5531 arg.fptr = fptr;
5532 arg.noalloc = noraise;
5533 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5534 }
5535 else {
5536 error = finish_writeconv(fptr, noraise);
5537 }
5538 }
5539 if (fptr->wbuf.len) {
5540 if (noraise) {
5541 io_flush_buffer_sync(fptr);
5542 }
5543 else {
5544 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5545 error = INT2NUM(errno);
5546 }
5547 }
5548 }
5549
5550 int done = 0;
5551
5552 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5553 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5554 done = 1;
5555 }
5556
5557 fptr->fd = -1;
5558 fptr->stdio_file = 0;
5560
5561 // Wait for blocking operations to ensure they do not hit EBADF:
5562 rb_thread_io_close_wait(fptr);
5563
5564 if (!done && stdio_file) {
5565 // stdio_file is deallocated anyway even if fclose failed.
5566 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5567 if (!noraise) {
5568 error = INT2NUM(errno);
5569 }
5570 }
5571
5572 done = 1;
5573 }
5574
5575 VALUE scheduler = rb_fiber_scheduler_current();
5576 if (!done && fd >= 0 && scheduler != Qnil) {
5577 VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
5578
5579 if (!UNDEF_P(result)) {
5580 done = RTEST(result);
5581 }
5582 }
5583
5584 if (!done && fd >= 0) {
5585 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5586 // We assumes it is closed.
5587
5588 keepgvl |= !(mode & FMODE_WRITABLE);
5589 keepgvl |= noraise;
5590 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5591 if (!noraise) {
5592 error = INT2NUM(errno);
5593 }
5594 }
5595
5596 done = 1;
5597 }
5598
5599 if (!NIL_P(error) && !noraise) {
5600 if (RB_INTEGER_TYPE_P(error))
5601 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5602 else
5603 rb_exc_raise(error);
5604 }
5605}
5606
5607static void
5608fptr_finalize(rb_io_t *fptr, int noraise)
5609{
5610 fptr_finalize_flush(fptr, noraise, FALSE);
5611 free_io_buffer(&fptr->rbuf);
5612 free_io_buffer(&fptr->wbuf);
5613 clear_codeconv(fptr);
5614}
5615
5616static void
5617rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5618{
5619 if (fptr->finalize) {
5620 (*fptr->finalize)(fptr, noraise);
5621 }
5622 else {
5623 fptr_finalize(fptr, noraise);
5624 }
5625}
5626
5627static void
5628free_io_buffer(rb_io_buffer_t *buf)
5629{
5630 if (buf->ptr) {
5631 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5632 buf->ptr = NULL;
5633 }
5634}
5635
5636static void
5637clear_readconv(rb_io_t *fptr)
5638{
5639 if (fptr->readconv) {
5640 rb_econv_close(fptr->readconv);
5641 fptr->readconv = NULL;
5642 }
5643 free_io_buffer(&fptr->cbuf);
5644}
5645
5646static void
5647clear_writeconv(rb_io_t *fptr)
5648{
5649 if (fptr->writeconv) {
5651 fptr->writeconv = NULL;
5652 }
5653 fptr->writeconv_initialized = 0;
5654}
5655
5656static void
5657clear_codeconv(rb_io_t *fptr)
5658{
5659 clear_readconv(fptr);
5660 clear_writeconv(fptr);
5661}
5662
5663static void
5664rb_io_fptr_cleanup_all(rb_io_t *fptr)
5665{
5666 fptr->pathv = Qnil;
5667 if (0 <= fptr->fd)
5668 rb_io_fptr_cleanup(fptr, TRUE);
5669 fptr->write_lock = Qnil;
5670 free_io_buffer(&fptr->rbuf);
5671 free_io_buffer(&fptr->wbuf);
5672 clear_codeconv(fptr);
5673}
5674
5675int
5677{
5678 if (!io) return 0;
5679 rb_io_fptr_cleanup_all(io);
5680 free(io);
5681
5682 return 1;
5683}
5684
5685size_t
5686rb_io_memsize(const rb_io_t *io)
5687{
5688 size_t size = sizeof(rb_io_t);
5689 size += io->rbuf.capa;
5690 size += io->wbuf.capa;
5691 size += io->cbuf.capa;
5692 if (io->readconv) size += rb_econv_memsize(io->readconv);
5693 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5694
5695 struct rb_io_blocking_operation *blocking_operation = 0;
5696
5697 // Validate the fork generation of the IO object. If the IO object fork generation is different, the list of blocking operations is not valid memory. See `rb_io_blocking_operations` for the exact semantics.
5698 rb_serial_t fork_generation = GET_VM()->fork_gen;
5699 if (io->fork_generation == fork_generation) {
5700 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5701 size += sizeof(struct rb_io_blocking_operation);
5702 }
5703 }
5704
5705 return size;
5706}
5707
5708#ifdef _WIN32
5709/* keep GVL while closing to prevent crash on Windows */
5710# define KEEPGVL TRUE
5711#else
5712# define KEEPGVL FALSE
5713#endif
5714
5715static rb_io_t *
5716io_close_fptr(VALUE io)
5717{
5718 rb_io_t *fptr;
5719 VALUE write_io;
5720 rb_io_t *write_fptr;
5721
5722 write_io = GetWriteIO(io);
5723 if (io != write_io) {
5724 write_fptr = RFILE(write_io)->fptr;
5725 if (write_fptr && 0 <= write_fptr->fd) {
5726 rb_io_fptr_cleanup(write_fptr, TRUE);
5727 }
5728 }
5729
5730 fptr = RFILE(io)->fptr;
5731 if (!fptr) return 0;
5732 if (fptr->fd < 0) return 0;
5733
5734 // This guards against multiple threads closing the same IO object:
5735 if (rb_thread_io_close_interrupt(fptr)) {
5736 /* calls close(fptr->fd): */
5737 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5738 }
5739
5740 rb_io_fptr_cleanup(fptr, FALSE);
5741 return fptr;
5742}
5743
5744static void
5745fptr_waitpid(rb_io_t *fptr, int nohang)
5746{
5747 int status;
5748 if (fptr->pid) {
5749 rb_last_status_clear();
5750 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5751 fptr->pid = 0;
5752 }
5753}
5754
5755VALUE
5757{
5758 rb_io_t *fptr = io_close_fptr(io);
5759 if (fptr) fptr_waitpid(fptr, 0);
5760 return Qnil;
5761}
5762
5763/*
5764 * call-seq:
5765 * close -> nil
5766 *
5767 * Closes the stream for both reading and writing
5768 * if open for either or both; returns +nil+.
5769 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5770 *
5771 * If the stream is open for writing, flushes any buffered writes
5772 * to the operating system before closing.
5773 *
5774 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5775 * (child exit status).
5776 *
5777 * It is not an error to close an IO object that has already been closed.
5778 * It just returns nil.
5779 *
5780 * Example:
5781 *
5782 * IO.popen('ruby', 'r+') do |pipe|
5783 * puts pipe.closed?
5784 * pipe.close
5785 * puts $?
5786 * puts pipe.closed?
5787 * end
5788 *
5789 * Output:
5790 *
5791 * false
5792 * pid 13760 exit 0
5793 * true
5794 *
5795 * Related: IO#close_read, IO#close_write, IO#closed?.
5796 */
5797
5798static VALUE
5799rb_io_close_m(VALUE io)
5800{
5801 rb_io_t *fptr = rb_io_get_fptr(io);
5802 if (fptr->fd < 0) {
5803 return Qnil;
5804 }
5805 rb_io_close(io);
5806 return Qnil;
5807}
5808
5809static VALUE
5810io_call_close(VALUE io)
5811{
5812 rb_check_funcall(io, rb_intern("close"), 0, 0);
5813 return io;
5814}
5815
5816static VALUE
5817ignore_closed_stream(VALUE io, VALUE exc)
5818{
5819 enum {mesg_len = sizeof(closed_stream)-1};
5820 VALUE mesg = rb_attr_get(exc, idMesg);
5821 if (!RB_TYPE_P(mesg, T_STRING) ||
5822 RSTRING_LEN(mesg) != mesg_len ||
5823 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5824 rb_exc_raise(exc);
5825 }
5826 return io;
5827}
5828
5829static VALUE
5830io_close(VALUE io)
5831{
5832 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5833 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5834 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5835 rb_eIOError, (VALUE)0);
5836 return io;
5837}
5838
5839/*
5840 * call-seq:
5841 * closed? -> true or false
5842 *
5843 * Returns +true+ if the stream is closed for both reading and writing,
5844 * +false+ otherwise.
5845 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5846 *
5847 * IO.popen('ruby', 'r+') do |pipe|
5848 * puts pipe.closed?
5849 * pipe.close_read
5850 * puts pipe.closed?
5851 * pipe.close_write
5852 * puts pipe.closed?
5853 * end
5854 *
5855 * Output:
5856 *
5857 * false
5858 * false
5859 * true
5860 *
5861 * Related: IO#close_read, IO#close_write, IO#close.
5862 */
5863VALUE
5865{
5866 rb_io_t *fptr;
5867 VALUE write_io;
5868 rb_io_t *write_fptr;
5869
5870 write_io = GetWriteIO(io);
5871 if (io != write_io) {
5872 write_fptr = RFILE(write_io)->fptr;
5873 if (write_fptr && 0 <= write_fptr->fd) {
5874 return Qfalse;
5875 }
5876 }
5877
5878 fptr = rb_io_get_fptr(io);
5879 return RBOOL(0 > fptr->fd);
5880}
5881
5882/*
5883 * call-seq:
5884 * close_read -> nil
5885 *
5886 * Closes the stream for reading if open for reading;
5887 * returns +nil+.
5888 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5889 *
5890 * If the stream was opened by IO.popen and is also closed for writing,
5891 * sets global variable <tt>$?</tt> (child exit status).
5892 *
5893 * Example:
5894 *
5895 * IO.popen('ruby', 'r+') do |pipe|
5896 * puts pipe.closed?
5897 * pipe.close_write
5898 * puts pipe.closed?
5899 * pipe.close_read
5900 * puts $?
5901 * puts pipe.closed?
5902 * end
5903 *
5904 * Output:
5905 *
5906 * false
5907 * false
5908 * pid 14748 exit 0
5909 * true
5910 *
5911 * Related: IO#close, IO#close_write, IO#closed?.
5912 */
5913
5914static VALUE
5915rb_io_close_read(VALUE io)
5916{
5917 rb_io_t *fptr;
5918 VALUE write_io;
5919
5920 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5921 if (fptr->fd < 0) return Qnil;
5922 if (is_socket(fptr->fd, fptr->pathv)) {
5923#ifndef SHUT_RD
5924# define SHUT_RD 0
5925#endif
5926 if (shutdown(fptr->fd, SHUT_RD) < 0)
5927 rb_sys_fail_path(fptr->pathv);
5928 fptr->mode &= ~FMODE_READABLE;
5929 if (!(fptr->mode & FMODE_WRITABLE))
5930 return rb_io_close(io);
5931 return Qnil;
5932 }
5933
5934 write_io = GetWriteIO(io);
5935 if (io != write_io) {
5936 rb_io_t *wfptr;
5937 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5938 wfptr->pid = fptr->pid;
5939 fptr->pid = 0;
5940 RFILE(io)->fptr = wfptr;
5941 /* bind to write_io temporarily to get rid of memory/fd leak */
5942 fptr->tied_io_for_writing = 0;
5943 RFILE(write_io)->fptr = fptr;
5944 rb_io_fptr_cleanup(fptr, FALSE);
5945 /* should not finalize fptr because another thread may be reading it */
5946 return Qnil;
5947 }
5948
5949 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5950 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5951 }
5952 return rb_io_close(io);
5953}
5954
5955/*
5956 * call-seq:
5957 * close_write -> nil
5958 *
5959 * Closes the stream for writing if open for writing;
5960 * returns +nil+.
5961 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5962 *
5963 * Flushes any buffered writes to the operating system before closing.
5964 *
5965 * If the stream was opened by IO.popen and is also closed for reading,
5966 * sets global variable <tt>$?</tt> (child exit status).
5967 *
5968 * IO.popen('ruby', 'r+') do |pipe|
5969 * puts pipe.closed?
5970 * pipe.close_read
5971 * puts pipe.closed?
5972 * pipe.close_write
5973 * puts $?
5974 * puts pipe.closed?
5975 * end
5976 *
5977 * Output:
5978 *
5979 * false
5980 * false
5981 * pid 15044 exit 0
5982 * true
5983 *
5984 * Related: IO#close, IO#close_read, IO#closed?.
5985 */
5986
5987static VALUE
5988rb_io_close_write(VALUE io)
5989{
5990 rb_io_t *fptr;
5991 VALUE write_io;
5992
5993 write_io = GetWriteIO(io);
5994 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5995 if (fptr->fd < 0) return Qnil;
5996 if (is_socket(fptr->fd, fptr->pathv)) {
5997#ifndef SHUT_WR
5998# define SHUT_WR 1
5999#endif
6000 if (shutdown(fptr->fd, SHUT_WR) < 0)
6001 rb_sys_fail_path(fptr->pathv);
6002 fptr->mode &= ~FMODE_WRITABLE;
6003 if (!(fptr->mode & FMODE_READABLE))
6004 return rb_io_close(write_io);
6005 return Qnil;
6006 }
6007
6008 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6009 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6010 }
6011
6012 if (io != write_io) {
6013 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6014 fptr->tied_io_for_writing = 0;
6015 }
6016 rb_io_close(write_io);
6017 return Qnil;
6018}
6019
6020/*
6021 * call-seq:
6022 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6023 *
6024 * Behaves like IO#seek, except that it:
6025 *
6026 * - Uses low-level system functions.
6027 * - Returns the new position.
6028 *
6029 */
6030
6031static VALUE
6032rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6033{
6034 VALUE offset, ptrname;
6035 int whence = SEEK_SET;
6036 rb_io_t *fptr;
6037 rb_off_t pos;
6038
6039 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6040 whence = interpret_seek_whence(ptrname);
6041 }
6042 pos = NUM2OFFT(offset);
6043 GetOpenFile(io, fptr);
6044 if ((fptr->mode & FMODE_READABLE) &&
6045 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6046 rb_raise(rb_eIOError, "sysseek for buffered IO");
6047 }
6048 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6049 rb_warn("sysseek for buffered IO");
6050 }
6051 errno = 0;
6052 pos = lseek(fptr->fd, pos, whence);
6053 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6054
6055 return OFFT2NUM(pos);
6056}
6057
6058/*
6059 * call-seq:
6060 * syswrite(object) -> integer
6061 *
6062 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6063 * returns the number bytes written.
6064 * If +object+ is not a string is converted via method to_s:
6065 *
6066 * f = File.new('t.tmp', 'w')
6067 * f.syswrite('foo') # => 3
6068 * f.syswrite(30) # => 2
6069 * f.syswrite(:foo) # => 3
6070 * f.close
6071 *
6072 * This methods should not be used with other stream-writer methods.
6073 *
6074 */
6075
6076static VALUE
6077rb_io_syswrite(VALUE io, VALUE str)
6078{
6079 VALUE tmp;
6080 rb_io_t *fptr;
6081 long n, len;
6082 const char *ptr;
6083
6084 if (!RB_TYPE_P(str, T_STRING))
6085 str = rb_obj_as_string(str);
6086
6087 io = GetWriteIO(io);
6088 GetOpenFile(io, fptr);
6090
6091 if (fptr->wbuf.len) {
6092 rb_warn("syswrite for buffered IO");
6093 }
6094
6095 tmp = rb_str_tmp_frozen_acquire(str);
6096 RSTRING_GETMEM(tmp, ptr, len);
6097 n = rb_io_write_memory(fptr, ptr, len);
6098 if (n < 0) rb_sys_fail_path(fptr->pathv);
6099 rb_str_tmp_frozen_release(str, tmp);
6100
6101 return LONG2FIX(n);
6102}
6103
6104/*
6105 * call-seq:
6106 * sysread(maxlen) -> string
6107 * sysread(maxlen, out_string) -> string
6108 *
6109 * Behaves like IO#readpartial, except that it uses low-level system functions.
6110 *
6111 * This method should not be used with other stream-reader methods.
6112 *
6113 */
6114
6115static VALUE
6116rb_io_sysread(int argc, VALUE *argv, VALUE io)
6117{
6118 VALUE len, str;
6119 rb_io_t *fptr;
6120 long n, ilen;
6121 struct io_internal_read_struct iis;
6122 int shrinkable;
6123
6124 rb_scan_args(argc, argv, "11", &len, &str);
6125 ilen = NUM2LONG(len);
6126
6127 shrinkable = io_setstrbuf(&str, ilen);
6128 if (ilen == 0) return str;
6129
6130 GetOpenFile(io, fptr);
6132
6133 if (READ_DATA_BUFFERED(fptr)) {
6134 rb_raise(rb_eIOError, "sysread for buffered IO");
6135 }
6136
6137 rb_io_check_closed(fptr);
6138
6139 io_setstrbuf(&str, ilen);
6140 iis.th = rb_thread_current();
6141 iis.fptr = fptr;
6142 iis.nonblock = 0;
6143 iis.fd = fptr->fd;
6144 iis.buf = RSTRING_PTR(str);
6145 iis.capa = ilen;
6146 iis.timeout = NULL;
6147 n = io_read_memory_locktmp(str, &iis);
6148
6149 if (n < 0) {
6150 rb_sys_fail_path(fptr->pathv);
6151 }
6152
6153 io_set_read_length(str, n, shrinkable);
6154
6155 if (n == 0 && ilen > 0) {
6156 rb_eof_error();
6157 }
6158
6159 return str;
6160}
6161
6163 struct rb_io *io;
6164 int fd;
6165 void *buf;
6166 size_t count;
6167 rb_off_t offset;
6168};
6169
6170static VALUE
6171internal_pread_func(void *_arg)
6172{
6173 struct prdwr_internal_arg *arg = _arg;
6174
6175 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6176}
6177
6178static VALUE
6179pread_internal_call(VALUE _arg)
6180{
6181 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6182
6183 VALUE scheduler = rb_fiber_scheduler_current();
6184 if (scheduler != Qnil) {
6185 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6186
6187 if (!UNDEF_P(result)) {
6189 }
6190 }
6191
6192 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6193}
6194
6195/*
6196 * call-seq:
6197 * pread(maxlen, offset) -> string
6198 * pread(maxlen, offset, out_string) -> string
6199 *
6200 * Behaves like IO#readpartial, except that it:
6201 *
6202 * - Reads at the given +offset+ (in bytes).
6203 * - Disregards, and does not modify, the stream's position
6204 * (see {Position}[rdoc-ref:IO@Position]).
6205 * - Bypasses any user space buffering in the stream.
6206 *
6207 * Because this method does not disturb the stream's state
6208 * (its position, in particular), +pread+ allows multiple threads and processes
6209 * to use the same \IO object for reading at various offsets.
6210 *
6211 * f = File.open('t.txt')
6212 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6213 * f.pos # => 52
6214 * # Read 12 bytes at offset 0.
6215 * f.pread(12, 0) # => "First line\n"
6216 * # Read 9 bytes at offset 8.
6217 * f.pread(9, 8) # => "ne\nSecon"
6218 * f.close
6219 *
6220 * Not available on some platforms.
6221 *
6222 */
6223static VALUE
6224rb_io_pread(int argc, VALUE *argv, VALUE io)
6225{
6226 VALUE len, offset, str;
6227 rb_io_t *fptr;
6228 ssize_t n;
6229 struct prdwr_internal_arg arg;
6230 int shrinkable;
6231
6232 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6233 arg.count = NUM2SIZET(len);
6234 arg.offset = NUM2OFFT(offset);
6235
6236 shrinkable = io_setstrbuf(&str, (long)arg.count);
6237 if (arg.count == 0) return str;
6238 arg.buf = RSTRING_PTR(str);
6239
6240 GetOpenFile(io, fptr);
6242
6243 arg.io = fptr;
6244 arg.fd = fptr->fd;
6245 rb_io_check_closed(fptr);
6246
6247 rb_str_locktmp(str);
6248 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6249
6250 if (n < 0) {
6251 rb_sys_fail_path(fptr->pathv);
6252 }
6253 io_set_read_length(str, n, shrinkable);
6254 if (n == 0 && arg.count > 0) {
6255 rb_eof_error();
6256 }
6257
6258 return str;
6259}
6260
6261static VALUE
6262internal_pwrite_func(void *_arg)
6263{
6264 struct prdwr_internal_arg *arg = _arg;
6265
6266 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6267}
6268
6269static VALUE
6270pwrite_internal_call(VALUE _arg)
6271{
6272 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6273
6274 VALUE scheduler = rb_fiber_scheduler_current();
6275 if (scheduler != Qnil) {
6276 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6277
6278 if (!UNDEF_P(result)) {
6280 }
6281 }
6282
6283 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
6284}
6285
6286/*
6287 * call-seq:
6288 * pwrite(object, offset) -> integer
6289 *
6290 * Behaves like IO#write, except that it:
6291 *
6292 * - Writes at the given +offset+ (in bytes).
6293 * - Disregards, and does not modify, the stream's position
6294 * (see {Position}[rdoc-ref:IO@Position]).
6295 * - Bypasses any user space buffering in the stream.
6296 *
6297 * Because this method does not disturb the stream's state
6298 * (its position, in particular), +pwrite+ allows multiple threads and processes
6299 * to use the same \IO object for writing at various offsets.
6300 *
6301 * f = File.open('t.tmp', 'w+')
6302 * # Write 6 bytes at offset 3.
6303 * f.pwrite('ABCDEF', 3) # => 6
6304 * f.rewind
6305 * f.read # => "\u0000\u0000\u0000ABCDEF"
6306 * f.close
6307 *
6308 * Not available on some platforms.
6309 *
6310 */
6311static VALUE
6312rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6313{
6314 rb_io_t *fptr;
6315 ssize_t n;
6316 struct prdwr_internal_arg arg;
6317 VALUE tmp;
6318
6319 if (!RB_TYPE_P(str, T_STRING))
6320 str = rb_obj_as_string(str);
6321
6322 arg.offset = NUM2OFFT(offset);
6323
6324 io = GetWriteIO(io);
6325 GetOpenFile(io, fptr);
6327
6328 arg.io = fptr;
6329 arg.fd = fptr->fd;
6330
6331 tmp = rb_str_tmp_frozen_acquire(str);
6332 arg.buf = RSTRING_PTR(tmp);
6333 arg.count = (size_t)RSTRING_LEN(tmp);
6334
6335 n = (ssize_t)pwrite_internal_call((VALUE)&arg);
6336 if (n < 0) rb_sys_fail_path(fptr->pathv);
6337 rb_str_tmp_frozen_release(str, tmp);
6338
6339 return SSIZET2NUM(n);
6340}
6341
6342VALUE
6344{
6345 rb_io_t *fptr;
6346
6347 GetOpenFile(io, fptr);
6348 if (fptr->readconv)
6350 if (fptr->writeconv)
6352 fptr->mode |= FMODE_BINMODE;
6353 fptr->mode &= ~FMODE_TEXTMODE;
6354 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6355#ifdef O_BINARY
6356 if (!fptr->readconv) {
6357 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6358 }
6359 else {
6360 setmode(fptr->fd, O_BINARY);
6361 }
6362#endif
6363 return io;
6364}
6365
6366static void
6367io_ascii8bit_binmode(rb_io_t *fptr)
6368{
6369 if (fptr->readconv) {
6370 rb_econv_close(fptr->readconv);
6371 fptr->readconv = NULL;
6372 }
6373 if (fptr->writeconv) {
6375 fptr->writeconv = NULL;
6376 }
6377 fptr->mode |= FMODE_BINMODE;
6378 fptr->mode &= ~FMODE_TEXTMODE;
6379 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6380
6381 fptr->encs.enc = rb_ascii8bit_encoding();
6382 fptr->encs.enc2 = NULL;
6383 fptr->encs.ecflags = 0;
6384 fptr->encs.ecopts = Qnil;
6385 clear_codeconv(fptr);
6386}
6387
6388VALUE
6390{
6391 rb_io_t *fptr;
6392
6393 GetOpenFile(io, fptr);
6394 io_ascii8bit_binmode(fptr);
6395
6396 return io;
6397}
6398
6399/*
6400 * call-seq:
6401 * binmode -> self
6402 *
6403 * Sets the stream's data mode as binary
6404 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6405 *
6406 * A stream's data mode may not be changed from binary to text.
6407 *
6408 */
6409
6410static VALUE
6411rb_io_binmode_m(VALUE io)
6412{
6413 VALUE write_io;
6414
6416
6417 write_io = GetWriteIO(io);
6418 if (write_io != io)
6419 rb_io_ascii8bit_binmode(write_io);
6420 return io;
6421}
6422
6423/*
6424 * call-seq:
6425 * binmode? -> true or false
6426 *
6427 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6428 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6429 *
6430 */
6431static VALUE
6432rb_io_binmode_p(VALUE io)
6433{
6434 rb_io_t *fptr;
6435 GetOpenFile(io, fptr);
6436 return RBOOL(fptr->mode & FMODE_BINMODE);
6437}
6438
6439static const char*
6440rb_io_fmode_modestr(enum rb_io_mode fmode)
6441{
6442 if (fmode & FMODE_APPEND) {
6443 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6444 return MODE_BTMODE("a+", "ab+", "at+");
6445 }
6446 return MODE_BTMODE("a", "ab", "at");
6447 }
6448 switch (fmode & FMODE_READWRITE) {
6449 default:
6450 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6451 case FMODE_READABLE:
6452 return MODE_BTMODE("r", "rb", "rt");
6453 case FMODE_WRITABLE:
6454 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6455 case FMODE_READWRITE:
6456 if (fmode & FMODE_CREATE) {
6457 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6458 }
6459 return MODE_BTMODE("r+", "rb+", "rt+");
6460 }
6461}
6462
6463static const char bom_prefix[] = "bom|";
6464static const char utf_prefix[] = "utf-";
6465enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6466enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6467
6468static int
6469io_encname_bom_p(const char *name, long len)
6470{
6471 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6472}
6473
6474enum rb_io_mode
6475rb_io_modestr_fmode(const char *modestr)
6476{
6477 enum rb_io_mode fmode = 0;
6478 const char *m = modestr, *p = NULL;
6479
6480 switch (*m++) {
6481 case 'r':
6482 fmode |= FMODE_READABLE;
6483 break;
6484 case 'w':
6486 break;
6487 case 'a':
6489 break;
6490 default:
6491 goto error;
6492 }
6493
6494 while (*m) {
6495 switch (*m++) {
6496 case 'b':
6497 fmode |= FMODE_BINMODE;
6498 break;
6499 case 't':
6500 fmode |= FMODE_TEXTMODE;
6501 break;
6502 case '+':
6503 fmode |= FMODE_READWRITE;
6504 break;
6505 case 'x':
6506 if (modestr[0] != 'w')
6507 goto error;
6508 fmode |= FMODE_EXCL;
6509 break;
6510 default:
6511 goto error;
6512 case ':':
6513 p = strchr(m, ':');
6514 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6515 fmode |= FMODE_SETENC_BY_BOM;
6516 goto finished;
6517 }
6518 }
6519
6520 finished:
6521 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6522 goto error;
6523
6524 return fmode;
6525
6526 error:
6527 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6529}
6530
6531int
6532rb_io_oflags_fmode(int oflags)
6533{
6534 enum rb_io_mode fmode = 0;
6535
6536 switch (oflags & O_ACCMODE) {
6537 case O_RDONLY:
6538 fmode = FMODE_READABLE;
6539 break;
6540 case O_WRONLY:
6541 fmode = FMODE_WRITABLE;
6542 break;
6543 case O_RDWR:
6544 fmode = FMODE_READWRITE;
6545 break;
6546 }
6547
6548 if (oflags & O_APPEND) {
6549 fmode |= FMODE_APPEND;
6550 }
6551 if (oflags & O_TRUNC) {
6552 fmode |= FMODE_TRUNC;
6553 }
6554 if (oflags & O_CREAT) {
6555 fmode |= FMODE_CREATE;
6556 }
6557 if (oflags & O_EXCL) {
6558 fmode |= FMODE_EXCL;
6559 }
6560#ifdef O_BINARY
6561 if (oflags & O_BINARY) {
6562 fmode |= FMODE_BINMODE;
6563 }
6564#endif
6565
6566 return fmode;
6567}
6568
6569static int
6570rb_io_fmode_oflags(enum rb_io_mode fmode)
6571{
6572 int oflags = 0;
6573
6574 switch (fmode & FMODE_READWRITE) {
6575 case FMODE_READABLE:
6576 oflags |= O_RDONLY;
6577 break;
6578 case FMODE_WRITABLE:
6579 oflags |= O_WRONLY;
6580 break;
6581 case FMODE_READWRITE:
6582 oflags |= O_RDWR;
6583 break;
6584 }
6585
6586 if (fmode & FMODE_APPEND) {
6587 oflags |= O_APPEND;
6588 }
6589 if (fmode & FMODE_TRUNC) {
6590 oflags |= O_TRUNC;
6591 }
6592 if (fmode & FMODE_CREATE) {
6593 oflags |= O_CREAT;
6594 }
6595 if (fmode & FMODE_EXCL) {
6596 oflags |= O_EXCL;
6597 }
6598#ifdef O_BINARY
6599 if (fmode & FMODE_BINMODE) {
6600 oflags |= O_BINARY;
6601 }
6602#endif
6603
6604 return oflags;
6605}
6606
6607int
6608rb_io_modestr_oflags(const char *modestr)
6609{
6610 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6611}
6612
6613static const char*
6614rb_io_oflags_modestr(int oflags)
6615{
6616#ifdef O_BINARY
6617# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6618#else
6619# define MODE_BINARY(a,b) (a)
6620#endif
6621 int accmode;
6622 if (oflags & O_EXCL) {
6623 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6624 }
6625 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6626 if (oflags & O_APPEND) {
6627 if (accmode == O_WRONLY) {
6628 return MODE_BINARY("a", "ab");
6629 }
6630 if (accmode == O_RDWR) {
6631 return MODE_BINARY("a+", "ab+");
6632 }
6633 }
6634 switch (accmode) {
6635 default:
6636 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6637 case O_RDONLY:
6638 return MODE_BINARY("r", "rb");
6639 case O_WRONLY:
6640 return MODE_BINARY("w", "wb");
6641 case O_RDWR:
6642 if (oflags & O_TRUNC) {
6643 return MODE_BINARY("w+", "wb+");
6644 }
6645 return MODE_BINARY("r+", "rb+");
6646 }
6647}
6648
6649/*
6650 * Convert external/internal encodings to enc/enc2
6651 * NULL => use default encoding
6652 * Qnil => no encoding specified (internal only)
6653 */
6654static void
6655rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6656{
6657 int default_ext = 0;
6658
6659 if (ext == NULL) {
6660 ext = rb_default_external_encoding();
6661 default_ext = 1;
6662 }
6663 if (rb_is_ascii8bit_enc(ext)) {
6664 /* If external is ASCII-8BIT, no transcoding */
6665 intern = NULL;
6666 }
6667 else if (intern == NULL) {
6668 intern = rb_default_internal_encoding();
6669 }
6670 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6671 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6672 /* No internal encoding => use external + no transcoding */
6673 *enc = (default_ext && intern != ext) ? NULL : ext;
6674 *enc2 = NULL;
6675 }
6676 else {
6677 *enc = intern;
6678 *enc2 = ext;
6679 }
6680}
6681
6682static void
6683unsupported_encoding(const char *name, rb_encoding *enc)
6684{
6685 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6686}
6687
6688static void
6689parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6690 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6691{
6692 const char *p;
6693 char encname[ENCODING_MAXNAMELEN+1];
6694 int idx, idx2;
6695 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6696 rb_encoding *ext_enc, *int_enc;
6697 long len;
6698
6699 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6700
6701 p = strrchr(estr, ':');
6702 len = p ? (p++ - estr) : (long)strlen(estr);
6703 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6704 estr += bom_prefix_len;
6705 len -= bom_prefix_len;
6706 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6707 fmode |= FMODE_SETENC_BY_BOM;
6708 }
6709 else {
6710 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6711 fmode &= ~FMODE_SETENC_BY_BOM;
6712 }
6713 }
6714 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6715 idx = -1;
6716 }
6717 else {
6718 if (p) {
6719 memcpy(encname, estr, len);
6720 encname[len] = '\0';
6721 estr = encname;
6722 }
6723 idx = rb_enc_find_index(estr);
6724 }
6725 if (fmode_p) *fmode_p = fmode;
6726
6727 if (idx >= 0)
6728 ext_enc = rb_enc_from_index(idx);
6729 else {
6730 if (idx != -2)
6731 unsupported_encoding(estr, estr_enc);
6732 ext_enc = NULL;
6733 }
6734
6735 int_enc = NULL;
6736 if (p) {
6737 if (*p == '-' && *(p+1) == '\0') {
6738 /* Special case - "-" => no transcoding */
6739 int_enc = (rb_encoding *)Qnil;
6740 }
6741 else {
6742 idx2 = rb_enc_find_index(p);
6743 if (idx2 < 0)
6744 unsupported_encoding(p, estr_enc);
6745 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6746 int_enc = (rb_encoding *)Qnil;
6747 }
6748 else
6749 int_enc = rb_enc_from_index(idx2);
6750 }
6751 }
6752
6753 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6754}
6755
6756int
6757rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6758{
6759 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6760 int extracted = 0;
6761 rb_encoding *extencoding = NULL;
6762 rb_encoding *intencoding = NULL;
6763
6764 if (!NIL_P(opt)) {
6765 VALUE v;
6766 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6767 if (v != Qnil) encoding = v;
6768 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6769 if (v != Qnil) extenc = v;
6770 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6771 if (!UNDEF_P(v)) intenc = v;
6772 }
6773 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6774 if (!NIL_P(ruby_verbose)) {
6775 int idx = rb_to_encoding_index(encoding);
6776 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6777 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6778 encoding, UNDEF_P(extenc) ? "internal" : "external");
6779 }
6780 encoding = Qnil;
6781 }
6782 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6783 extencoding = rb_to_encoding(extenc);
6784 }
6785 if (!UNDEF_P(intenc)) {
6786 if (NIL_P(intenc)) {
6787 /* internal_encoding: nil => no transcoding */
6788 intencoding = (rb_encoding *)Qnil;
6789 }
6790 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6791 char *p = StringValueCStr(tmp);
6792
6793 if (*p == '-' && *(p+1) == '\0') {
6794 /* Special case - "-" => no transcoding */
6795 intencoding = (rb_encoding *)Qnil;
6796 }
6797 else {
6798 intencoding = rb_to_encoding(intenc);
6799 }
6800 }
6801 else {
6802 intencoding = rb_to_encoding(intenc);
6803 }
6804 if (extencoding == intencoding) {
6805 intencoding = (rb_encoding *)Qnil;
6806 }
6807 }
6808 if (!NIL_P(encoding)) {
6809 extracted = 1;
6810 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6811 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6812 enc_p, enc2_p, fmode_p);
6813 }
6814 else {
6815 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6816 }
6817 }
6818 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6819 extracted = 1;
6820 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6821 }
6822 return extracted;
6823}
6824
6825static void
6826validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6827{
6828 enum rb_io_mode fmode = *fmode_p;
6829
6830 if ((fmode & FMODE_READABLE) &&
6831 !enc2 &&
6832 !(fmode & FMODE_BINMODE) &&
6833 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6834 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6835
6836 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6837 rb_raise(rb_eArgError, "newline decorator with binary mode");
6838 }
6839 if (!(fmode & FMODE_BINMODE) &&
6840 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6841 fmode |= FMODE_TEXTMODE;
6842 *fmode_p = fmode;
6843 }
6844#if !DEFAULT_TEXTMODE
6845 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6846 fmode &= ~FMODE_TEXTMODE;
6847 *fmode_p = fmode;
6848 }
6849#endif
6850}
6851
6852static void
6853extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
6854{
6855 if (!NIL_P(opthash)) {
6856 VALUE v;
6857 v = rb_hash_aref(opthash, sym_textmode);
6858 if (!NIL_P(v)) {
6859 if (*fmode & FMODE_TEXTMODE)
6860 rb_raise(rb_eArgError, "textmode specified twice");
6861 if (*fmode & FMODE_BINMODE)
6862 rb_raise(rb_eArgError, "both textmode and binmode specified");
6863 if (RTEST(v))
6864 *fmode |= FMODE_TEXTMODE;
6865 }
6866 v = rb_hash_aref(opthash, sym_binmode);
6867 if (!NIL_P(v)) {
6868 if (*fmode & FMODE_BINMODE)
6869 rb_raise(rb_eArgError, "binmode specified twice");
6870 if (*fmode & FMODE_TEXTMODE)
6871 rb_raise(rb_eArgError, "both textmode and binmode specified");
6872 if (RTEST(v))
6873 *fmode |= FMODE_BINMODE;
6874 }
6875
6876 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6877 rb_raise(rb_eArgError, "both textmode and binmode specified");
6878 }
6879}
6880
6881void
6882rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6883 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
6884{
6885 VALUE vmode;
6886 int oflags;
6887 enum rb_io_mode fmode;
6888 rb_encoding *enc, *enc2;
6889 int ecflags;
6890 VALUE ecopts;
6891 int has_enc = 0, has_vmode = 0;
6892 VALUE intmode;
6893
6894 vmode = *vmode_p;
6895
6896 /* Set to defaults */
6897 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6898
6899 vmode_handle:
6900 if (NIL_P(vmode)) {
6901 fmode = FMODE_READABLE;
6902 oflags = O_RDONLY;
6903 }
6904 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6905 vmode = intmode;
6906 oflags = NUM2INT(intmode);
6907 fmode = rb_io_oflags_fmode(oflags);
6908 }
6909 else {
6910 const char *p;
6911
6912 StringValue(vmode);
6913 p = StringValueCStr(vmode);
6914 fmode = rb_io_modestr_fmode(p);
6915 oflags = rb_io_fmode_oflags(fmode);
6916 p = strchr(p, ':');
6917 if (p) {
6918 has_enc = 1;
6919 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6920 }
6921 else {
6922 rb_encoding *e;
6923
6924 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6925 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6926 }
6927 }
6928
6929 if (NIL_P(opthash)) {
6930 ecflags = (fmode & FMODE_READABLE) ?
6933#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6934 ecflags |= (fmode & FMODE_WRITABLE) ?
6935 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6936 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6937#endif
6938 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6939 ecopts = Qnil;
6940 if (fmode & FMODE_BINMODE) {
6941#ifdef O_BINARY
6942 oflags |= O_BINARY;
6943#endif
6944 if (!has_enc)
6945 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6946 }
6947#if DEFAULT_TEXTMODE
6948 else if (NIL_P(vmode)) {
6949 fmode |= DEFAULT_TEXTMODE;
6950 }
6951#endif
6952 }
6953 else {
6954 VALUE v;
6955 if (!has_vmode) {
6956 v = rb_hash_aref(opthash, sym_mode);
6957 if (!NIL_P(v)) {
6958 if (!NIL_P(vmode)) {
6959 rb_raise(rb_eArgError, "mode specified twice");
6960 }
6961 has_vmode = 1;
6962 vmode = v;
6963 goto vmode_handle;
6964 }
6965 }
6966 v = rb_hash_aref(opthash, sym_flags);
6967 if (!NIL_P(v)) {
6968 v = rb_to_int(v);
6969 oflags |= NUM2INT(v);
6970 vmode = INT2NUM(oflags);
6971 fmode = rb_io_oflags_fmode(oflags);
6972 }
6973 extract_binmode(opthash, &fmode);
6974 if (fmode & FMODE_BINMODE) {
6975#ifdef O_BINARY
6976 oflags |= O_BINARY;
6977#endif
6978 if (!has_enc)
6979 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6980 }
6981#if DEFAULT_TEXTMODE
6982 else if (NIL_P(vmode)) {
6983 fmode |= DEFAULT_TEXTMODE;
6984 }
6985#endif
6986 v = rb_hash_aref(opthash, sym_perm);
6987 if (!NIL_P(v)) {
6988 if (vperm_p) {
6989 if (!NIL_P(*vperm_p)) {
6990 rb_raise(rb_eArgError, "perm specified twice");
6991 }
6992 *vperm_p = v;
6993 }
6994 else {
6995 /* perm no use, just ignore */
6996 }
6997 }
6998 ecflags = (fmode & FMODE_READABLE) ?
7001#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7002 ecflags |= (fmode & FMODE_WRITABLE) ?
7003 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7004 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7005#endif
7006
7007 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7008 if (has_enc) {
7009 rb_raise(rb_eArgError, "encoding specified twice");
7010 }
7011 }
7012 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7013 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7014 }
7015
7016 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7017
7018 *vmode_p = vmode;
7019
7020 *oflags_p = oflags;
7021 *fmode_p = fmode;
7022 convconfig_p->enc = enc;
7023 convconfig_p->enc2 = enc2;
7024 convconfig_p->ecflags = ecflags;
7025 convconfig_p->ecopts = ecopts;
7026}
7027
7029 VALUE fname;
7030 int oflags;
7031 mode_t perm;
7032};
7033
7034static void *
7035sysopen_func(void *ptr)
7036{
7037 const struct sysopen_struct *data = ptr;
7038 const char *fname = RSTRING_PTR(data->fname);
7039 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7040}
7041
7042static inline int
7043rb_sysopen_internal(struct sysopen_struct *data)
7044{
7045 int fd;
7046 do {
7047 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7048 } while (fd < 0 && errno == EINTR);
7049 if (0 <= fd)
7050 rb_update_max_fd(fd);
7051 return fd;
7052}
7053
7054static int
7055rb_sysopen(VALUE fname, int oflags, mode_t perm)
7056{
7057 int fd = -1;
7058 struct sysopen_struct data;
7059
7060 data.fname = rb_str_encode_ospath(fname);
7061 StringValueCStr(data.fname);
7062 data.oflags = oflags;
7063 data.perm = perm;
7064
7065 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7066 rb_syserr_fail_path(first_errno, fname);
7067 }
7068 return fd;
7069}
7070
7071static inline FILE *
7072fdopen_internal(int fd, const char *modestr)
7073{
7074 FILE *file;
7075
7076#if defined(__sun)
7077 errno = 0;
7078#endif
7079 file = fdopen(fd, modestr);
7080 if (!file) {
7081#ifdef _WIN32
7082 if (errno == 0) errno = EINVAL;
7083#elif defined(__sun)
7084 if (errno == 0) errno = EMFILE;
7085#endif
7086 }
7087 return file;
7088}
7089
7090FILE *
7091rb_fdopen(int fd, const char *modestr)
7092{
7093 FILE *file = 0;
7094
7095 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7096 rb_syserr_fail(first_errno, 0);
7097 }
7098
7099 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7100#ifdef USE_SETVBUF
7101 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7102 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7103#endif
7104 return file;
7105}
7106
7107static int
7108io_check_tty(rb_io_t *fptr)
7109{
7110 int t = isatty(fptr->fd);
7111 if (t)
7112 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7113 return t;
7114}
7115
7116static VALUE rb_io_internal_encoding(VALUE);
7117static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7118
7119static int
7120io_strip_bom(VALUE io)
7121{
7122 VALUE b1, b2, b3, b4;
7123 rb_io_t *fptr;
7124
7125 GetOpenFile(io, fptr);
7126 if (!(fptr->mode & FMODE_READABLE)) return 0;
7127 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7128 switch (b1) {
7129 case INT2FIX(0xEF):
7130 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7131 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7132 if (b3 == INT2FIX(0xBF)) {
7133 return rb_utf8_encindex();
7134 }
7135 rb_io_ungetbyte(io, b3);
7136 }
7137 rb_io_ungetbyte(io, b2);
7138 break;
7139
7140 case INT2FIX(0xFE):
7141 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7142 if (b2 == INT2FIX(0xFF)) {
7143 return ENCINDEX_UTF_16BE;
7144 }
7145 rb_io_ungetbyte(io, b2);
7146 break;
7147
7148 case INT2FIX(0xFF):
7149 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7150 if (b2 == INT2FIX(0xFE)) {
7151 b3 = rb_io_getbyte(io);
7152 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7153 if (b4 == INT2FIX(0)) {
7154 return ENCINDEX_UTF_32LE;
7155 }
7156 rb_io_ungetbyte(io, b4);
7157 }
7158 rb_io_ungetbyte(io, b3);
7159 return ENCINDEX_UTF_16LE;
7160 }
7161 rb_io_ungetbyte(io, b2);
7162 break;
7163
7164 case INT2FIX(0):
7165 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7166 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7167 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7168 if (b4 == INT2FIX(0xFF)) {
7169 return ENCINDEX_UTF_32BE;
7170 }
7171 rb_io_ungetbyte(io, b4);
7172 }
7173 rb_io_ungetbyte(io, b3);
7174 }
7175 rb_io_ungetbyte(io, b2);
7176 break;
7177 }
7178 rb_io_ungetbyte(io, b1);
7179 return 0;
7180}
7181
7182static rb_encoding *
7183io_set_encoding_by_bom(VALUE io)
7184{
7185 int idx = io_strip_bom(io);
7186 rb_io_t *fptr;
7187 rb_encoding *extenc = NULL;
7188
7189 GetOpenFile(io, fptr);
7190 if (idx) {
7191 extenc = rb_enc_from_index(idx);
7192 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7193 rb_io_internal_encoding(io), Qnil);
7194 }
7195 else {
7196 fptr->encs.enc2 = NULL;
7197 }
7198 return extenc;
7199}
7200
7201static VALUE
7202rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7203 const struct rb_io_encoding *convconfig, mode_t perm)
7204{
7205 VALUE pathv;
7206 rb_io_t *fptr;
7207 struct rb_io_encoding cc;
7208 if (!convconfig) {
7209 /* Set to default encodings */
7210 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7211 cc.ecflags = 0;
7212 cc.ecopts = Qnil;
7213 convconfig = &cc;
7214 }
7215 validate_enc_binmode(&fmode, convconfig->ecflags,
7216 convconfig->enc, convconfig->enc2);
7217
7218 MakeOpenFile(io, fptr);
7219 fptr->mode = fmode;
7220 fptr->encs = *convconfig;
7221 pathv = rb_str_new_frozen(filename);
7222#ifdef O_TMPFILE
7223 if (!(oflags & O_TMPFILE)) {
7224 fptr->pathv = pathv;
7225 }
7226#else
7227 fptr->pathv = pathv;
7228#endif
7229 fptr->fd = rb_sysopen(pathv, oflags, perm);
7230 io_check_tty(fptr);
7231 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7232
7233 return io;
7234}
7235
7236static VALUE
7237rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7238{
7239 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7240 const char *p = strchr(modestr, ':');
7241 struct rb_io_encoding convconfig;
7242
7243 if (p) {
7244 parse_mode_enc(p+1, rb_usascii_encoding(),
7245 &convconfig.enc, &convconfig.enc2, &fmode);
7246 }
7247 else {
7248 rb_encoding *e;
7249 /* Set to default encodings */
7250
7251 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7252 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7253 }
7254
7255 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7258#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7259 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7260 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7261 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7262#endif
7263 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7264 convconfig.ecopts = Qnil;
7265
7266 return rb_file_open_generic(io, filename,
7267 rb_io_fmode_oflags(fmode),
7268 fmode,
7269 &convconfig,
7270 0666);
7271}
7272
7273VALUE
7274rb_file_open_str(VALUE fname, const char *modestr)
7275{
7276 FilePathValue(fname);
7277 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7278}
7279
7280VALUE
7281rb_file_open(const char *fname, const char *modestr)
7282{
7283 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7284}
7285
7286#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7287static struct pipe_list {
7288 rb_io_t *fptr;
7289 struct pipe_list *next;
7290} *pipe_list;
7291
7292static void
7293pipe_add_fptr(rb_io_t *fptr)
7294{
7295 struct pipe_list *list;
7296
7297 list = ALLOC(struct pipe_list);
7298 list->fptr = fptr;
7299 list->next = pipe_list;
7300 pipe_list = list;
7301}
7302
7303static void
7304pipe_del_fptr(rb_io_t *fptr)
7305{
7306 struct pipe_list **prev = &pipe_list;
7307 struct pipe_list *tmp;
7308
7309 while ((tmp = *prev) != 0) {
7310 if (tmp->fptr == fptr) {
7311 *prev = tmp->next;
7312 free(tmp);
7313 return;
7314 }
7315 prev = &tmp->next;
7316 }
7317}
7318
7319#if defined (_WIN32) || defined(__CYGWIN__)
7320static void
7321pipe_atexit(void)
7322{
7323 struct pipe_list *list = pipe_list;
7324 struct pipe_list *tmp;
7325
7326 while (list) {
7327 tmp = list->next;
7328 rb_io_fptr_finalize(list->fptr);
7329 list = tmp;
7330 }
7331}
7332#endif
7333
7334static void
7335pipe_finalize(rb_io_t *fptr, int noraise)
7336{
7337#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7338 int status = 0;
7339 if (fptr->stdio_file) {
7340 status = pclose(fptr->stdio_file);
7341 }
7342 fptr->fd = -1;
7343 fptr->stdio_file = 0;
7344 rb_last_status_set(status, fptr->pid);
7345#else
7346 fptr_finalize(fptr, noraise);
7347#endif
7348 pipe_del_fptr(fptr);
7349}
7350#endif
7351
7352static void
7353fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7354{
7355#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7356 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7357
7358 if (old_finalize == orig->finalize) return;
7359#endif
7360
7361 fptr->finalize = orig->finalize;
7362
7363#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7364 if (old_finalize != pipe_finalize) {
7365 struct pipe_list *list;
7366 for (list = pipe_list; list; list = list->next) {
7367 if (list->fptr == fptr) break;
7368 }
7369 if (!list) pipe_add_fptr(fptr);
7370 }
7371 else {
7372 pipe_del_fptr(fptr);
7373 }
7374#endif
7375}
7376
7377void
7379{
7381 fptr->mode |= FMODE_SYNC;
7382}
7383
7384void
7385rb_io_unbuffered(rb_io_t *fptr)
7386{
7387 rb_io_synchronized(fptr);
7388}
7389
7390int
7391rb_pipe(int *pipes)
7392{
7393 int ret;
7394 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7395 if (ret == 0) {
7396 rb_update_max_fd(pipes[0]);
7397 rb_update_max_fd(pipes[1]);
7398 }
7399 return ret;
7400}
7401
7402#ifdef _WIN32
7403#define HAVE_SPAWNV 1
7404#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7405#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7406#endif
7407
7408#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7409struct popen_arg {
7410 VALUE execarg_obj;
7411 struct rb_execarg *eargp;
7412 int modef;
7413 int pair[2];
7414 int write_pair[2];
7415};
7416#endif
7417
7418#ifdef HAVE_WORKING_FORK
7419# ifndef __EMSCRIPTEN__
7420static void
7421popen_redirect(struct popen_arg *p)
7422{
7423 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7424 close(p->write_pair[1]);
7425 if (p->write_pair[0] != 0) {
7426 dup2(p->write_pair[0], 0);
7427 close(p->write_pair[0]);
7428 }
7429 close(p->pair[0]);
7430 if (p->pair[1] != 1) {
7431 dup2(p->pair[1], 1);
7432 close(p->pair[1]);
7433 }
7434 }
7435 else if (p->modef & FMODE_READABLE) {
7436 close(p->pair[0]);
7437 if (p->pair[1] != 1) {
7438 dup2(p->pair[1], 1);
7439 close(p->pair[1]);
7440 }
7441 }
7442 else {
7443 close(p->pair[1]);
7444 if (p->pair[0] != 0) {
7445 dup2(p->pair[0], 0);
7446 close(p->pair[0]);
7447 }
7448 }
7449}
7450# endif
7451
7452#if defined(__linux__)
7453/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7454 * Since /proc may not be available, linux_get_maxfd is just a hint.
7455 * This function, linux_get_maxfd, must be async-signal-safe.
7456 * I.e. opendir() is not usable.
7457 *
7458 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7459 * However they are easy to re-implement in async-signal-safe manner.
7460 * (Also note that there is missing/memcmp.c.)
7461 */
7462static int
7463linux_get_maxfd(void)
7464{
7465 int fd;
7466 char buf[4096], *p, *np, *e;
7467 ssize_t ss;
7468 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7469 if (fd < 0) return fd;
7470 ss = read(fd, buf, sizeof(buf));
7471 if (ss < 0) goto err;
7472 p = buf;
7473 e = buf + ss;
7474 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7475 (np = memchr(p, '\n', e-p)) != NULL) {
7476 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7477 int fdsize;
7478 p += sizeof("FDSize:")-1;
7479 *np = '\0';
7480 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7481 close(fd);
7482 return fdsize;
7483 }
7484 p = np+1;
7485 }
7486 /* fall through */
7487
7488 err:
7489 close(fd);
7490 return (int)ss;
7491}
7492#endif
7493
7494/* This function should be async-signal-safe. */
7495void
7496rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7497{
7498#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7499 int fd, ret;
7500 int max = (int)max_file_descriptor;
7501# ifdef F_MAXFD
7502 /* F_MAXFD is available since NetBSD 2.0. */
7503 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7504 if (ret != -1)
7505 maxhint = max = ret;
7506# elif defined(__linux__)
7507 ret = linux_get_maxfd();
7508 if (maxhint < ret)
7509 maxhint = ret;
7510 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7511# endif
7512 if (max < maxhint)
7513 max = maxhint;
7514 for (fd = lowfd; fd <= max; fd++) {
7515 if (!NIL_P(noclose_fds) &&
7516 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7517 continue;
7518 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7519 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7520 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7521 }
7522# define CONTIGUOUS_CLOSED_FDS 20
7523 if (ret != -1) {
7524 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7525 max = fd + CONTIGUOUS_CLOSED_FDS;
7526 }
7527 }
7528#endif
7529}
7530
7531# ifndef __EMSCRIPTEN__
7532static int
7533popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7534{
7535 struct popen_arg *p = (struct popen_arg*)pp;
7536
7537 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7538}
7539# endif
7540#endif
7541
7542#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7543static VALUE
7544rb_execarg_fixup_v(VALUE execarg_obj)
7545{
7546 rb_execarg_parent_start(execarg_obj);
7547 return Qnil;
7548}
7549#else
7550char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7551#endif
7552
7553#ifndef __EMSCRIPTEN__
7554static VALUE
7555pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7556 const struct rb_io_encoding *convconfig)
7557{
7558 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7559 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7560 rb_pid_t pid = 0;
7561 rb_io_t *fptr;
7562 VALUE port;
7563 rb_io_t *write_fptr;
7564 VALUE write_port;
7565#if defined(HAVE_WORKING_FORK)
7566 int status;
7567 char errmsg[80] = { '\0' };
7568#endif
7569#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7570 int state;
7571 struct popen_arg arg;
7572#endif
7573 int e = 0;
7574#if defined(HAVE_SPAWNV)
7575# if defined(HAVE_SPAWNVE)
7576# define DO_SPAWN(cmd, args, envp) ((args) ? \
7577 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7578 spawne(P_NOWAIT, (cmd), (envp)))
7579# else
7580# define DO_SPAWN(cmd, args, envp) ((args) ? \
7581 spawnv(P_NOWAIT, (cmd), (args)) : \
7582 spawn(P_NOWAIT, (cmd)))
7583# endif
7584# if !defined(HAVE_WORKING_FORK)
7585 char **args = NULL;
7586# if defined(HAVE_SPAWNVE)
7587 char **envp = NULL;
7588# endif
7589# endif
7590#endif
7591#if !defined(HAVE_WORKING_FORK)
7592 struct rb_execarg sarg, *sargp = &sarg;
7593#endif
7594 FILE *fp = 0;
7595 int fd = -1;
7596 int write_fd = -1;
7597#if !defined(HAVE_WORKING_FORK)
7598 const char *cmd = 0;
7599
7600 if (prog)
7601 cmd = StringValueCStr(prog);
7602#endif
7603
7604#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7605 arg.execarg_obj = execarg_obj;
7606 arg.eargp = eargp;
7607 arg.modef = fmode;
7608 arg.pair[0] = arg.pair[1] = -1;
7609 arg.write_pair[0] = arg.write_pair[1] = -1;
7610# if !defined(HAVE_WORKING_FORK)
7611 if (eargp && !eargp->use_shell) {
7612 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7613 }
7614# endif
7615 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7617 if (rb_pipe(arg.write_pair) < 0)
7618 rb_sys_fail_str(prog);
7619 if (rb_pipe(arg.pair) < 0) {
7620 e = errno;
7621 close(arg.write_pair[0]);
7622 close(arg.write_pair[1]);
7623 rb_syserr_fail_str(e, prog);
7624 }
7625 if (eargp) {
7626 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7627 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7628 }
7629 break;
7630 case FMODE_READABLE:
7631 if (rb_pipe(arg.pair) < 0)
7632 rb_sys_fail_str(prog);
7633 if (eargp)
7634 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7635 break;
7636 case FMODE_WRITABLE:
7637 if (rb_pipe(arg.pair) < 0)
7638 rb_sys_fail_str(prog);
7639 if (eargp)
7640 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7641 break;
7642 default:
7643 rb_sys_fail_str(prog);
7644 }
7645 if (!NIL_P(execarg_obj)) {
7646 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7647 if (state) {
7648 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7649 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7650 if (0 <= arg.pair[0]) close(arg.pair[0]);
7651 if (0 <= arg.pair[1]) close(arg.pair[1]);
7652 rb_execarg_parent_end(execarg_obj);
7653 rb_jump_tag(state);
7654 }
7655
7656# if defined(HAVE_WORKING_FORK)
7657 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7658# else
7659 rb_execarg_run_options(eargp, sargp, NULL, 0);
7660# if defined(HAVE_SPAWNVE)
7661 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7662# endif
7663 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7664 /* exec failed */
7665 switch (e = errno) {
7666 case EAGAIN:
7667# if EWOULDBLOCK != EAGAIN
7668 case EWOULDBLOCK:
7669# endif
7670 rb_thread_sleep(1);
7671 continue;
7672 }
7673 break;
7674 }
7675 if (eargp)
7676 rb_execarg_run_options(sargp, NULL, NULL, 0);
7677# endif
7678 rb_execarg_parent_end(execarg_obj);
7679 }
7680 else {
7681# if defined(HAVE_WORKING_FORK)
7682 pid = rb_call_proc__fork();
7683 if (pid == 0) { /* child */
7684 popen_redirect(&arg);
7685 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7686 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7687 return Qnil;
7688 }
7689# else
7691# endif
7692 }
7693
7694 /* parent */
7695 if (pid < 0) {
7696# if defined(HAVE_WORKING_FORK)
7697 e = errno;
7698# endif
7699 close(arg.pair[0]);
7700 close(arg.pair[1]);
7702 close(arg.write_pair[0]);
7703 close(arg.write_pair[1]);
7704 }
7705# if defined(HAVE_WORKING_FORK)
7706 if (errmsg[0])
7707 rb_syserr_fail(e, errmsg);
7708# endif
7709 rb_syserr_fail_str(e, prog);
7710 }
7711 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7712 close(arg.pair[1]);
7713 fd = arg.pair[0];
7714 close(arg.write_pair[0]);
7715 write_fd = arg.write_pair[1];
7716 }
7717 else if (fmode & FMODE_READABLE) {
7718 close(arg.pair[1]);
7719 fd = arg.pair[0];
7720 }
7721 else {
7722 close(arg.pair[0]);
7723 fd = arg.pair[1];
7724 }
7725#else
7726 cmd = rb_execarg_commandline(eargp, &prog);
7727 if (!NIL_P(execarg_obj)) {
7728 rb_execarg_parent_start(execarg_obj);
7729 rb_execarg_run_options(eargp, sargp, NULL, 0);
7730 }
7731 fp = popen(cmd, modestr);
7732 e = errno;
7733 if (eargp) {
7734 rb_execarg_parent_end(execarg_obj);
7735 rb_execarg_run_options(sargp, NULL, NULL, 0);
7736 }
7737 if (!fp) rb_syserr_fail_path(e, prog);
7738 fd = fileno(fp);
7739#endif
7740
7741 port = io_alloc(rb_cIO);
7742 MakeOpenFile(port, fptr);
7743 fptr->fd = fd;
7744 fptr->stdio_file = fp;
7745 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7746 if (convconfig) {
7747 fptr->encs = *convconfig;
7748#if RUBY_CRLF_ENVIRONMENT
7751 }
7752#endif
7753 }
7754 else {
7755 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7757 }
7758#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7759 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7760 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7761 }
7762#endif
7763 }
7764 fptr->pid = pid;
7765
7766 if (0 <= write_fd) {
7767 write_port = io_alloc(rb_cIO);
7768 MakeOpenFile(write_port, write_fptr);
7769 write_fptr->fd = write_fd;
7770 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7771 fptr->mode &= ~FMODE_WRITABLE;
7772 fptr->tied_io_for_writing = write_port;
7773 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7774 }
7775
7776#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7777 fptr->finalize = pipe_finalize;
7778 pipe_add_fptr(fptr);
7779#endif
7780 return port;
7781}
7782#else
7783static VALUE
7784pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7785 const struct rb_io_encoding *convconfig)
7786{
7787 rb_raise(rb_eNotImpError, "popen() is not available");
7788}
7789#endif
7790
7791static int
7792is_popen_fork(VALUE prog)
7793{
7794 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7795#if !defined(HAVE_WORKING_FORK)
7796 rb_raise(rb_eNotImpError,
7797 "fork() function is unimplemented on this machine");
7798#else
7799 return TRUE;
7800#endif
7801 }
7802 return FALSE;
7803}
7804
7805static VALUE
7806pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
7807 const struct rb_io_encoding *convconfig)
7808{
7809 int argc = 1;
7810 VALUE *argv = &prog;
7811 VALUE execarg_obj = Qnil;
7812
7813 if (!is_popen_fork(prog))
7814 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7815 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7816}
7817
7818static VALUE
7819pipe_close(VALUE io)
7820{
7821 rb_io_t *fptr = io_close_fptr(io);
7822 if (fptr) {
7823 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7824 }
7825 return Qnil;
7826}
7827
7828static VALUE popen_finish(VALUE port, VALUE klass);
7829
7830/*
7831 * call-seq:
7832 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7833 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7834 *
7835 * Executes the given command +cmd+ as a subprocess
7836 * whose $stdin and $stdout are connected to a new stream +io+.
7837 *
7838 * This method has potential security vulnerabilities if called with untrusted input;
7839 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
7840 *
7841 * If no block is given, returns the new stream,
7842 * which depending on given +mode+ may be open for reading, writing, or both.
7843 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7844 *
7845 * If a block is given, the stream is passed to the block
7846 * (again, open for reading, writing, or both);
7847 * when the block exits, the stream is closed,
7848 * the block's value is returned,
7849 * and the global variable <tt>$?</tt> is set to the child's exit status.
7850 *
7851 * Optional argument +mode+ may be any valid \IO mode.
7852 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7853 *
7854 * Required argument +cmd+ determines which of the following occurs:
7855 *
7856 * - The process forks.
7857 * - A specified program runs in a shell.
7858 * - A specified program runs with specified arguments.
7859 * - A specified program runs with specified arguments and a specified +argv0+.
7860 *
7861 * Each of these is detailed below.
7862 *
7863 * The optional hash argument +env+ specifies name/value pairs that are to be added
7864 * to the environment variables for the subprocess:
7865 *
7866 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7867 * pipe.puts 'puts ENV["FOO"]'
7868 * pipe.close_write
7869 * pipe.gets
7870 * end => "bar\n"
7871 *
7872 * Optional keyword arguments +opts+ specify:
7873 *
7874 * - {Open options}[rdoc-ref:IO@Open+Options].
7875 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7876 * - Options for Kernel#spawn.
7877 *
7878 * <b>Forked Process</b>
7879 *
7880 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7881 * IO.popen('-') do |pipe|
7882 * if pipe
7883 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7884 * else
7885 * $stderr.puts "In child, pid is #{$$}\n"
7886 * end
7887 * end
7888 *
7889 * Output:
7890 *
7891 * In parent, child pid is 26253
7892 * In child, pid is 26253
7893 *
7894 * Note that this is not supported on all platforms.
7895 *
7896 * <b>Shell Subprocess</b>
7897 *
7898 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7899 * the program named +cmd+ is run as a shell command:
7900 *
7901 * IO.popen('uname') do |pipe|
7902 * pipe.readlines
7903 * end
7904 *
7905 * Output:
7906 *
7907 * ["Linux\n"]
7908 *
7909 * Another example:
7910 *
7911 * IO.popen('/bin/sh', 'r+') do |pipe|
7912 * pipe.puts('ls')
7913 * pipe.close_write
7914 * $stderr.puts pipe.readlines.size
7915 * end
7916 *
7917 * Output:
7918 *
7919 * 213
7920 *
7921 * <b>Program Subprocess</b>
7922 *
7923 * When argument +cmd+ is an array of strings,
7924 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7925 *
7926 * IO.popen(['du', '..', '.']) do |pipe|
7927 * $stderr.puts pipe.readlines.size
7928 * end
7929 *
7930 * Output:
7931 *
7932 * 1111
7933 *
7934 * <b>Program Subprocess with <tt>argv0</tt></b>
7935 *
7936 * When argument +cmd+ is an array whose first element is a 2-element string array
7937 * and whose remaining elements (if any) are strings:
7938 *
7939 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7940 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7941 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7942 *
7943 * Example (sets <tt>$0</tt> to 'foo'):
7944 *
7945 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7946 *
7947 * <b>Some Special Examples</b>
7948 *
7949 * # Set IO encoding.
7950 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7951 * euc_jp_string = nkf_io.read
7952 * }
7953 *
7954 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7955 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7956 * ls_result_with_error = io.read
7957 * end
7958 *
7959 * # Use mixture of spawn options and IO options.
7960 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7961 * ls_result_with_error = io.read
7962 * end
7963 *
7964 * f = IO.popen("uname")
7965 * p f.readlines
7966 * f.close
7967 * puts "Parent is #{Process.pid}"
7968 * IO.popen("date") {|f| puts f.gets }
7969 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7970 * p $?
7971 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7972 * f.puts "bar"; f.close_write; puts f.gets
7973 * }
7974 *
7975 * Output (from last section):
7976 *
7977 * ["Linux\n"]
7978 * Parent is 21346
7979 * Thu Jan 15 22:41:19 JST 2009
7980 * 21346 is here, f is #<IO:fd 3>
7981 * 21352 is here, f is nil
7982 * #<Process::Status: pid 21352 exit 0>
7983 * <foo>bar;zot;
7984 *
7985 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7986 *
7987 */
7988
7989static VALUE
7990rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7991{
7992 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7993
7994 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7995 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7996 switch (argc) {
7997 case 2:
7998 pmode = argv[1];
7999 case 1:
8000 pname = argv[0];
8001 break;
8002 default:
8003 {
8004 int ex = !NIL_P(opt);
8005 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8006 }
8007 }
8008 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8009}
8010
8011VALUE
8012rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8013{
8014 const char *modestr;
8015 VALUE tmp, execarg_obj = Qnil;
8016 int oflags;
8017 enum rb_io_mode fmode;
8018 struct rb_io_encoding convconfig;
8019
8020 tmp = rb_check_array_type(pname);
8021 if (!NIL_P(tmp)) {
8022 long len = RARRAY_LEN(tmp);
8023#if SIZEOF_LONG > SIZEOF_INT
8024 if (len > INT_MAX) {
8025 rb_raise(rb_eArgError, "too many arguments");
8026 }
8027#endif
8028 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8029 RB_GC_GUARD(tmp);
8030 }
8031 else {
8032 StringValue(pname);
8033 execarg_obj = Qnil;
8034 if (!is_popen_fork(pname))
8035 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8036 }
8037 if (!NIL_P(execarg_obj)) {
8038 if (!NIL_P(opt))
8039 opt = rb_execarg_extract_options(execarg_obj, opt);
8040 if (!NIL_P(env))
8041 rb_execarg_setenv(execarg_obj, env);
8042 }
8043 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8044 modestr = rb_io_oflags_modestr(oflags);
8045
8046 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8047}
8048
8049static VALUE
8050popen_finish(VALUE port, VALUE klass)
8051{
8052 if (NIL_P(port)) {
8053 /* child */
8054 if (rb_block_given_p()) {
8055 rb_protect(rb_yield, Qnil, NULL);
8056 rb_io_flush(rb_ractor_stdout());
8057 rb_io_flush(rb_ractor_stderr());
8058 _exit(0);
8059 }
8060 return Qnil;
8061 }
8062 RBASIC_SET_CLASS(port, klass);
8063 if (rb_block_given_p()) {
8064 return rb_ensure(rb_yield, port, pipe_close, port);
8065 }
8066 return port;
8067}
8068
8069#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8070struct popen_writer_arg {
8071 char *const *argv;
8072 struct popen_arg popen;
8073};
8074
8075static int
8076exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8077{
8078 struct popen_writer_arg *pw = arg;
8079 pw->popen.modef = FMODE_WRITABLE;
8080 popen_redirect(&pw->popen);
8081 execv(pw->argv[0], pw->argv);
8082 strlcpy(errmsg, strerror(errno), buflen);
8083 return -1;
8084}
8085#endif
8086
8087FILE *
8088ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8089{
8090#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8091# ifdef HAVE_WORKING_FORK
8092 struct popen_writer_arg pw;
8093 int *const write_pair = pw.popen.pair;
8094# else
8095 int write_pair[2];
8096# endif
8097
8098#ifdef HAVE_PIPE2
8099 int result = pipe2(write_pair, O_CLOEXEC);
8100#else
8101 int result = pipe(write_pair);
8102#endif
8103
8104 *pid = -1;
8105 if (result == 0) {
8106# ifdef HAVE_WORKING_FORK
8107 pw.argv = argv;
8108 int status;
8109 char errmsg[80] = {'\0'};
8110 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8111# else
8112 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8113 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8114# endif
8115 close(write_pair[0]);
8116 if (*pid < 0) {
8117 close(write_pair[1]);
8118 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8119 }
8120 else {
8121 return fdopen(write_pair[1], "w");
8122 }
8123 }
8124#endif
8125 return NULL;
8126}
8127
8128static VALUE
8129rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8130{
8131 int oflags;
8132 enum rb_io_mode fmode;
8133 struct rb_io_encoding convconfig;
8134 mode_t perm;
8135
8136 FilePathValue(fname);
8137
8138 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8139 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8140
8141 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8142
8143 return io;
8144}
8145
8146/*
8147 * Document-method: File::open
8148 *
8149 * call-seq:
8150 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8151 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8152 *
8153 * Creates a new File object, via File.new with the given arguments.
8154 *
8155 * With no block given, returns the File object.
8156 *
8157 * With a block given, calls the block with the File object
8158 * and returns the block's value.
8159 *
8160 */
8161
8162/*
8163 * Document-method: IO::open
8164 *
8165 * call-seq:
8166 * IO.open(fd, mode = 'r', **opts) -> io
8167 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8168 *
8169 * Creates a new \IO object, via IO.new with the given arguments.
8170 *
8171 * With no block given, returns the \IO object.
8172 *
8173 * With a block given, calls the block with the \IO object
8174 * and returns the block's value.
8175 *
8176 */
8177
8178static VALUE
8179rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8180{
8182
8183 if (rb_block_given_p()) {
8184 return rb_ensure(rb_yield, io, io_close, io);
8185 }
8186
8187 return io;
8188}
8189
8190/*
8191 * call-seq:
8192 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8193 *
8194 * Opens the file at the given path with the given mode and permissions;
8195 * returns the integer file descriptor.
8196 *
8197 * If the file is to be readable, it must exist;
8198 * if the file is to be writable and does not exist,
8199 * it is created with the given permissions:
8200 *
8201 * File.write('t.tmp', '') # => 0
8202 * IO.sysopen('t.tmp') # => 8
8203 * IO.sysopen('t.tmp', 'w') # => 9
8204 *
8205 *
8206 */
8207
8208static VALUE
8209rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8210{
8211 VALUE fname, vmode, vperm;
8212 VALUE intmode;
8213 int oflags, fd;
8214 mode_t perm;
8215
8216 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8217 FilePathValue(fname);
8218
8219 if (NIL_P(vmode))
8220 oflags = O_RDONLY;
8221 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8222 oflags = NUM2INT(intmode);
8223 else {
8224 StringValue(vmode);
8225 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8226 }
8227 if (NIL_P(vperm)) perm = 0666;
8228 else perm = NUM2MODET(vperm);
8229
8230 RB_GC_GUARD(fname) = rb_str_new4(fname);
8231 fd = rb_sysopen(fname, oflags, perm);
8232 return INT2NUM(fd);
8233}
8234
8235/*
8236 * call-seq:
8237 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8238 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8239 *
8240 * Creates an IO object connected to the given file.
8241 *
8242 * This method has potential security vulnerabilities if called with untrusted input;
8243 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
8244 *
8245 * With no block given, file stream is returned:
8246 *
8247 * open('t.txt') # => #<File:t.txt>
8248 *
8249 * With a block given, calls the block with the open file stream,
8250 * then closes the stream:
8251 *
8252 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8253 *
8254 * Output:
8255 *
8256 * #<File:t.txt>
8257 *
8258 * See File.open for details.
8259 *
8260 */
8261
8262static VALUE
8263rb_f_open(int argc, VALUE *argv, VALUE _)
8264{
8265 ID to_open = 0;
8266 int redirect = FALSE;
8267
8268 if (argc >= 1) {
8269 CONST_ID(to_open, "to_open");
8270 if (rb_respond_to(argv[0], to_open)) {
8271 redirect = TRUE;
8272 }
8273 else {
8274 VALUE tmp = argv[0];
8275 FilePathValue(tmp);
8276 if (NIL_P(tmp)) {
8277 redirect = TRUE;
8278 }
8279 else {
8280 argv[0] = tmp;
8281 }
8282 }
8283 }
8284 if (redirect) {
8285 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8286
8287 if (rb_block_given_p()) {
8288 return rb_ensure(rb_yield, io, io_close, io);
8289 }
8290 return io;
8291 }
8292 return rb_io_s_open(argc, argv, rb_cFile);
8293}
8294
8295static VALUE
8296rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8297 const struct rb_io_encoding *convconfig, mode_t perm)
8298{
8299 return rb_file_open_generic(io_alloc(klass), filename,
8300 oflags, fmode, convconfig, perm);
8301}
8302
8303static VALUE
8304rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8305{
8306 int oflags;
8307 enum rb_io_mode fmode;
8308 struct rb_io_encoding convconfig;
8309 mode_t perm;
8310
8311 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8312 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8313 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8314}
8315
8316static VALUE
8317io_reopen(VALUE io, VALUE nfile)
8318{
8319 rb_io_t *fptr, *orig;
8320 int fd, fd2;
8321 rb_off_t pos = 0;
8322
8323 nfile = rb_io_get_io(nfile);
8324 GetOpenFile(io, fptr);
8325 GetOpenFile(nfile, orig);
8326
8327 if (fptr == orig) return io;
8328 if (RUBY_IO_EXTERNAL_P(fptr)) {
8329 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8330 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8331 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8332 rb_raise(rb_eArgError,
8333 "%s can't change access mode from \"%s\" to \"%s\"",
8334 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8335 rb_io_fmode_modestr(orig->mode));
8336 }
8337 }
8338 if (fptr->mode & FMODE_WRITABLE) {
8339 if (io_fflush(fptr) < 0)
8340 rb_sys_fail_on_write(fptr);
8341 }
8342 else {
8343 flush_before_seek(fptr, true);
8344 }
8345 if (orig->mode & FMODE_READABLE) {
8346 pos = io_tell(orig);
8347 }
8348 if (orig->mode & FMODE_WRITABLE) {
8349 if (io_fflush(orig) < 0)
8350 rb_sys_fail_on_write(fptr);
8351 }
8352
8353 /* copy rb_io_t structure */
8354 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8355 fptr->encs = orig->encs;
8356 fptr->pid = orig->pid;
8357 fptr->lineno = orig->lineno;
8358 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8359 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8360 fptr_copy_finalizer(fptr, orig);
8361
8362 fd = fptr->fd;
8363 fd2 = orig->fd;
8364 if (fd != fd2) {
8365 // Interrupt all usage of the old file descriptor:
8366 rb_thread_io_close_interrupt(fptr);
8367 rb_thread_io_close_wait(fptr);
8368
8369 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8370 /* need to keep FILE objects of stdin, stdout and stderr */
8371 if (rb_cloexec_dup2(fd2, fd) < 0)
8372 rb_sys_fail_path(orig->pathv);
8373 rb_update_max_fd(fd);
8374 }
8375 else {
8376 fclose(fptr->stdio_file);
8377 fptr->stdio_file = 0;
8378 fptr->fd = -1;
8379 if (rb_cloexec_dup2(fd2, fd) < 0)
8380 rb_sys_fail_path(orig->pathv);
8381 rb_update_max_fd(fd);
8382 fptr->fd = fd;
8383 }
8384
8385 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8386 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8387 rb_sys_fail_path(fptr->pathv);
8388 }
8389 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8390 rb_sys_fail_path(orig->pathv);
8391 }
8392 }
8393 }
8394
8395 if (fptr->mode & FMODE_BINMODE) {
8396 rb_io_binmode(io);
8397 }
8398
8399 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8400 return io;
8401}
8402
8403#ifdef _WIN32
8404int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8405#else
8406static int
8407rb_freopen(VALUE fname, const char *mode, FILE *fp)
8408{
8409 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8410 RB_GC_GUARD(fname);
8411 return errno;
8412 }
8413 return 0;
8414}
8415#endif
8416
8417/*
8418 * call-seq:
8419 * reopen(other_io) -> self
8420 * reopen(path, mode = 'r', **opts) -> self
8421 *
8422 * Reassociates the stream with another stream,
8423 * which may be of a different class.
8424 * This method may be used to redirect an existing stream
8425 * to a new destination.
8426 *
8427 * With argument +other_io+ given, reassociates with that stream:
8428 *
8429 * # Redirect $stdin from a file.
8430 * f = File.open('t.txt')
8431 * $stdin.reopen(f)
8432 * f.close
8433 *
8434 * # Redirect $stdout to a file.
8435 * f = File.open('t.tmp', 'w')
8436 * $stdout.reopen(f)
8437 * f.close
8438 *
8439 * With argument +path+ given, reassociates with a new stream to that file path:
8440 *
8441 * $stdin.reopen('t.txt')
8442 * $stdout.reopen('t.tmp', 'w')
8443 *
8444 * Optional keyword arguments +opts+ specify:
8445 *
8446 * - {Open Options}[rdoc-ref:IO@Open+Options].
8447 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8448 *
8449 */
8450
8451static VALUE
8452rb_io_reopen(int argc, VALUE *argv, VALUE file)
8453{
8454 VALUE fname, nmode, opt;
8455 int oflags;
8456 rb_io_t *fptr;
8457
8458 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8459 VALUE tmp = rb_io_check_io(fname);
8460 if (!NIL_P(tmp)) {
8461 return io_reopen(file, tmp);
8462 }
8463 }
8464
8465 FilePathValue(fname);
8466 rb_io_taint_check(file);
8467 fptr = RFILE(file)->fptr;
8468 if (!fptr) {
8469 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8470 }
8471
8472 if (!NIL_P(nmode) || !NIL_P(opt)) {
8473 enum rb_io_mode fmode;
8474 struct rb_io_encoding convconfig;
8475
8476 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8477 if (RUBY_IO_EXTERNAL_P(fptr) &&
8478 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8479 (fptr->mode & FMODE_READWRITE)) {
8480 rb_raise(rb_eArgError,
8481 "%s can't change access mode from \"%s\" to \"%s\"",
8482 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8483 rb_io_fmode_modestr(fmode));
8484 }
8485 fptr->mode = fmode;
8486 fptr->encs = convconfig;
8487 }
8488 else {
8489 oflags = rb_io_fmode_oflags(fptr->mode);
8490 }
8491
8492 fptr->pathv = fname;
8493 if (fptr->fd < 0) {
8494 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8495 fptr->stdio_file = 0;
8496 return file;
8497 }
8498
8499 if (fptr->mode & FMODE_WRITABLE) {
8500 if (io_fflush(fptr) < 0)
8501 rb_sys_fail_on_write(fptr);
8502 }
8503 fptr->rbuf.off = fptr->rbuf.len = 0;
8504
8505 if (fptr->stdio_file) {
8506 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8507 rb_io_oflags_modestr(oflags),
8508 fptr->stdio_file);
8509 if (e) rb_syserr_fail_path(e, fptr->pathv);
8510 fptr->fd = fileno(fptr->stdio_file);
8511 rb_fd_fix_cloexec(fptr->fd);
8512#ifdef USE_SETVBUF
8513 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8514 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8515#endif
8516 if (fptr->stdio_file == stderr) {
8517 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8518 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8519 }
8520 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8521 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8522 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8523 }
8524 }
8525 else {
8526 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8527 int err = 0;
8528 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8529 err = errno;
8530 (void)close(tmpfd);
8531 if (err) {
8532 rb_syserr_fail_path(err, fptr->pathv);
8533 }
8534 }
8535
8536 return file;
8537}
8538
8539/* :nodoc: */
8540static VALUE
8541rb_io_init_copy(VALUE dest, VALUE io)
8542{
8543 rb_io_t *fptr, *orig;
8544 int fd;
8545 VALUE write_io;
8546 rb_off_t pos;
8547
8548 io = rb_io_get_io(io);
8549 if (!OBJ_INIT_COPY(dest, io)) return dest;
8550 GetOpenFile(io, orig);
8551 MakeOpenFile(dest, fptr);
8552
8553 rb_io_flush(io);
8554
8555 /* copy rb_io_t structure */
8556 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8557 fptr->encs = orig->encs;
8558 fptr->pid = orig->pid;
8559 fptr->lineno = orig->lineno;
8560 fptr->timeout = orig->timeout;
8561
8562 ccan_list_head_init(&fptr->blocking_operations);
8563 fptr->closing_ec = NULL;
8564 fptr->wakeup_mutex = Qnil;
8565 fptr->fork_generation = GET_VM()->fork_gen;
8566
8567 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8568 fptr_copy_finalizer(fptr, orig);
8569
8570 fd = ruby_dup(orig->fd);
8571 fptr->fd = fd;
8572 pos = io_tell(orig);
8573 if (0 <= pos)
8574 io_seek(fptr, pos, SEEK_SET);
8575 if (fptr->mode & FMODE_BINMODE) {
8576 rb_io_binmode(dest);
8577 }
8578
8579 write_io = GetWriteIO(io);
8580 if (io != write_io) {
8581 write_io = rb_obj_dup(write_io);
8582 fptr->tied_io_for_writing = write_io;
8583 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8584 }
8585
8586 return dest;
8587}
8588
8589/*
8590 * call-seq:
8591 * printf(format_string, *objects) -> nil
8592 *
8593 * Formats and writes +objects+ to the stream.
8594 *
8595 * For details on +format_string+, see
8596 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8597 *
8598 */
8599
8600VALUE
8601rb_io_printf(int argc, const VALUE *argv, VALUE out)
8602{
8603 rb_io_write(out, rb_f_sprintf(argc, argv));
8604 return Qnil;
8605}
8606
8607/*
8608 * call-seq:
8609 * printf(format_string, *objects) -> nil
8610 * printf(io, format_string, *objects) -> nil
8611 *
8612 * Equivalent to:
8613 *
8614 * io.write(sprintf(format_string, *objects))
8615 *
8616 * For details on +format_string+, see
8617 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8618 *
8619 * With the single argument +format_string+, formats +objects+ into the string,
8620 * then writes the formatted string to $stdout:
8621 *
8622 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8623 *
8624 * Output (on $stdout):
8625 *
8626 * 0024 24 24.00#
8627 *
8628 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8629 * then writes the formatted string to +io+:
8630 *
8631 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8632 *
8633 * Output (on $stderr):
8634 *
8635 * 0024 24 24.00# => nil
8636 *
8637 * With no arguments, does nothing.
8638 *
8639 */
8640
8641static VALUE
8642rb_f_printf(int argc, VALUE *argv, VALUE _)
8643{
8644 VALUE out;
8645
8646 if (argc == 0) return Qnil;
8647 if (RB_TYPE_P(argv[0], T_STRING)) {
8648 out = rb_ractor_stdout();
8649 }
8650 else {
8651 out = argv[0];
8652 argv++;
8653 argc--;
8654 }
8655 rb_io_write(out, rb_f_sprintf(argc, argv));
8656
8657 return Qnil;
8658}
8659
8660extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
8661
8662static void
8663deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8664{
8665 rb_deprecated_str_setter(val, id, &val);
8666 if (!NIL_P(val)) {
8667 if (rb_str_equal(val, rb_default_rs)) {
8668 val = rb_default_rs;
8669 }
8670 else {
8671 val = rb_str_frozen_bare_string(val);
8672 }
8673 }
8674 *var = val;
8675}
8676
8677/*
8678 * call-seq:
8679 * print(*objects) -> nil
8680 *
8681 * Writes the given objects to the stream; returns +nil+.
8682 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8683 * (<tt>$\</tt>), if it is not +nil+.
8684 * See {Line IO}[rdoc-ref:IO@Line+IO].
8685 *
8686 * With argument +objects+ given, for each object:
8687 *
8688 * - Converts via its method +to_s+ if not a string.
8689 * - Writes to the stream.
8690 * - If not the last object, writes the output field separator
8691 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8692 *
8693 * With default separators:
8694 *
8695 * f = File.open('t.tmp', 'w+')
8696 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8697 * p $OUTPUT_RECORD_SEPARATOR
8698 * p $OUTPUT_FIELD_SEPARATOR
8699 * f.print(*objects)
8700 * f.rewind
8701 * p f.read
8702 * f.close
8703 *
8704 * Output:
8705 *
8706 * nil
8707 * nil
8708 * "00.00/10+0izerozero"
8709 *
8710 * With specified separators:
8711 *
8712 * $\ = "\n"
8713 * $, = ','
8714 * f.rewind
8715 * f.print(*objects)
8716 * f.rewind
8717 * p f.read
8718 *
8719 * Output:
8720 *
8721 * "0,0.0,0/1,0+0i,zero,zero\n"
8722 *
8723 * With no argument given, writes the content of <tt>$_</tt>
8724 * (which is usually the most recent user input):
8725 *
8726 * f = File.open('t.tmp', 'w+')
8727 * gets # Sets $_ to the most recent user input.
8728 * f.print
8729 * f.close
8730 *
8731 */
8732
8733VALUE
8734rb_io_print(int argc, const VALUE *argv, VALUE out)
8735{
8736 int i;
8737 VALUE line;
8738
8739 /* if no argument given, print `$_' */
8740 if (argc == 0) {
8741 argc = 1;
8742 line = rb_lastline_get();
8743 argv = &line;
8744 }
8745 if (argc > 1 && !NIL_P(rb_output_fs)) {
8746 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8747 }
8748 for (i=0; i<argc; i++) {
8749 if (!NIL_P(rb_output_fs) && i>0) {
8750 rb_io_write(out, rb_output_fs);
8751 }
8752 rb_io_write(out, argv[i]);
8753 }
8754 if (argc > 0 && !NIL_P(rb_output_rs)) {
8755 rb_io_write(out, rb_output_rs);
8756 }
8757
8758 return Qnil;
8759}
8760
8761/*
8762 * call-seq:
8763 * print(*objects) -> nil
8764 *
8765 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8766 * this method is the straightforward way to write to <tt>$stdout</tt>.
8767 *
8768 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8769 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8770 * <tt>$\</tt>), if it is not +nil+.
8771 *
8772 * With argument +objects+ given, for each object:
8773 *
8774 * - Converts via its method +to_s+ if not a string.
8775 * - Writes to <tt>stdout</tt>.
8776 * - If not the last object, writes the output field separator
8777 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8778 *
8779 * With default separators:
8780 *
8781 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8782 * $OUTPUT_RECORD_SEPARATOR
8783 * $OUTPUT_FIELD_SEPARATOR
8784 * print(*objects)
8785 *
8786 * Output:
8787 *
8788 * nil
8789 * nil
8790 * 00.00/10+0izerozero
8791 *
8792 * With specified separators:
8793 *
8794 * $OUTPUT_RECORD_SEPARATOR = "\n"
8795 * $OUTPUT_FIELD_SEPARATOR = ','
8796 * print(*objects)
8797 *
8798 * Output:
8799 *
8800 * 0,0.0,0/1,0+0i,zero,zero
8801 *
8802 * With no argument given, writes the content of <tt>$_</tt>
8803 * (which is usually the most recent user input):
8804 *
8805 * gets # Sets $_ to the most recent user input.
8806 * print # Prints $_.
8807 *
8808 */
8809
8810static VALUE
8811rb_f_print(int argc, const VALUE *argv, VALUE _)
8812{
8813 rb_io_print(argc, argv, rb_ractor_stdout());
8814 return Qnil;
8815}
8816
8817/*
8818 * call-seq:
8819 * putc(object) -> object
8820 *
8821 * Writes a character to the stream.
8822 * See {Character IO}[rdoc-ref:IO@Character+IO].
8823 *
8824 * If +object+ is numeric, converts to integer if necessary,
8825 * then writes the character whose code is the
8826 * least significant byte;
8827 * if +object+ is a string, writes the first character:
8828 *
8829 * $stdout.putc "A"
8830 * $stdout.putc 65
8831 *
8832 * Output:
8833 *
8834 * AA
8835 *
8836 */
8837
8838static VALUE
8839rb_io_putc(VALUE io, VALUE ch)
8840{
8841 VALUE str;
8842 if (RB_TYPE_P(ch, T_STRING)) {
8843 str = rb_str_substr(ch, 0, 1);
8844 }
8845 else {
8846 char c = NUM2CHR(ch);
8847 str = rb_str_new(&c, 1);
8848 }
8849 rb_io_write(io, str);
8850 return ch;
8851}
8852
8853#define forward(obj, id, argc, argv) \
8854 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8855#define forward_public(obj, id, argc, argv) \
8856 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8857#define forward_current(id, argc, argv) \
8858 forward_public(ARGF.current_file, id, argc, argv)
8859
8860/*
8861 * call-seq:
8862 * putc(int) -> int
8863 *
8864 * Equivalent to:
8865 *
8866 * $stdout.putc(int)
8867 *
8868 * See IO#putc for important information regarding multi-byte characters.
8869 *
8870 */
8871
8872static VALUE
8873rb_f_putc(VALUE recv, VALUE ch)
8874{
8875 VALUE r_stdout = rb_ractor_stdout();
8876 if (recv == r_stdout) {
8877 return rb_io_putc(recv, ch);
8878 }
8879 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8880}
8881
8882
8883int
8884rb_str_end_with_asciichar(VALUE str, int c)
8885{
8886 long len = RSTRING_LEN(str);
8887 const char *ptr = RSTRING_PTR(str);
8888 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8889 int n;
8890
8891 if (len == 0) return 0;
8892 if ((n = rb_enc_mbminlen(enc)) == 1) {
8893 return ptr[len - 1] == c;
8894 }
8895 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8896}
8897
8898static VALUE
8899io_puts_ary(VALUE ary, VALUE out, int recur)
8900{
8901 VALUE tmp;
8902 long i;
8903
8904 if (recur) {
8905 tmp = rb_str_new2("[...]");
8906 rb_io_puts(1, &tmp, out);
8907 return Qtrue;
8908 }
8909 ary = rb_check_array_type(ary);
8910 if (NIL_P(ary)) return Qfalse;
8911 for (i=0; i<RARRAY_LEN(ary); i++) {
8912 tmp = RARRAY_AREF(ary, i);
8913 rb_io_puts(1, &tmp, out);
8914 }
8915 return Qtrue;
8916}
8917
8918/*
8919 * call-seq:
8920 * puts(*objects) -> nil
8921 *
8922 * Writes the given +objects+ to the stream, which must be open for writing;
8923 * returns +nil+.\
8924 * Writes a newline after each that does not already end with a newline sequence.
8925 * If called without arguments, writes a newline.
8926 * See {Line IO}[rdoc-ref:IO@Line+IO].
8927 *
8928 * Note that each added newline is the character <tt>"\n"<//tt>,
8929 * not the output record separator (<tt>$\</tt>).
8930 *
8931 * Treatment for each object:
8932 *
8933 * - String: writes the string.
8934 * - Neither string nor array: writes <tt>object.to_s</tt>.
8935 * - Array: writes each element of the array; arrays may be nested.
8936 *
8937 * To keep these examples brief, we define this helper method:
8938 *
8939 * def show(*objects)
8940 * # Puts objects to file.
8941 * f = File.new('t.tmp', 'w+')
8942 * f.puts(objects)
8943 * # Return file content.
8944 * f.rewind
8945 * p f.read
8946 * f.close
8947 * end
8948 *
8949 * # Strings without newlines.
8950 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8951 * # Strings, some with newlines.
8952 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8953 *
8954 * # Neither strings nor arrays:
8955 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8956 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8957 *
8958 * # Array of strings.
8959 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8960 * # Nested arrays.
8961 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8962 *
8963 */
8964
8965VALUE
8966rb_io_puts(int argc, const VALUE *argv, VALUE out)
8967{
8968 VALUE line, args[2];
8969
8970 /* if no argument given, print newline. */
8971 if (argc == 0) {
8972 rb_io_write(out, rb_default_rs);
8973 return Qnil;
8974 }
8975 for (int i = 0; i < argc; i++) {
8976 // Convert the argument to a string:
8977 if (RB_TYPE_P(argv[i], T_STRING)) {
8978 line = argv[i];
8979 }
8980 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8981 continue;
8982 }
8983 else {
8984 line = rb_obj_as_string(argv[i]);
8985 }
8986
8987 // Write the line:
8988 int n = 0;
8989 if (RSTRING_LEN(line) == 0) {
8990 args[n++] = rb_default_rs;
8991 }
8992 else {
8993 args[n++] = line;
8994 if (!rb_str_end_with_asciichar(line, '\n')) {
8995 args[n++] = rb_default_rs;
8996 }
8997 }
8998
8999 rb_io_writev(out, n, args);
9000 }
9001
9002 return Qnil;
9003}
9004
9005/*
9006 * call-seq:
9007 * puts(*objects) -> nil
9008 *
9009 * Equivalent to
9010 *
9011 * $stdout.puts(objects)
9012 */
9013
9014static VALUE
9015rb_f_puts(int argc, VALUE *argv, VALUE recv)
9016{
9017 VALUE r_stdout = rb_ractor_stdout();
9018 if (recv == r_stdout) {
9019 return rb_io_puts(argc, argv, recv);
9020 }
9021 return forward(r_stdout, rb_intern("puts"), argc, argv);
9022}
9023
9024static VALUE
9025rb_p_write(VALUE str)
9026{
9027 VALUE args[2];
9028 args[0] = str;
9029 args[1] = rb_default_rs;
9030 VALUE r_stdout = rb_ractor_stdout();
9031 if (RB_TYPE_P(r_stdout, T_FILE) &&
9032 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9033 io_writev(2, args, r_stdout);
9034 }
9035 else {
9036 rb_io_writev(r_stdout, 2, args);
9037 }
9038 return Qnil;
9039}
9040
9041void
9042rb_p(VALUE obj) /* for debug print within C code */
9043{
9044 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9045}
9046
9047static VALUE
9048rb_p_result(int argc, const VALUE *argv)
9049{
9050 VALUE ret = Qnil;
9051
9052 if (argc == 1) {
9053 ret = argv[0];
9054 }
9055 else if (argc > 1) {
9056 ret = rb_ary_new4(argc, argv);
9057 }
9058 VALUE r_stdout = rb_ractor_stdout();
9059 if (RB_TYPE_P(r_stdout, T_FILE)) {
9060 rb_uninterruptible(rb_io_flush, r_stdout);
9061 }
9062 return ret;
9063}
9064
9065/*
9066 * call-seq:
9067 * p(object) -> obj
9068 * p(*objects) -> array of objects
9069 * p -> nil
9070 *
9071 * For each object +obj+, executes:
9072 *
9073 * $stdout.write(obj.inspect, "\n")
9074 *
9075 * With one object given, returns the object;
9076 * with multiple objects given, returns an array containing the objects;
9077 * with no object given, returns +nil+.
9078 *
9079 * Examples:
9080 *
9081 * r = Range.new(0, 4)
9082 * p r # => 0..4
9083 * p [r, r, r] # => [0..4, 0..4, 0..4]
9084 * p # => nil
9085 *
9086 * Output:
9087 *
9088 * 0..4
9089 * [0..4, 0..4, 0..4]
9090 *
9091 * Kernel#p is designed for debugging purposes.
9092 * Ruby implementations may define Kernel#p to be uninterruptible
9093 * in whole or in part.
9094 * On CRuby, Kernel#p's writing of data is uninterruptible.
9095 */
9096
9097static VALUE
9098rb_f_p(int argc, VALUE *argv, VALUE self)
9099{
9100 int i;
9101 for (i=0; i<argc; i++) {
9102 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9103 rb_uninterruptible(rb_p_write, inspected);
9104 }
9105 return rb_p_result(argc, argv);
9106}
9107
9108/*
9109 * call-seq:
9110 * display(port = $>) -> nil
9111 *
9112 * Writes +self+ on the given port:
9113 *
9114 * 1.display
9115 * "cat".display
9116 * [ 4, 5, 6 ].display
9117 * puts
9118 *
9119 * Output:
9120 *
9121 * 1cat[4, 5, 6]
9122 *
9123 */
9124
9125static VALUE
9126rb_obj_display(int argc, VALUE *argv, VALUE self)
9127{
9128 VALUE out;
9129
9130 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9131 rb_io_write(out, self);
9132
9133 return Qnil;
9134}
9135
9136static int
9137rb_stderr_to_original_p(VALUE err)
9138{
9139 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9140}
9141
9142void
9143rb_write_error2(const char *mesg, long len)
9144{
9145 VALUE out = rb_ractor_stderr();
9146 if (rb_stderr_to_original_p(out)) {
9147#ifdef _WIN32
9148 if (isatty(fileno(stderr))) {
9149 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9150 }
9151#endif
9152 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9153 /* failed to write to stderr, what can we do? */
9154 return;
9155 }
9156 }
9157 else {
9158 rb_io_write(out, rb_str_new(mesg, len));
9159 }
9160}
9161
9162void
9163rb_write_error(const char *mesg)
9164{
9165 rb_write_error2(mesg, strlen(mesg));
9166}
9167
9168void
9169rb_write_error_str(VALUE mesg)
9170{
9171 VALUE out = rb_ractor_stderr();
9172 /* a stopgap measure for the time being */
9173 if (rb_stderr_to_original_p(out)) {
9174 size_t len = (size_t)RSTRING_LEN(mesg);
9175#ifdef _WIN32
9176 if (isatty(fileno(stderr))) {
9177 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9178 }
9179#endif
9180 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9181 RB_GC_GUARD(mesg);
9182 return;
9183 }
9184 }
9185 else {
9186 /* may unlock GVL, and */
9187 rb_io_write(out, mesg);
9188 }
9189}
9190
9191int
9192rb_stderr_tty_p(void)
9193{
9194 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9195 return isatty(fileno(stderr));
9196 return 0;
9197}
9198
9199static void
9200must_respond_to(ID mid, VALUE val, ID id)
9201{
9202 if (!rb_respond_to(val, mid)) {
9203 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9204 rb_id2str(id), rb_id2str(mid),
9205 rb_obj_class(val));
9206 }
9207}
9208
9209static void
9210stdin_setter(VALUE val, ID id, VALUE *ptr)
9211{
9213}
9214
9215static VALUE
9216stdin_getter(ID id, VALUE *ptr)
9217{
9218 return rb_ractor_stdin();
9219}
9220
9221static void
9222stdout_setter(VALUE val, ID id, VALUE *ptr)
9223{
9224 must_respond_to(id_write, val, id);
9226}
9227
9228static VALUE
9229stdout_getter(ID id, VALUE *ptr)
9230{
9231 return rb_ractor_stdout();
9232}
9233
9234static void
9235stderr_setter(VALUE val, ID id, VALUE *ptr)
9236{
9237 must_respond_to(id_write, val, id);
9239}
9240
9241static VALUE
9242stderr_getter(ID id, VALUE *ptr)
9243{
9244 return rb_ractor_stderr();
9245}
9246
9247static VALUE
9248allocate_and_open_new_file(VALUE klass)
9249{
9250 VALUE self = io_alloc(klass);
9251 rb_io_make_open_file(self);
9252 return self;
9253}
9254
9255VALUE
9256rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9257{
9258 int state;
9259 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9260 if (state) {
9261 /* if we raised an exception allocating an IO object, but the caller
9262 intended to transfer ownership of this FD to us, close the fd before
9263 raising the exception. Otherwise, we would leak a FD - the caller
9264 expects GC to close the file, but we never got around to assigning
9265 it to a rb_io. */
9266 if (!(mode & FMODE_EXTERNAL)) {
9267 maygvl_close(descriptor, 0);
9268 }
9269 rb_jump_tag(state);
9270 }
9271
9272
9273 rb_io_t *io = RFILE(self)->fptr;
9274 io->self = self;
9275 io->fd = descriptor;
9276 io->mode = mode;
9277
9278 /* At this point, Ruby fully owns the descriptor, and will close it when
9279 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9280 in the rest of this method. */
9281
9282 if (NIL_P(path)) {
9283 io->pathv = Qnil;
9284 }
9285 else {
9286 StringValue(path);
9287 io->pathv = rb_str_new_frozen(path);
9288 }
9289
9290 io->timeout = timeout;
9291
9292 ccan_list_head_init(&io->blocking_operations);
9293 io->closing_ec = NULL;
9294 io->wakeup_mutex = Qnil;
9295 io->fork_generation = GET_VM()->fork_gen;
9296
9297 if (encoding) {
9298 io->encs = *encoding;
9299 }
9300
9301 rb_update_max_fd(descriptor);
9302
9303 return self;
9304}
9305
9306static VALUE
9307prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9308{
9309 VALUE path_value = Qnil;
9310 rb_encoding *e;
9311 struct rb_io_encoding convconfig;
9312
9313 if (path) {
9314 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9315 }
9316
9317 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9318 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9319 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9322#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9323 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9324 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9325 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9326#endif
9327 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9328 convconfig.ecopts = Qnil;
9329
9330 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9331 rb_io_t*io = RFILE(self)->fptr;
9332
9333 if (!io_check_tty(io)) {
9334#ifdef __CYGWIN__
9335 io->mode |= FMODE_BINMODE;
9336 setmode(fd, O_BINARY);
9337#endif
9338 }
9339
9340 return self;
9341}
9342
9343VALUE
9344rb_io_fdopen(int fd, int oflags, const char *path)
9345{
9346 VALUE klass = rb_cIO;
9347
9348 if (path && strcmp(path, "-")) klass = rb_cFile;
9349 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9350}
9351
9352static VALUE
9353prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9354{
9355 rb_io_t *fptr;
9356 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9357
9358 GetOpenFile(io, fptr);
9360#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9361 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9362 if (fmode & FMODE_READABLE) {
9364 }
9365#endif
9366 fptr->stdio_file = f;
9367
9368 return io;
9369}
9370
9371VALUE
9372rb_io_prep_stdin(void)
9373{
9374 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9375}
9376
9377VALUE
9378rb_io_prep_stdout(void)
9379{
9380 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9381}
9382
9383VALUE
9384rb_io_prep_stderr(void)
9385{
9386 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9387}
9388
9389FILE *
9391{
9392 if (!fptr->stdio_file) {
9393 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9394 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9395 }
9396 return fptr->stdio_file;
9397}
9398
9399static inline void
9400rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9401{
9402 buf->ptr = NULL;
9403 buf->off = 0;
9404 buf->len = 0;
9405 buf->capa = 0;
9406}
9407
9408static inline rb_io_t *
9409rb_io_fptr_new(void)
9410{
9411 rb_io_t *fp = ALLOC(rb_io_t);
9412 fp->self = Qnil;
9413 fp->fd = -1;
9414 fp->stdio_file = NULL;
9415 fp->mode = 0;
9416 fp->pid = 0;
9417 fp->lineno = 0;
9418 fp->pathv = Qnil;
9419 fp->finalize = 0;
9420 rb_io_buffer_init(&fp->wbuf);
9421 rb_io_buffer_init(&fp->rbuf);
9422 rb_io_buffer_init(&fp->cbuf);
9423 fp->readconv = NULL;
9424 fp->writeconv = NULL;
9426 fp->writeconv_pre_ecflags = 0;
9428 fp->writeconv_initialized = 0;
9429 fp->tied_io_for_writing = 0;
9430 fp->encs.enc = NULL;
9431 fp->encs.enc2 = NULL;
9432 fp->encs.ecflags = 0;
9433 fp->encs.ecopts = Qnil;
9434 fp->write_lock = Qnil;
9435 fp->timeout = Qnil;
9436 ccan_list_head_init(&fp->blocking_operations);
9437 fp->closing_ec = NULL;
9438 fp->wakeup_mutex = Qnil;
9439 fp->fork_generation = GET_VM()->fork_gen;
9440 return fp;
9441}
9442
9443rb_io_t *
9444rb_io_make_open_file(VALUE obj)
9445{
9446 rb_io_t *fp = 0;
9447
9448 Check_Type(obj, T_FILE);
9449 if (RFILE(obj)->fptr) {
9450 rb_io_close(obj);
9451 rb_io_fptr_finalize(RFILE(obj)->fptr);
9452 RFILE(obj)->fptr = 0;
9453 }
9454 fp = rb_io_fptr_new();
9455 fp->self = obj;
9456 RFILE(obj)->fptr = fp;
9457 return fp;
9458}
9459
9460static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9461
9462/*
9463 * call-seq:
9464 * IO.new(fd, mode = 'r', **opts) -> io
9465 *
9466 * Creates and returns a new \IO object (file stream) from a file descriptor.
9467 *
9468 * \IO.new may be useful for interaction with low-level libraries.
9469 * For higher-level interactions, it may be simpler to create
9470 * the file stream using File.open.
9471 *
9472 * Argument +fd+ must be a valid file descriptor (integer):
9473 *
9474 * path = 't.tmp'
9475 * fd = IO.sysopen(path) # => 3
9476 * IO.new(fd) # => #<IO:fd 3>
9477 *
9478 * The new \IO object does not inherit encoding
9479 * (because the integer file descriptor does not have an encoding):
9480 *
9481 * fd = IO.sysopen('t.rus', 'rb')
9482 * io = IO.new(fd)
9483 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9484 *
9485 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9486 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9487 *
9488 * IO.new(fd, 'w') # => #<IO:fd 3>
9489 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9490 *
9491 * Optional keyword arguments +opts+ specify:
9492 *
9493 * - {Open Options}[rdoc-ref:IO@Open+Options].
9494 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9495 *
9496 * Examples:
9497 *
9498 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9499 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9500 *
9501 */
9502
9503static VALUE
9504rb_io_initialize(int argc, VALUE *argv, VALUE io)
9505{
9506 VALUE fnum, vmode;
9507 VALUE opt;
9508
9509 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9510 return io_initialize(io, fnum, vmode, opt);
9511}
9512
9513static VALUE
9514io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9515{
9516 rb_io_t *fp;
9517 int fd, oflags = O_RDONLY;
9518 enum rb_io_mode fmode;
9519 struct rb_io_encoding convconfig;
9520#if defined(HAVE_FCNTL) && defined(F_GETFL)
9521 int ofmode;
9522#else
9523 struct stat st;
9524#endif
9525
9526 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9527
9528 fd = NUM2INT(fnum);
9529 if (rb_reserved_fd_p(fd)) {
9530 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9531 }
9532#if defined(HAVE_FCNTL) && defined(F_GETFL)
9533 oflags = fcntl(fd, F_GETFL);
9534 if (oflags == -1) rb_sys_fail(0);
9535#else
9536 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9537#endif
9538 rb_update_max_fd(fd);
9539#if defined(HAVE_FCNTL) && defined(F_GETFL)
9540 ofmode = rb_io_oflags_fmode(oflags);
9541 if (NIL_P(vmode)) {
9542 fmode = ofmode;
9543 }
9544 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9545 VALUE error = INT2FIX(EINVAL);
9547 }
9548#endif
9549 VALUE path = Qnil;
9550
9551 if (!NIL_P(opt)) {
9552 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9553 fmode |= FMODE_EXTERNAL;
9554 }
9555
9556 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9557 if (!NIL_P(path)) {
9558 StringValue(path);
9559 path = rb_str_new_frozen(path);
9560 }
9561 }
9562
9563 MakeOpenFile(io, fp);
9564 fp->self = io;
9565 fp->fd = fd;
9566 fp->mode = fmode;
9567 fp->encs = convconfig;
9568 fp->pathv = path;
9569 fp->timeout = Qnil;
9570 ccan_list_head_init(&fp->blocking_operations);
9571 fp->closing_ec = NULL;
9572 fp->wakeup_mutex = Qnil;
9573 fp->fork_generation = GET_VM()->fork_gen;
9574 clear_codeconv(fp);
9575 io_check_tty(fp);
9576 if (fileno(stdin) == fd)
9577 fp->stdio_file = stdin;
9578 else if (fileno(stdout) == fd)
9579 fp->stdio_file = stdout;
9580 else if (fileno(stderr) == fd)
9581 fp->stdio_file = stderr;
9582
9583 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9584 return io;
9585}
9586
9587/*
9588 * call-seq:
9589 * set_encoding_by_bom -> encoding or nil
9590 *
9591 * If the stream begins with a BOM
9592 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9593 * consumes the BOM and sets the external encoding accordingly;
9594 * returns the result encoding if found, or +nil+ otherwise:
9595 *
9596 * File.write('t.tmp', "\u{FEFF}abc")
9597 * io = File.open('t.tmp', 'rb')
9598 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9599 * io.close
9600 *
9601 * File.write('t.tmp', 'abc')
9602 * io = File.open('t.tmp', 'rb')
9603 * io.set_encoding_by_bom # => nil
9604 * io.close
9605 *
9606 * Raises an exception if the stream is not binmode
9607 * or its encoding has already been set.
9608 *
9609 */
9610
9611static VALUE
9612rb_io_set_encoding_by_bom(VALUE io)
9613{
9614 rb_io_t *fptr;
9615
9616 GetOpenFile(io, fptr);
9617 if (!(fptr->mode & FMODE_BINMODE)) {
9618 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9619 }
9620 if (fptr->encs.enc2) {
9621 rb_raise(rb_eArgError, "encoding conversion is set");
9622 }
9623 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9624 rb_raise(rb_eArgError, "encoding is set to %s already",
9625 rb_enc_name(fptr->encs.enc));
9626 }
9627 if (!io_set_encoding_by_bom(io)) return Qnil;
9628 return rb_enc_from_encoding(fptr->encs.enc);
9629}
9630
9631/*
9632 * call-seq:
9633 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9634 *
9635 * Opens the file at the given +path+ according to the given +mode+;
9636 * creates and returns a new File object for that file.
9637 *
9638 * The new File object is buffered mode (or non-sync mode), unless
9639 * +filename+ is a tty.
9640 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9641 *
9642 * Argument +path+ must be a valid file path:
9643 *
9644 * f = File.new('/etc/fstab')
9645 * f.close
9646 * f = File.new('t.txt')
9647 * f.close
9648 *
9649 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9650 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9651 *
9652 * f = File.new('t.tmp', 'w')
9653 * f.close
9654 * f = File.new('t.tmp', File::RDONLY)
9655 * f.close
9656 *
9657 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9658 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9659 *
9660 * f = File.new('t.tmp', File::CREAT, 0644)
9661 * f.close
9662 * f = File.new('t.tmp', File::CREAT, 0444)
9663 * f.close
9664 *
9665 * Optional keyword arguments +opts+ specify:
9666 *
9667 * - {Open Options}[rdoc-ref:IO@Open+Options].
9668 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9669 *
9670 */
9671
9672static VALUE
9673rb_file_initialize(int argc, VALUE *argv, VALUE io)
9674{
9675 if (RFILE(io)->fptr) {
9676 rb_raise(rb_eRuntimeError, "reinitializing File");
9677 }
9678 VALUE fname, vmode, vperm, opt;
9679 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9680 if (posargc < 3) { /* perm is File only */
9681 VALUE fd = rb_check_to_int(fname);
9682
9683 if (!NIL_P(fd)) {
9684 return io_initialize(io, fd, vmode, opt);
9685 }
9686 }
9687 return rb_open_file(io, fname, vmode, vperm, opt);
9688}
9689
9690/* :nodoc: */
9691static VALUE
9692rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9693{
9694 if (rb_block_given_p()) {
9695 VALUE cname = rb_obj_as_string(klass);
9696
9697 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9698 cname, cname);
9699 }
9700 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9701}
9702
9703
9704/*
9705 * call-seq:
9706 * IO.for_fd(fd, mode = 'r', **opts) -> io
9707 *
9708 * Synonym for IO.new.
9709 *
9710 */
9711
9712static VALUE
9713rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9714{
9715 VALUE io = rb_obj_alloc(klass);
9716 rb_io_initialize(argc, argv, io);
9717 return io;
9718}
9719
9720/*
9721 * call-seq:
9722 * ios.autoclose? -> true or false
9723 *
9724 * Returns +true+ if the underlying file descriptor of _ios_ will be
9725 * closed at its finalization or at calling #close, otherwise +false+.
9726 */
9727
9728static VALUE
9729rb_io_autoclose_p(VALUE io)
9730{
9731 rb_io_t *fptr = RFILE(io)->fptr;
9732 rb_io_check_closed(fptr);
9733 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9734}
9735
9736/*
9737 * call-seq:
9738 * io.autoclose = bool -> true or false
9739 *
9740 * Sets auto-close flag.
9741 *
9742 * f = File.open(File::NULL)
9743 * IO.for_fd(f.fileno).close
9744 * f.gets # raises Errno::EBADF
9745 *
9746 * f = File.open(File::NULL)
9747 * g = IO.for_fd(f.fileno)
9748 * g.autoclose = false
9749 * g.close
9750 * f.gets # won't cause Errno::EBADF
9751 */
9752
9753static VALUE
9754rb_io_set_autoclose(VALUE io, VALUE autoclose)
9755{
9756 rb_io_t *fptr;
9757 GetOpenFile(io, fptr);
9758 if (!RTEST(autoclose))
9759 fptr->mode |= FMODE_EXTERNAL;
9760 else
9761 fptr->mode &= ~FMODE_EXTERNAL;
9762 return autoclose;
9763}
9764
9765static VALUE
9766io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9767{
9768 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9769
9770 if (!RB_TEST(result)) {
9771 return Qnil;
9772 }
9773
9774 int mask = RB_NUM2INT(result);
9775
9776 if (mask & event) {
9777 if (return_io)
9778 return io;
9779 else
9780 return result;
9781 }
9782 else {
9783 return Qfalse;
9784 }
9785}
9786
9787/*
9788 * call-seq:
9789 * io.wait_readable -> truthy or falsy
9790 * io.wait_readable(timeout) -> truthy or falsy
9791 *
9792 * Waits until IO is readable and returns a truthy value, or a falsy
9793 * value when times out. Returns a truthy value immediately when
9794 * buffered data is available.
9795 */
9796
9797static VALUE
9798io_wait_readable(int argc, VALUE *argv, VALUE io)
9799{
9800 rb_io_t *fptr;
9801
9802 RB_IO_POINTER(io, fptr);
9804
9805 if (rb_io_read_pending(fptr)) return Qtrue;
9806
9807 rb_check_arity(argc, 0, 1);
9808 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9809
9810 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9811}
9812
9813/*
9814 * call-seq:
9815 * io.wait_writable -> truthy or falsy
9816 * io.wait_writable(timeout) -> truthy or falsy
9817 *
9818 * Waits until IO is writable and returns a truthy value or a falsy
9819 * value when times out.
9820 */
9821static VALUE
9822io_wait_writable(int argc, VALUE *argv, VALUE io)
9823{
9824 rb_io_t *fptr;
9825
9826 RB_IO_POINTER(io, fptr);
9828
9829 rb_check_arity(argc, 0, 1);
9830 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9831
9832 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9833}
9834
9835/*
9836 * call-seq:
9837 * io.wait_priority -> truthy or falsy
9838 * io.wait_priority(timeout) -> truthy or falsy
9839 *
9840 * Waits until IO is priority and returns a truthy value or a falsy
9841 * value when times out. Priority data is sent and received using
9842 * the Socket::MSG_OOB flag and is typically limited to streams.
9843 */
9844static VALUE
9845io_wait_priority(int argc, VALUE *argv, VALUE io)
9846{
9847 rb_io_t *fptr = NULL;
9848
9849 RB_IO_POINTER(io, fptr);
9851
9852 if (rb_io_read_pending(fptr)) return Qtrue;
9853
9854 rb_check_arity(argc, 0, 1);
9855 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9856
9857 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9858}
9859
9860static int
9861wait_mode_sym(VALUE mode)
9862{
9863 if (mode == ID2SYM(rb_intern("r"))) {
9864 return RB_WAITFD_IN;
9865 }
9866 if (mode == ID2SYM(rb_intern("read"))) {
9867 return RB_WAITFD_IN;
9868 }
9869 if (mode == ID2SYM(rb_intern("readable"))) {
9870 return RB_WAITFD_IN;
9871 }
9872 if (mode == ID2SYM(rb_intern("w"))) {
9873 return RB_WAITFD_OUT;
9874 }
9875 if (mode == ID2SYM(rb_intern("write"))) {
9876 return RB_WAITFD_OUT;
9877 }
9878 if (mode == ID2SYM(rb_intern("writable"))) {
9879 return RB_WAITFD_OUT;
9880 }
9881 if (mode == ID2SYM(rb_intern("rw"))) {
9882 return RB_WAITFD_IN|RB_WAITFD_OUT;
9883 }
9884 if (mode == ID2SYM(rb_intern("read_write"))) {
9885 return RB_WAITFD_IN|RB_WAITFD_OUT;
9886 }
9887 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9888 return RB_WAITFD_IN|RB_WAITFD_OUT;
9889 }
9890
9891 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9892}
9893
9894static inline enum rb_io_event
9895io_event_from_value(VALUE value)
9896{
9897 int events = RB_NUM2INT(value);
9898
9899 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9900
9901 return events;
9902}
9903
9904/*
9905 * call-seq:
9906 * io.wait(events, timeout) -> event mask, false or nil
9907 * io.wait(*event_symbols[, timeout]) -> self, true, or false
9908 *
9909 * Waits until the IO becomes ready for the specified events and returns the
9910 * subset of events that become ready, or a falsy value when times out.
9911 *
9912 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9913 * +IO::PRIORITY+.
9914 *
9915 * Returns an event mask (truthy value) immediately when buffered data is
9916 * available.
9917 *
9918 * The second form: if one or more event symbols (+:read+, +:write+, or
9919 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
9920 * corresponding to those symbols. In this form, +timeout+ is optional, the
9921 * order of the arguments is arbitrary, and returns +io+ if any of the
9922 * events is ready.
9923 */
9924
9925static VALUE
9926io_wait(int argc, VALUE *argv, VALUE io)
9927{
9928 VALUE timeout = Qundef;
9929 enum rb_io_event events = 0;
9930 int return_io = 0;
9931
9932 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9933 // We'd prefer to return the actual mask, but this form would return the io itself:
9934 return_io = 1;
9935
9936 // Slow/messy path:
9937 for (int i = 0; i < argc; i += 1) {
9938 if (RB_SYMBOL_P(argv[i])) {
9939 events |= wait_mode_sym(argv[i]);
9940 }
9941 else if (UNDEF_P(timeout)) {
9942 rb_time_interval(timeout = argv[i]);
9943 }
9944 else {
9945 rb_raise(rb_eArgError, "timeout given more than once");
9946 }
9947 }
9948
9949 if (UNDEF_P(timeout)) timeout = Qnil;
9950
9951 if (events == 0) {
9952 events = RUBY_IO_READABLE;
9953 }
9954 }
9955 else /* argc == 2 and neither are symbols */ {
9956 // This is the fast path:
9957 events = io_event_from_value(argv[0]);
9958 timeout = argv[1];
9959 }
9960
9961 if (events & RUBY_IO_READABLE) {
9962 rb_io_t *fptr = NULL;
9963 RB_IO_POINTER(io, fptr);
9964
9965 if (rb_io_read_pending(fptr)) {
9966 // This was the original behaviour:
9967 if (return_io) return Qtrue;
9968 // New behaviour always returns an event mask:
9969 else return RB_INT2NUM(RUBY_IO_READABLE);
9970 }
9971 }
9972
9973 return io_wait_event(io, events, timeout, return_io);
9974}
9975
9976static void
9977argf_mark_and_move(void *ptr)
9978{
9979 struct argf *p = ptr;
9980 rb_gc_mark_and_move(&p->filename);
9981 rb_gc_mark_and_move(&p->current_file);
9982 rb_gc_mark_and_move(&p->argv);
9983 rb_gc_mark_and_move(&p->inplace);
9984 rb_gc_mark_and_move(&p->encs.ecopts);
9985}
9986
9987static size_t
9988argf_memsize(const void *ptr)
9989{
9990 const struct argf *p = ptr;
9991 size_t size = sizeof(*p);
9992 return size;
9993}
9994
9995static const rb_data_type_t argf_type = {
9996 "ARGF",
9997 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
9998 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9999};
10000
10001static inline void
10002argf_init(struct argf *p, VALUE v)
10003{
10004 p->filename = Qnil;
10005 p->current_file = Qnil;
10006 p->lineno = 0;
10007 p->argv = v;
10008}
10009
10010static VALUE
10011argf_alloc(VALUE klass)
10012{
10013 struct argf *p;
10014 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10015
10016 argf_init(p, Qnil);
10017 return argf;
10018}
10019
10020#undef rb_argv
10021
10022/* :nodoc: */
10023static VALUE
10024argf_initialize(VALUE argf, VALUE argv)
10025{
10026 memset(&ARGF, 0, sizeof(ARGF));
10027 argf_init(&ARGF, argv);
10028
10029 return argf;
10030}
10031
10032/* :nodoc: */
10033static VALUE
10034argf_initialize_copy(VALUE argf, VALUE orig)
10035{
10036 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10037 ARGF = argf_of(orig);
10038 ARGF.argv = rb_obj_dup(ARGF.argv);
10039 return argf;
10040}
10041
10042/*
10043 * call-seq:
10044 * ARGF.lineno = integer -> integer
10045 *
10046 * Sets the line number of ARGF as a whole to the given Integer.
10047 *
10048 * ARGF sets the line number automatically as you read data, so normally
10049 * you will not need to set it explicitly. To access the current line number
10050 * use ARGF.lineno.
10051 *
10052 * For example:
10053 *
10054 * ARGF.lineno #=> 0
10055 * ARGF.readline #=> "This is line 1\n"
10056 * ARGF.lineno #=> 1
10057 * ARGF.lineno = 0 #=> 0
10058 * ARGF.lineno #=> 0
10059 */
10060static VALUE
10061argf_set_lineno(VALUE argf, VALUE val)
10062{
10063 ARGF.lineno = NUM2INT(val);
10064 ARGF.last_lineno = ARGF.lineno;
10065 return val;
10066}
10067
10068/*
10069 * call-seq:
10070 * ARGF.lineno -> integer
10071 *
10072 * Returns the current line number of ARGF as a whole. This value
10073 * can be set manually with ARGF.lineno=.
10074 *
10075 * For example:
10076 *
10077 * ARGF.lineno #=> 0
10078 * ARGF.readline #=> "This is line 1\n"
10079 * ARGF.lineno #=> 1
10080 */
10081static VALUE
10082argf_lineno(VALUE argf)
10083{
10084 return INT2FIX(ARGF.lineno);
10085}
10086
10087static VALUE
10088argf_forward(int argc, VALUE *argv, VALUE argf)
10089{
10090 return forward_current(rb_frame_this_func(), argc, argv);
10091}
10092
10093#define next_argv() argf_next_argv(argf)
10094#define ARGF_GENERIC_INPUT_P() \
10095 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10096#define ARGF_FORWARD(argc, argv) do {\
10097 if (ARGF_GENERIC_INPUT_P())\
10098 return argf_forward((argc), (argv), argf);\
10099} while (0)
10100#define NEXT_ARGF_FORWARD(argc, argv) do {\
10101 if (!next_argv()) return Qnil;\
10102 ARGF_FORWARD((argc), (argv));\
10103} while (0)
10104
10105static void
10106argf_close(VALUE argf)
10107{
10108 VALUE file = ARGF.current_file;
10109 if (file == rb_stdin) return;
10110 if (RB_TYPE_P(file, T_FILE)) {
10111 rb_io_set_write_io(file, Qnil);
10112 }
10113 io_close(file);
10114 ARGF.init_p = -1;
10115}
10116
10117static int
10118argf_next_argv(VALUE argf)
10119{
10120 char *fn;
10121 rb_io_t *fptr;
10122 int stdout_binmode = 0;
10123 enum rb_io_mode fmode;
10124
10125 VALUE r_stdout = rb_ractor_stdout();
10126
10127 if (RB_TYPE_P(r_stdout, T_FILE)) {
10128 GetOpenFile(r_stdout, fptr);
10129 if (fptr->mode & FMODE_BINMODE)
10130 stdout_binmode = 1;
10131 }
10132
10133 if (ARGF.init_p == 0) {
10134 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10135 ARGF.next_p = 1;
10136 }
10137 else {
10138 ARGF.next_p = -1;
10139 }
10140 ARGF.init_p = 1;
10141 }
10142 else {
10143 if (NIL_P(ARGF.argv)) {
10144 ARGF.next_p = -1;
10145 }
10146 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10147 ARGF.next_p = 1;
10148 }
10149 }
10150
10151 if (ARGF.next_p == 1) {
10152 if (ARGF.init_p == 1) argf_close(argf);
10153 retry:
10154 if (RARRAY_LEN(ARGF.argv) > 0) {
10155 VALUE filename = rb_ary_shift(ARGF.argv);
10156 FilePathValue(filename);
10157 ARGF.filename = filename;
10158 filename = rb_str_encode_ospath(filename);
10159 fn = StringValueCStr(filename);
10160 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10161 ARGF.current_file = rb_stdin;
10162 if (ARGF.inplace) {
10163 rb_warn("Can't do inplace edit for stdio; skipping");
10164 goto retry;
10165 }
10166 }
10167 else {
10168 VALUE write_io = Qnil;
10169 int fr = rb_sysopen(filename, O_RDONLY, 0);
10170
10171 if (ARGF.inplace) {
10172 struct stat st;
10173#ifndef NO_SAFE_RENAME
10174 struct stat st2;
10175#endif
10176 VALUE str;
10177 int fw;
10178
10179 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10180 rb_io_close(r_stdout);
10181 }
10182 fstat(fr, &st);
10183 str = filename;
10184 if (!NIL_P(ARGF.inplace)) {
10185 VALUE suffix = ARGF.inplace;
10186 str = rb_str_dup(str);
10187 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10188 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10189 rb_enc_get(suffix), 0, Qnil))) {
10190 rb_str_append(str, suffix);
10191 }
10192#ifdef NO_SAFE_RENAME
10193 (void)close(fr);
10194 (void)unlink(RSTRING_PTR(str));
10195 if (rename(fn, RSTRING_PTR(str)) < 0) {
10196 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10197 filename, str, strerror(errno));
10198 goto retry;
10199 }
10200 fr = rb_sysopen(str, O_RDONLY, 0);
10201#else
10202 if (rename(fn, RSTRING_PTR(str)) < 0) {
10203 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10204 filename, str, strerror(errno));
10205 close(fr);
10206 goto retry;
10207 }
10208#endif
10209 }
10210 else {
10211#ifdef NO_SAFE_RENAME
10212 rb_fatal("Can't do inplace edit without backup");
10213#else
10214 if (unlink(fn) < 0) {
10215 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10216 filename, strerror(errno));
10217 close(fr);
10218 goto retry;
10219 }
10220#endif
10221 }
10222 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10223#ifndef NO_SAFE_RENAME
10224 fstat(fw, &st2);
10225#ifdef HAVE_FCHMOD
10226 fchmod(fw, st.st_mode);
10227#else
10228 chmod(fn, st.st_mode);
10229#endif
10230 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10231 int err;
10232#ifdef HAVE_FCHOWN
10233 err = fchown(fw, st.st_uid, st.st_gid);
10234#else
10235 err = chown(fn, st.st_uid, st.st_gid);
10236#endif
10237 if (err && getuid() == 0 && st2.st_uid == 0) {
10238 const char *wkfn = RSTRING_PTR(filename);
10239 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10240 filename, str, strerror(errno));
10241 (void)close(fr);
10242 (void)close(fw);
10243 (void)unlink(wkfn);
10244 goto retry;
10245 }
10246 }
10247#endif
10248 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10249 rb_ractor_stdout_set(write_io);
10250 if (stdout_binmode) rb_io_binmode(rb_stdout);
10251 }
10252 fmode = FMODE_READABLE;
10253 if (!ARGF.binmode) {
10254 fmode |= DEFAULT_TEXTMODE;
10255 }
10256 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10257 if (!NIL_P(write_io)) {
10258 rb_io_set_write_io(ARGF.current_file, write_io);
10259 }
10260 RB_GC_GUARD(filename);
10261 }
10262 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10263 GetOpenFile(ARGF.current_file, fptr);
10264 if (ARGF.encs.enc) {
10265 fptr->encs = ARGF.encs;
10266 clear_codeconv(fptr);
10267 }
10268 else {
10269 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10270 if (!ARGF.binmode) {
10272#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10273 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10274#endif
10275 }
10276 }
10277 ARGF.next_p = 0;
10278 }
10279 else {
10280 ARGF.next_p = 1;
10281 return FALSE;
10282 }
10283 }
10284 else if (ARGF.next_p == -1) {
10285 ARGF.current_file = rb_stdin;
10286 ARGF.filename = rb_str_new2("-");
10287 if (ARGF.inplace) {
10288 rb_warn("Can't do inplace edit for stdio");
10289 rb_ractor_stdout_set(orig_stdout);
10290 }
10291 }
10292 if (ARGF.init_p == -1) ARGF.init_p = 1;
10293 return TRUE;
10294}
10295
10296static VALUE
10297argf_getline(int argc, VALUE *argv, VALUE argf)
10298{
10299 VALUE line;
10300 long lineno = ARGF.lineno;
10301
10302 retry:
10303 if (!next_argv()) return Qnil;
10304 if (ARGF_GENERIC_INPUT_P()) {
10305 line = forward_current(idGets, argc, argv);
10306 }
10307 else {
10308 if (argc == 0 && rb_rs == rb_default_rs) {
10309 line = rb_io_gets(ARGF.current_file);
10310 }
10311 else {
10312 line = rb_io_getline(argc, argv, ARGF.current_file);
10313 }
10314 if (NIL_P(line) && ARGF.next_p != -1) {
10315 argf_close(argf);
10316 ARGF.next_p = 1;
10317 goto retry;
10318 }
10319 }
10320 if (!NIL_P(line)) {
10321 ARGF.lineno = ++lineno;
10322 ARGF.last_lineno = ARGF.lineno;
10323 }
10324 return line;
10325}
10326
10327static VALUE
10328argf_lineno_getter(ID id, VALUE *var)
10329{
10330 VALUE argf = *var;
10331 return INT2FIX(ARGF.last_lineno);
10332}
10333
10334static void
10335argf_lineno_setter(VALUE val, ID id, VALUE *var)
10336{
10337 VALUE argf = *var;
10338 int n = NUM2INT(val);
10339 ARGF.last_lineno = ARGF.lineno = n;
10340}
10341
10342void
10343rb_reset_argf_lineno(long n)
10344{
10345 ARGF.last_lineno = ARGF.lineno = n;
10346}
10347
10348static VALUE argf_gets(int, VALUE *, VALUE);
10349
10350/*
10351 * call-seq:
10352 * gets(sep=$/ [, getline_args]) -> string or nil
10353 * gets(limit [, getline_args]) -> string or nil
10354 * gets(sep, limit [, getline_args]) -> string or nil
10355 *
10356 * Returns (and assigns to <code>$_</code>) the next line from the list
10357 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10358 * no files are present on the command line. Returns +nil+ at end of
10359 * file. The optional argument specifies the record separator. The
10360 * separator is included with the contents of each record. A separator
10361 * of +nil+ reads the entire contents, and a zero-length separator
10362 * reads the input one paragraph at a time, where paragraphs are
10363 * divided by two consecutive newlines. If the first argument is an
10364 * integer, or optional second argument is given, the returning string
10365 * would not be longer than the given value in bytes. If multiple
10366 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10367 * the contents one file at a time.
10368 *
10369 * ARGV << "testfile"
10370 * print while gets
10371 *
10372 * <em>produces:</em>
10373 *
10374 * This is line one
10375 * This is line two
10376 * This is line three
10377 * And so on...
10378 *
10379 * The style of programming using <code>$_</code> as an implicit
10380 * parameter is gradually losing favor in the Ruby community.
10381 */
10382
10383static VALUE
10384rb_f_gets(int argc, VALUE *argv, VALUE recv)
10385{
10386 if (recv == argf) {
10387 return argf_gets(argc, argv, argf);
10388 }
10389 return forward(argf, idGets, argc, argv);
10390}
10391
10392/*
10393 * call-seq:
10394 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10395 * ARGF.gets(limit [, getline_args]) -> string or nil
10396 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10397 *
10398 * Returns the next line from the current file in ARGF.
10399 *
10400 * By default lines are assumed to be separated by <code>$/</code>;
10401 * to use a different character as a separator, supply it as a String
10402 * for the _sep_ argument.
10403 *
10404 * The optional _limit_ argument specifies how many characters of each line
10405 * to return. By default all characters are returned.
10406 *
10407 * See IO.readlines for details about getline_args.
10408 *
10409 */
10410static VALUE
10411argf_gets(int argc, VALUE *argv, VALUE argf)
10412{
10413 VALUE line;
10414
10415 line = argf_getline(argc, argv, argf);
10416 rb_lastline_set(line);
10417
10418 return line;
10419}
10420
10421VALUE
10423{
10424 VALUE line;
10425
10426 if (rb_rs != rb_default_rs) {
10427 return rb_f_gets(0, 0, argf);
10428 }
10429
10430 retry:
10431 if (!next_argv()) return Qnil;
10432 line = rb_io_gets(ARGF.current_file);
10433 if (NIL_P(line) && ARGF.next_p != -1) {
10434 rb_io_close(ARGF.current_file);
10435 ARGF.next_p = 1;
10436 goto retry;
10437 }
10438 rb_lastline_set(line);
10439 if (!NIL_P(line)) {
10440 ARGF.lineno++;
10441 ARGF.last_lineno = ARGF.lineno;
10442 }
10443
10444 return line;
10445}
10446
10447static VALUE argf_readline(int, VALUE *, VALUE);
10448
10449/*
10450 * call-seq:
10451 * readline(sep = $/, chomp: false) -> string
10452 * readline(limit, chomp: false) -> string
10453 * readline(sep, limit, chomp: false) -> string
10454 *
10455 * Equivalent to method Kernel#gets, except that it raises an exception
10456 * if called at end-of-stream:
10457 *
10458 * $ cat t.txt | ruby -e "p readlines; readline"
10459 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10460 * in `readline': end of file reached (EOFError)
10461 *
10462 * Optional keyword argument +chomp+ specifies whether line separators
10463 * are to be omitted.
10464 */
10465
10466static VALUE
10467rb_f_readline(int argc, VALUE *argv, VALUE recv)
10468{
10469 if (recv == argf) {
10470 return argf_readline(argc, argv, argf);
10471 }
10472 return forward(argf, rb_intern("readline"), argc, argv);
10473}
10474
10475
10476/*
10477 * call-seq:
10478 * ARGF.readline(sep=$/) -> string
10479 * ARGF.readline(limit) -> string
10480 * ARGF.readline(sep, limit) -> string
10481 *
10482 * Returns the next line from the current file in ARGF.
10483 *
10484 * By default lines are assumed to be separated by <code>$/</code>;
10485 * to use a different character as a separator, supply it as a String
10486 * for the _sep_ argument.
10487 *
10488 * The optional _limit_ argument specifies how many characters of each line
10489 * to return. By default all characters are returned.
10490 *
10491 * An EOFError is raised at the end of the file.
10492 */
10493static VALUE
10494argf_readline(int argc, VALUE *argv, VALUE argf)
10495{
10496 VALUE line;
10497
10498 if (!next_argv()) rb_eof_error();
10499 ARGF_FORWARD(argc, argv);
10500 line = argf_gets(argc, argv, argf);
10501 if (NIL_P(line)) {
10502 rb_eof_error();
10503 }
10504
10505 return line;
10506}
10507
10508static VALUE argf_readlines(int, VALUE *, VALUE);
10509
10510/*
10511 * call-seq:
10512 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10513 * readlines(limit, chomp: false, **enc_opts) -> array
10514 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10515 *
10516 * Returns an array containing the lines returned by calling
10517 * Kernel#gets until the end-of-stream is reached;
10518 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10519 *
10520 * With only string argument +sep+ given,
10521 * returns the remaining lines as determined by line separator +sep+,
10522 * or +nil+ if none;
10523 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10524 *
10525 * # Default separator.
10526 * $ cat t.txt | ruby -e "p readlines"
10527 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10528 *
10529 * # Specified separator.
10530 * $ cat t.txt | ruby -e "p readlines 'li'"
10531 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10532 *
10533 * # Get-all separator.
10534 * $ cat t.txt | ruby -e "p readlines nil"
10535 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10536 *
10537 * # Get-paragraph separator.
10538 * $ cat t.txt | ruby -e "p readlines ''"
10539 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10540 *
10541 * With only integer argument +limit+ given,
10542 * limits the number of bytes in the line;
10543 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10544 *
10545 * $cat t.txt | ruby -e "p readlines 10"
10546 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10547 *
10548 * $cat t.txt | ruby -e "p readlines 11"
10549 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10550 *
10551 * $cat t.txt | ruby -e "p readlines 12"
10552 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10553 *
10554 * With arguments +sep+ and +limit+ given,
10555 * combines the two behaviors
10556 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10557 *
10558 * Optional keyword argument +chomp+ specifies whether line separators
10559 * are to be omitted:
10560 *
10561 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10562 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10563 *
10564 * Optional keyword arguments +enc_opts+ specify encoding options;
10565 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10566 *
10567 */
10568
10569static VALUE
10570rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10571{
10572 if (recv == argf) {
10573 return argf_readlines(argc, argv, argf);
10574 }
10575 return forward(argf, rb_intern("readlines"), argc, argv);
10576}
10577
10578/*
10579 * call-seq:
10580 * ARGF.readlines(sep = $/, chomp: false) -> array
10581 * ARGF.readlines(limit, chomp: false) -> array
10582 * ARGF.readlines(sep, limit, chomp: false) -> array
10583 *
10584 * ARGF.to_a(sep = $/, chomp: false) -> array
10585 * ARGF.to_a(limit, chomp: false) -> array
10586 * ARGF.to_a(sep, limit, chomp: false) -> array
10587 *
10588 * Reads each file in ARGF in its entirety, returning an Array containing
10589 * lines from the files. Lines are assumed to be separated by _sep_.
10590 *
10591 * lines = ARGF.readlines
10592 * lines[0] #=> "This is line one\n"
10593 *
10594 * See +IO.readlines+ for a full description of all options.
10595 */
10596static VALUE
10597argf_readlines(int argc, VALUE *argv, VALUE argf)
10598{
10599 long lineno = ARGF.lineno;
10600 VALUE lines, ary;
10601
10602 ary = rb_ary_new();
10603 while (next_argv()) {
10604 if (ARGF_GENERIC_INPUT_P()) {
10605 lines = forward_current(rb_intern("readlines"), argc, argv);
10606 }
10607 else {
10608 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10609 argf_close(argf);
10610 }
10611 ARGF.next_p = 1;
10612 rb_ary_concat(ary, lines);
10613 ARGF.lineno = lineno + RARRAY_LEN(ary);
10614 ARGF.last_lineno = ARGF.lineno;
10615 }
10616 ARGF.init_p = 0;
10617 return ary;
10618}
10619
10620/*
10621 * call-seq:
10622 * `command` -> string
10623 *
10624 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10625 * sets global variable <tt>$?</tt> to the process status.
10626 *
10627 * This method has potential security vulnerabilities if called with untrusted input;
10628 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
10629 *
10630 * Examples:
10631 *
10632 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10633 * $ `echo oops && exit 99` # => "oops\n"
10634 * $ $? # => #<Process::Status: pid 17088 exit 99>
10635 * $ $?.exitstatus # => 99
10636 *
10637 * The built-in syntax <tt>%x{...}</tt> uses this method.
10638 *
10639 */
10640
10641static VALUE
10642rb_f_backquote(VALUE obj, VALUE str)
10643{
10644 VALUE port;
10645 VALUE result;
10646 rb_io_t *fptr;
10647
10648 StringValue(str);
10649 rb_last_status_clear();
10650 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10651 if (NIL_P(port)) return rb_str_new(0,0);
10652
10653 GetOpenFile(port, fptr);
10654 result = read_all(fptr, remain_size(fptr), Qnil);
10655 rb_io_close(port);
10656 rb_io_fptr_cleanup_all(fptr);
10657 RB_GC_GUARD(port);
10658
10659 return result;
10660}
10661
10662#ifdef HAVE_SYS_SELECT_H
10663#include <sys/select.h>
10664#endif
10665
10666static VALUE
10667select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10668{
10669 VALUE res, list;
10670 rb_fdset_t *rp, *wp, *ep;
10671 rb_io_t *fptr;
10672 long i;
10673 int max = 0, n;
10674 int pending = 0;
10675 struct timeval timerec;
10676
10677 if (!NIL_P(read)) {
10678 Check_Type(read, T_ARRAY);
10679 for (i=0; i<RARRAY_LEN(read); i++) {
10680 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10681 rb_fd_set(fptr->fd, &fds[0]);
10682 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10683 pending++;
10684 rb_fd_set(fptr->fd, &fds[3]);
10685 }
10686 if (max < fptr->fd) max = fptr->fd;
10687 }
10688 if (pending) { /* no blocking if there's buffered data */
10689 timerec.tv_sec = timerec.tv_usec = 0;
10690 tp = &timerec;
10691 }
10692 rp = &fds[0];
10693 }
10694 else
10695 rp = 0;
10696
10697 if (!NIL_P(write)) {
10698 Check_Type(write, T_ARRAY);
10699 for (i=0; i<RARRAY_LEN(write); i++) {
10700 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10701 GetOpenFile(write_io, fptr);
10702 rb_fd_set(fptr->fd, &fds[1]);
10703 if (max < fptr->fd) max = fptr->fd;
10704 }
10705 wp = &fds[1];
10706 }
10707 else
10708 wp = 0;
10709
10710 if (!NIL_P(except)) {
10711 Check_Type(except, T_ARRAY);
10712 for (i=0; i<RARRAY_LEN(except); i++) {
10713 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10714 VALUE write_io = GetWriteIO(io);
10715 GetOpenFile(io, fptr);
10716 rb_fd_set(fptr->fd, &fds[2]);
10717 if (max < fptr->fd) max = fptr->fd;
10718 if (io != write_io) {
10719 GetOpenFile(write_io, fptr);
10720 rb_fd_set(fptr->fd, &fds[2]);
10721 if (max < fptr->fd) max = fptr->fd;
10722 }
10723 }
10724 ep = &fds[2];
10725 }
10726 else {
10727 ep = 0;
10728 }
10729
10730 max++;
10731
10732 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10733 if (n < 0) {
10734 rb_sys_fail(0);
10735 }
10736 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10737
10738 res = rb_ary_new2(3);
10739 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10740 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10741 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10742
10743 if (rp) {
10744 list = RARRAY_AREF(res, 0);
10745 for (i=0; i< RARRAY_LEN(read); i++) {
10746 VALUE obj = rb_ary_entry(read, i);
10747 VALUE io = rb_io_get_io(obj);
10748 GetOpenFile(io, fptr);
10749 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10750 rb_fd_isset(fptr->fd, &fds[3])) {
10751 rb_ary_push(list, obj);
10752 }
10753 }
10754 }
10755
10756 if (wp) {
10757 list = RARRAY_AREF(res, 1);
10758 for (i=0; i< RARRAY_LEN(write); i++) {
10759 VALUE obj = rb_ary_entry(write, i);
10760 VALUE io = rb_io_get_io(obj);
10761 VALUE write_io = GetWriteIO(io);
10762 GetOpenFile(write_io, fptr);
10763 if (rb_fd_isset(fptr->fd, &fds[1])) {
10764 rb_ary_push(list, obj);
10765 }
10766 }
10767 }
10768
10769 if (ep) {
10770 list = RARRAY_AREF(res, 2);
10771 for (i=0; i< RARRAY_LEN(except); i++) {
10772 VALUE obj = rb_ary_entry(except, i);
10773 VALUE io = rb_io_get_io(obj);
10774 VALUE write_io = GetWriteIO(io);
10775 GetOpenFile(io, fptr);
10776 if (rb_fd_isset(fptr->fd, &fds[2])) {
10777 rb_ary_push(list, obj);
10778 }
10779 else if (io != write_io) {
10780 GetOpenFile(write_io, fptr);
10781 if (rb_fd_isset(fptr->fd, &fds[2])) {
10782 rb_ary_push(list, obj);
10783 }
10784 }
10785 }
10786 }
10787
10788 return res; /* returns an empty array on interrupt */
10789}
10790
10792 VALUE read, write, except;
10793 struct timeval *timeout;
10794 rb_fdset_t fdsets[4];
10795};
10796
10797static VALUE
10798select_call(VALUE arg)
10799{
10800 struct select_args *p = (struct select_args *)arg;
10801
10802 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10803}
10804
10805static VALUE
10806select_end(VALUE arg)
10807{
10808 struct select_args *p = (struct select_args *)arg;
10809 int i;
10810
10811 for (i = 0; i < numberof(p->fdsets); ++i)
10812 rb_fd_term(&p->fdsets[i]);
10813 return Qnil;
10814}
10815
10816static VALUE sym_normal, sym_sequential, sym_random,
10817 sym_willneed, sym_dontneed, sym_noreuse;
10818
10819#ifdef HAVE_POSIX_FADVISE
10820struct io_advise_struct {
10821 int fd;
10822 int advice;
10823 rb_off_t offset;
10824 rb_off_t len;
10825};
10826
10827static VALUE
10828io_advise_internal(void *arg)
10829{
10830 struct io_advise_struct *ptr = arg;
10831 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10832}
10833
10834static VALUE
10835io_advise_sym_to_const(VALUE sym)
10836{
10837#ifdef POSIX_FADV_NORMAL
10838 if (sym == sym_normal)
10839 return INT2NUM(POSIX_FADV_NORMAL);
10840#endif
10841
10842#ifdef POSIX_FADV_RANDOM
10843 if (sym == sym_random)
10844 return INT2NUM(POSIX_FADV_RANDOM);
10845#endif
10846
10847#ifdef POSIX_FADV_SEQUENTIAL
10848 if (sym == sym_sequential)
10849 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10850#endif
10851
10852#ifdef POSIX_FADV_WILLNEED
10853 if (sym == sym_willneed)
10854 return INT2NUM(POSIX_FADV_WILLNEED);
10855#endif
10856
10857#ifdef POSIX_FADV_DONTNEED
10858 if (sym == sym_dontneed)
10859 return INT2NUM(POSIX_FADV_DONTNEED);
10860#endif
10861
10862#ifdef POSIX_FADV_NOREUSE
10863 if (sym == sym_noreuse)
10864 return INT2NUM(POSIX_FADV_NOREUSE);
10865#endif
10866
10867 return Qnil;
10868}
10869
10870static VALUE
10871do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10872{
10873 int rv;
10874 struct io_advise_struct ias;
10875 VALUE num_adv;
10876
10877 num_adv = io_advise_sym_to_const(advice);
10878
10879 /*
10880 * The platform doesn't support this hint. We don't raise exception, instead
10881 * silently ignore it. Because IO::advise is only hint.
10882 */
10883 if (NIL_P(num_adv))
10884 return Qnil;
10885
10886 ias.fd = fptr->fd;
10887 ias.advice = NUM2INT(num_adv);
10888 ias.offset = offset;
10889 ias.len = len;
10890
10891 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10892 if (rv && rv != ENOSYS) {
10893 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10894 it returns the error code. */
10895 VALUE message = rb_sprintf("%"PRIsVALUE" "
10896 "(%"PRI_OFFT_PREFIX"d, "
10897 "%"PRI_OFFT_PREFIX"d, "
10898 "%"PRIsVALUE")",
10899 fptr->pathv, offset, len, advice);
10900 rb_syserr_fail_str(rv, message);
10901 }
10902
10903 return Qnil;
10904}
10905
10906#endif /* HAVE_POSIX_FADVISE */
10907
10908static void
10909advice_arg_check(VALUE advice)
10910{
10911 if (!SYMBOL_P(advice))
10912 rb_raise(rb_eTypeError, "advice must be a Symbol");
10913
10914 if (advice != sym_normal &&
10915 advice != sym_sequential &&
10916 advice != sym_random &&
10917 advice != sym_willneed &&
10918 advice != sym_dontneed &&
10919 advice != sym_noreuse) {
10920 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10921 }
10922}
10923
10924/*
10925 * call-seq:
10926 * advise(advice, offset = 0, len = 0) -> nil
10927 *
10928 * Invokes Posix system call
10929 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10930 * which announces an intention to access data from the current file
10931 * in a particular manner.
10932 *
10933 * The arguments and results are platform-dependent.
10934 *
10935 * The relevant data is specified by:
10936 *
10937 * - +offset+: The offset of the first byte of data.
10938 * - +len+: The number of bytes to be accessed;
10939 * if +len+ is zero, or is larger than the number of bytes remaining,
10940 * all remaining bytes will be accessed.
10941 *
10942 * Argument +advice+ is one of the following symbols:
10943 *
10944 * - +:normal+: The application has no advice to give
10945 * about its access pattern for the specified data.
10946 * If no advice is given for an open file, this is the default assumption.
10947 * - +:sequential+: The application expects to access the specified data sequentially
10948 * (with lower offsets read before higher ones).
10949 * - +:random+: The specified data will be accessed in random order.
10950 * - +:noreuse+: The specified data will be accessed only once.
10951 * - +:willneed+: The specified data will be accessed in the near future.
10952 * - +:dontneed+: The specified data will not be accessed in the near future.
10953 *
10954 * Not implemented on all platforms.
10955 *
10956 */
10957static VALUE
10958rb_io_advise(int argc, VALUE *argv, VALUE io)
10959{
10960 VALUE advice, offset, len;
10961 rb_off_t off, l;
10962 rb_io_t *fptr;
10963
10964 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10965 advice_arg_check(advice);
10966
10967 io = GetWriteIO(io);
10968 GetOpenFile(io, fptr);
10969
10970 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10971 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10972
10973#ifdef HAVE_POSIX_FADVISE
10974 return do_io_advise(fptr, advice, off, l);
10975#else
10976 ((void)off, (void)l); /* Ignore all hint */
10977 return Qnil;
10978#endif
10979}
10980
10981static int
10982is_pos_inf(VALUE x)
10983{
10984 double f;
10985 if (!RB_FLOAT_TYPE_P(x))
10986 return 0;
10987 f = RFLOAT_VALUE(x);
10988 return isinf(f) && 0 < f;
10989}
10990
10991/*
10992 * call-seq:
10993 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
10994 *
10995 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
10996 * which monitors multiple file descriptors,
10997 * waiting until one or more of the file descriptors
10998 * becomes ready for some class of I/O operation.
10999 *
11000 * Not implemented on all platforms.
11001 *
11002 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11003 * is an array of IO objects.
11004 *
11005 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11006 * interval in seconds.
11007 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11008 * +nil+ and +Float::INFINITY+ means no timeout.
11009 *
11010 * The method monitors the \IO objects given in all three arrays,
11011 * waiting for some to be ready;
11012 * returns a 3-element array whose elements are:
11013 *
11014 * - An array of the objects in +read_ios+ that are ready for reading.
11015 * - An array of the objects in +write_ios+ that are ready for writing.
11016 * - An array of the objects in +error_ios+ have pending exceptions.
11017 *
11018 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11019 *
11020 * \IO.select peeks the buffer of \IO objects for testing readability.
11021 * If the \IO buffer is not empty, \IO.select immediately notifies
11022 * readability. This "peek" only happens for \IO objects. It does not
11023 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11024 *
11025 * The best way to use \IO.select is invoking it after non-blocking
11026 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11027 * raise an exception which is extended by IO::WaitReadable or
11028 * IO::WaitWritable. The modules notify how the caller should wait
11029 * with \IO.select. If IO::WaitReadable is raised, the caller should
11030 * wait for reading. If IO::WaitWritable is raised, the caller should
11031 * wait for writing.
11032 *
11033 * So, blocking read (#readpartial) can be emulated using
11034 * #read_nonblock and \IO.select as follows:
11035 *
11036 * begin
11037 * result = io_like.read_nonblock(maxlen)
11038 * rescue IO::WaitReadable
11039 * IO.select([io_like])
11040 * retry
11041 * rescue IO::WaitWritable
11042 * IO.select(nil, [io_like])
11043 * retry
11044 * end
11045 *
11046 * Especially, the combination of non-blocking methods and \IO.select is
11047 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11048 * has #to_io method to return underlying IO object. IO.select calls
11049 * #to_io to obtain the file descriptor to wait.
11050 *
11051 * This means that readability notified by \IO.select doesn't mean
11052 * readability from OpenSSL::SSL::SSLSocket object.
11053 *
11054 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11055 * some data. \IO.select doesn't see the buffer. So \IO.select can
11056 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11057 *
11058 * However, several more complicated situations exist.
11059 *
11060 * SSL is a protocol which is sequence of records.
11061 * The record consists of multiple bytes.
11062 * So, the remote side of SSL sends a partial record, IO.select
11063 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11064 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11065 *
11066 * Also, the remote side can request SSL renegotiation which forces
11067 * the local SSL engine to write some data.
11068 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11069 * system call and it can block.
11070 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11071 * IO::WaitWritable instead of blocking.
11072 * So, the caller should wait for ready for writability as above
11073 * example.
11074 *
11075 * The combination of non-blocking methods and \IO.select is also useful
11076 * for streams such as tty, pipe socket socket when multiple processes
11077 * read from a stream.
11078 *
11079 * Finally, Linux kernel developers don't guarantee that
11080 * readability of select(2) means readability of following read(2) even
11081 * for a single process;
11082 * see {select(2)}[https://linux.die.net/man/2/select]
11083 *
11084 * Invoking \IO.select before IO#readpartial works well as usual.
11085 * However it is not the best way to use \IO.select.
11086 *
11087 * The writability notified by select(2) doesn't show
11088 * how many bytes are writable.
11089 * IO#write method blocks until given whole string is written.
11090 * So, <tt>IO#write(two or more bytes)</tt> can block after
11091 * writability is notified by \IO.select. IO#write_nonblock is required
11092 * to avoid the blocking.
11093 *
11094 * Blocking write (#write) can be emulated using #write_nonblock and
11095 * IO.select as follows: IO::WaitReadable should also be rescued for
11096 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11097 *
11098 * while 0 < string.bytesize
11099 * begin
11100 * written = io_like.write_nonblock(string)
11101 * rescue IO::WaitReadable
11102 * IO.select([io_like])
11103 * retry
11104 * rescue IO::WaitWritable
11105 * IO.select(nil, [io_like])
11106 * retry
11107 * end
11108 * string = string.byteslice(written..-1)
11109 * end
11110 *
11111 * Example:
11112 *
11113 * rp, wp = IO.pipe
11114 * mesg = "ping "
11115 * 100.times {
11116 * # IO.select follows IO#read. Not the best way to use IO.select.
11117 * rs, ws, = IO.select([rp], [wp])
11118 * if r = rs[0]
11119 * ret = r.read(5)
11120 * print ret
11121 * case ret
11122 * when /ping/
11123 * mesg = "pong\n"
11124 * when /pong/
11125 * mesg = "ping "
11126 * end
11127 * end
11128 * if w = ws[0]
11129 * w.write(mesg)
11130 * end
11131 * }
11132 *
11133 * Output:
11134 *
11135 * ping pong
11136 * ping pong
11137 * ping pong
11138 * (snipped)
11139 * ping
11140 *
11141 */
11142
11143static VALUE
11144rb_f_select(int argc, VALUE *argv, VALUE obj)
11145{
11146 VALUE scheduler = rb_fiber_scheduler_current();
11147 if (scheduler != Qnil) {
11148 // It's optionally supported.
11149 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11150 if (!UNDEF_P(result)) return result;
11151 }
11152
11153 VALUE timeout;
11154 struct select_args args;
11155 struct timeval timerec;
11156 int i;
11157
11158 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11159 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11160 args.timeout = 0;
11161 }
11162 else {
11163 timerec = rb_time_interval(timeout);
11164 args.timeout = &timerec;
11165 }
11166
11167 for (i = 0; i < numberof(args.fdsets); ++i)
11168 rb_fd_init(&args.fdsets[i]);
11169
11170 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11171}
11172
11173#ifdef IOCTL_REQ_TYPE
11174 typedef IOCTL_REQ_TYPE ioctl_req_t;
11175#else
11176 typedef int ioctl_req_t;
11177# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11178#endif
11179
11180#ifdef HAVE_IOCTL
11181struct ioctl_arg {
11182 int fd;
11183 ioctl_req_t cmd;
11184 long narg;
11185};
11186
11187static VALUE
11188nogvl_ioctl(void *ptr)
11189{
11190 struct ioctl_arg *arg = ptr;
11191
11192 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11193}
11194
11195static int
11196do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11197{
11198 int retval;
11199 struct ioctl_arg arg;
11200
11201 arg.fd = io->fd;
11202 arg.cmd = cmd;
11203 arg.narg = narg;
11204
11205 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11206
11207 return retval;
11208}
11209#endif
11210
11211#define DEFAULT_IOCTL_NARG_LEN (256)
11212
11213#if defined(__linux__) && defined(_IOC_SIZE)
11214static long
11215linux_iocparm_len(ioctl_req_t cmd)
11216{
11217 long len;
11218
11219 if ((cmd & 0xFFFF0000) == 0) {
11220 /* legacy and unstructured ioctl number. */
11221 return DEFAULT_IOCTL_NARG_LEN;
11222 }
11223
11224 len = _IOC_SIZE(cmd);
11225
11226 /* paranoia check for silly drivers which don't keep ioctl convention */
11227 if (len < DEFAULT_IOCTL_NARG_LEN)
11228 len = DEFAULT_IOCTL_NARG_LEN;
11229
11230 return len;
11231}
11232#endif
11233
11234#ifdef HAVE_IOCTL
11235static long
11236ioctl_narg_len(ioctl_req_t cmd)
11237{
11238 long len;
11239
11240#ifdef IOCPARM_MASK
11241#ifndef IOCPARM_LEN
11242#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11243#endif
11244#endif
11245#ifdef IOCPARM_LEN
11246 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11247#elif defined(__linux__) && defined(_IOC_SIZE)
11248 len = linux_iocparm_len(cmd);
11249#else
11250 /* otherwise guess at what's safe */
11251 len = DEFAULT_IOCTL_NARG_LEN;
11252#endif
11253
11254 return len;
11255}
11256#endif
11257
11258#ifdef HAVE_FCNTL
11259#ifdef __linux__
11260typedef long fcntl_arg_t;
11261#else
11262/* posix */
11263typedef int fcntl_arg_t;
11264#endif
11265
11266static long
11267fcntl_narg_len(ioctl_req_t cmd)
11268{
11269 long len;
11270
11271 switch (cmd) {
11272#ifdef F_DUPFD
11273 case F_DUPFD:
11274 len = sizeof(fcntl_arg_t);
11275 break;
11276#endif
11277#ifdef F_DUP2FD /* bsd specific */
11278 case F_DUP2FD:
11279 len = sizeof(int);
11280 break;
11281#endif
11282#ifdef F_DUPFD_CLOEXEC /* linux specific */
11283 case F_DUPFD_CLOEXEC:
11284 len = sizeof(fcntl_arg_t);
11285 break;
11286#endif
11287#ifdef F_GETFD
11288 case F_GETFD:
11289 len = 1;
11290 break;
11291#endif
11292#ifdef F_SETFD
11293 case F_SETFD:
11294 len = sizeof(fcntl_arg_t);
11295 break;
11296#endif
11297#ifdef F_GETFL
11298 case F_GETFL:
11299 len = 1;
11300 break;
11301#endif
11302#ifdef F_SETFL
11303 case F_SETFL:
11304 len = sizeof(fcntl_arg_t);
11305 break;
11306#endif
11307#ifdef F_GETOWN
11308 case F_GETOWN:
11309 len = 1;
11310 break;
11311#endif
11312#ifdef F_SETOWN
11313 case F_SETOWN:
11314 len = sizeof(fcntl_arg_t);
11315 break;
11316#endif
11317#ifdef F_GETOWN_EX /* linux specific */
11318 case F_GETOWN_EX:
11319 len = sizeof(struct f_owner_ex);
11320 break;
11321#endif
11322#ifdef F_SETOWN_EX /* linux specific */
11323 case F_SETOWN_EX:
11324 len = sizeof(struct f_owner_ex);
11325 break;
11326#endif
11327#ifdef F_GETLK
11328 case F_GETLK:
11329 len = sizeof(struct flock);
11330 break;
11331#endif
11332#ifdef F_SETLK
11333 case F_SETLK:
11334 len = sizeof(struct flock);
11335 break;
11336#endif
11337#ifdef F_SETLKW
11338 case F_SETLKW:
11339 len = sizeof(struct flock);
11340 break;
11341#endif
11342#ifdef F_READAHEAD /* bsd specific */
11343 case F_READAHEAD:
11344 len = sizeof(int);
11345 break;
11346#endif
11347#ifdef F_RDAHEAD /* Darwin specific */
11348 case F_RDAHEAD:
11349 len = sizeof(int);
11350 break;
11351#endif
11352#ifdef F_GETSIG /* linux specific */
11353 case F_GETSIG:
11354 len = 1;
11355 break;
11356#endif
11357#ifdef F_SETSIG /* linux specific */
11358 case F_SETSIG:
11359 len = sizeof(fcntl_arg_t);
11360 break;
11361#endif
11362#ifdef F_GETLEASE /* linux specific */
11363 case F_GETLEASE:
11364 len = 1;
11365 break;
11366#endif
11367#ifdef F_SETLEASE /* linux specific */
11368 case F_SETLEASE:
11369 len = sizeof(fcntl_arg_t);
11370 break;
11371#endif
11372#ifdef F_NOTIFY /* linux specific */
11373 case F_NOTIFY:
11374 len = sizeof(fcntl_arg_t);
11375 break;
11376#endif
11377
11378 default:
11379 len = 256;
11380 break;
11381 }
11382
11383 return len;
11384}
11385#else /* HAVE_FCNTL */
11386static long
11387fcntl_narg_len(ioctl_req_t cmd)
11388{
11389 return 0;
11390}
11391#endif /* HAVE_FCNTL */
11392
11393#define NARG_SENTINEL 17
11394
11395static long
11396setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11397{
11398 long narg = 0;
11399 VALUE arg = *argp;
11400
11401 if (!RTEST(arg)) {
11402 narg = 0;
11403 }
11404 else if (FIXNUM_P(arg)) {
11405 narg = FIX2LONG(arg);
11406 }
11407 else if (arg == Qtrue) {
11408 narg = 1;
11409 }
11410 else {
11411 VALUE tmp = rb_check_string_type(arg);
11412
11413 if (NIL_P(tmp)) {
11414 narg = NUM2LONG(arg);
11415 }
11416 else {
11417 char *ptr;
11418 long len, slen;
11419
11420 *argp = arg = tmp;
11421 len = narg_len(cmd);
11422 rb_str_modify(arg);
11423
11424 slen = RSTRING_LEN(arg);
11425 /* expand for data + sentinel. */
11426 if (slen < len+1) {
11427 rb_str_resize(arg, len+1);
11428 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11429 slen = len+1;
11430 }
11431 /* a little sanity check here */
11432 ptr = RSTRING_PTR(arg);
11433 ptr[slen - 1] = NARG_SENTINEL;
11434 narg = (long)(SIGNED_VALUE)ptr;
11435 }
11436 }
11437
11438 return narg;
11439}
11440
11441static VALUE
11442finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11443{
11444 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11445 if (RB_TYPE_P(arg, T_STRING)) {
11446 char *ptr;
11447 long slen;
11448 RSTRING_GETMEM(arg, ptr, slen);
11449 if (ptr[slen-1] != NARG_SENTINEL)
11450 rb_raise(rb_eArgError, "return value overflowed string");
11451 ptr[slen-1] = '\0';
11452 }
11453
11454 return INT2NUM(retval);
11455}
11456
11457#ifdef HAVE_IOCTL
11458static VALUE
11459rb_ioctl(VALUE io, VALUE req, VALUE arg)
11460{
11461 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11462 rb_io_t *fptr;
11463 long narg;
11464 int retval;
11465
11466 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11467 GetOpenFile(io, fptr);
11468 retval = do_ioctl(fptr, cmd, narg);
11469 return finish_narg(retval, arg, fptr);
11470}
11471
11472/*
11473 * call-seq:
11474 * ioctl(integer_cmd, argument) -> integer
11475 *
11476 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11477 * which issues a low-level command to an I/O device.
11478 *
11479 * Issues a low-level command to an I/O device.
11480 * The arguments and returned value are platform-dependent.
11481 * The effect of the call is platform-dependent.
11482 *
11483 * If argument +argument+ is an integer, it is passed directly;
11484 * if it is a string, it is interpreted as a binary sequence of bytes.
11485 *
11486 * Not implemented on all platforms.
11487 *
11488 */
11489
11490static VALUE
11491rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11492{
11493 VALUE req, arg;
11494
11495 rb_scan_args(argc, argv, "11", &req, &arg);
11496 return rb_ioctl(io, req, arg);
11497}
11498#else
11499#define rb_io_ioctl rb_f_notimplement
11500#endif
11501
11502#ifdef HAVE_FCNTL
11503struct fcntl_arg {
11504 int fd;
11505 int cmd;
11506 long narg;
11507};
11508
11509static VALUE
11510nogvl_fcntl(void *ptr)
11511{
11512 struct fcntl_arg *arg = ptr;
11513
11514#if defined(F_DUPFD)
11515 if (arg->cmd == F_DUPFD)
11516 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11517#endif
11518 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11519}
11520
11521static int
11522do_fcntl(struct rb_io *io, int cmd, long narg)
11523{
11524 int retval;
11525 struct fcntl_arg arg;
11526
11527 arg.fd = io->fd;
11528 arg.cmd = cmd;
11529 arg.narg = narg;
11530
11531 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11532 if (retval != -1) {
11533 switch (cmd) {
11534#if defined(F_DUPFD)
11535 case F_DUPFD:
11536#endif
11537#if defined(F_DUPFD_CLOEXEC)
11538 case F_DUPFD_CLOEXEC:
11539#endif
11540 rb_update_max_fd(retval);
11541 }
11542 }
11543
11544 return retval;
11545}
11546
11547static VALUE
11548rb_fcntl(VALUE io, VALUE req, VALUE arg)
11549{
11550 int cmd = NUM2INT(req);
11551 rb_io_t *fptr;
11552 long narg;
11553 int retval;
11554
11555 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11556 GetOpenFile(io, fptr);
11557 retval = do_fcntl(fptr, cmd, narg);
11558 return finish_narg(retval, arg, fptr);
11559}
11560
11561/*
11562 * call-seq:
11563 * fcntl(integer_cmd, argument) -> integer
11564 *
11565 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11566 * which provides a mechanism for issuing low-level commands to control or query
11567 * a file-oriented I/O stream. Arguments and results are platform
11568 * dependent.
11569 *
11570 * If +argument+ is a number, its value is passed directly;
11571 * if it is a string, it is interpreted as a binary sequence of bytes.
11572 * (Array#pack might be a useful way to build this string.)
11573 *
11574 * Not implemented on all platforms.
11575 *
11576 */
11577
11578static VALUE
11579rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11580{
11581 VALUE req, arg;
11582
11583 rb_scan_args(argc, argv, "11", &req, &arg);
11584 return rb_fcntl(io, req, arg);
11585}
11586#else
11587#define rb_io_fcntl rb_f_notimplement
11588#endif
11589
11590#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11591/*
11592 * call-seq:
11593 * syscall(integer_callno, *arguments) -> integer
11594 *
11595 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11596 * which calls a specified function.
11597 *
11598 * Calls the operating system function identified by +integer_callno+;
11599 * returns the result of the function or raises SystemCallError if it failed.
11600 * The effect of the call is platform-dependent.
11601 * The arguments and returned value are platform-dependent.
11602 *
11603 * For each of +arguments+: if it is an integer, it is passed directly;
11604 * if it is a string, it is interpreted as a binary sequence of bytes.
11605 * There may be as many as nine such arguments.
11606 *
11607 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11608 * are platform-dependent.
11609 *
11610 * Note: Method +syscall+ is essentially unsafe and unportable.
11611 * The DL (Fiddle) library is preferred for safer and a bit
11612 * more portable programming.
11613 *
11614 * Not implemented on all platforms.
11615 *
11616 */
11617
11618static VALUE
11619rb_f_syscall(int argc, VALUE *argv, VALUE _)
11620{
11621 VALUE arg[8];
11622#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11623# define SYSCALL __syscall
11624# define NUM2SYSCALLID(x) NUM2LONG(x)
11625# define RETVAL2NUM(x) LONG2NUM(x)
11626# if SIZEOF_LONG == 8
11627 long num, retval = -1;
11628# elif SIZEOF_LONG_LONG == 8
11629 long long num, retval = -1;
11630# else
11631# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11632# endif
11633#elif defined(__linux__)
11634# define SYSCALL syscall
11635# define NUM2SYSCALLID(x) NUM2LONG(x)
11636# define RETVAL2NUM(x) LONG2NUM(x)
11637 /*
11638 * Linux man page says, syscall(2) function prototype is below.
11639 *
11640 * int syscall(int number, ...);
11641 *
11642 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11643 */
11644 long num, retval = -1;
11645#else
11646# define SYSCALL syscall
11647# define NUM2SYSCALLID(x) NUM2INT(x)
11648# define RETVAL2NUM(x) INT2NUM(x)
11649 int num, retval = -1;
11650#endif
11651 int i;
11652
11653 if (RTEST(ruby_verbose)) {
11655 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11656 }
11657
11658 if (argc == 0)
11659 rb_raise(rb_eArgError, "too few arguments for syscall");
11660 if (argc > numberof(arg))
11661 rb_raise(rb_eArgError, "too many arguments for syscall");
11662 num = NUM2SYSCALLID(argv[0]); ++argv;
11663 for (i = argc - 1; i--; ) {
11664 VALUE v = rb_check_string_type(argv[i]);
11665
11666 if (!NIL_P(v)) {
11667 StringValue(v);
11668 rb_str_modify(v);
11669 arg[i] = (VALUE)StringValueCStr(v);
11670 }
11671 else {
11672 arg[i] = (VALUE)NUM2LONG(argv[i]);
11673 }
11674 }
11675
11676 switch (argc) {
11677 case 1:
11678 retval = SYSCALL(num);
11679 break;
11680 case 2:
11681 retval = SYSCALL(num, arg[0]);
11682 break;
11683 case 3:
11684 retval = SYSCALL(num, arg[0],arg[1]);
11685 break;
11686 case 4:
11687 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11688 break;
11689 case 5:
11690 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11691 break;
11692 case 6:
11693 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11694 break;
11695 case 7:
11696 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11697 break;
11698 case 8:
11699 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11700 break;
11701 }
11702
11703 if (retval == -1)
11704 rb_sys_fail(0);
11705 return RETVAL2NUM(retval);
11706#undef SYSCALL
11707#undef NUM2SYSCALLID
11708#undef RETVAL2NUM
11709}
11710#else
11711#define rb_f_syscall rb_f_notimplement
11712#endif
11713
11714static VALUE
11715io_new_instance(VALUE args)
11716{
11717 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11718}
11719
11720static rb_encoding *
11721find_encoding(VALUE v)
11722{
11723 rb_encoding *enc = rb_find_encoding(v);
11724 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11725 return enc;
11726}
11727
11728static void
11729io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11730{
11731 rb_encoding *enc, *enc2;
11732 int ecflags = fptr->encs.ecflags;
11733 VALUE ecopts, tmp;
11734
11735 if (!NIL_P(v2)) {
11736 enc2 = find_encoding(v1);
11737 tmp = rb_check_string_type(v2);
11738 if (!NIL_P(tmp)) {
11739 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11740 /* Special case - "-" => no transcoding */
11741 enc = enc2;
11742 enc2 = NULL;
11743 }
11744 else
11745 enc = find_encoding(v2);
11746 if (enc == enc2) {
11747 /* Special case - "-" => no transcoding */
11748 enc2 = NULL;
11749 }
11750 }
11751 else {
11752 enc = find_encoding(v2);
11753 if (enc == enc2) {
11754 /* Special case - "-" => no transcoding */
11755 enc2 = NULL;
11756 }
11757 }
11758 if (enc2 == rb_ascii8bit_encoding()) {
11759 /* If external is ASCII-8BIT, no transcoding */
11760 enc = enc2;
11761 enc2 = NULL;
11762 }
11763 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11764 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11765 }
11766 else {
11767 if (NIL_P(v1)) {
11768 /* Set to default encodings */
11769 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11770 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11771 ecopts = Qnil;
11772 }
11773 else {
11774 tmp = rb_check_string_type(v1);
11775 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11776 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11777 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11778 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11779 }
11780 else {
11781 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11782 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11783 ecopts = Qnil;
11784 }
11785 }
11786 }
11787 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11788 fptr->encs.enc = enc;
11789 fptr->encs.enc2 = enc2;
11790 fptr->encs.ecflags = ecflags;
11791 fptr->encs.ecopts = ecopts;
11792 clear_codeconv(fptr);
11793
11794}
11795
11797 rb_io_t *fptr;
11798 VALUE v1;
11799 VALUE v2;
11800 VALUE opt;
11801};
11802
11803static VALUE
11804io_encoding_set_v(VALUE v)
11805{
11806 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11807 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11808 return Qnil;
11809}
11810
11811static VALUE
11812pipe_pair_close(VALUE rw)
11813{
11814 VALUE *rwp = (VALUE *)rw;
11815 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11816}
11817
11818/*
11819 * call-seq:
11820 * IO.pipe(**opts) -> [read_io, write_io]
11821 * IO.pipe(enc, **opts) -> [read_io, write_io]
11822 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11823 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11824 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11825 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11826 *
11827 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11828 * connected to each other.
11829 *
11830 * If argument +enc_string+ is given, it must be a string containing one of:
11831 *
11832 * - The name of the encoding to be used as the external encoding.
11833 * - The colon-separated names of two encodings to be used as the external
11834 * and internal encodings.
11835 *
11836 * If argument +int_enc+ is given, it must be an Encoding object
11837 * or encoding name string that specifies the internal encoding to be used;
11838 * if argument +ext_enc+ is also given, it must be an Encoding object
11839 * or encoding name string that specifies the external encoding to be used.
11840 *
11841 * The string read from +read_io+ is tagged with the external encoding;
11842 * if an internal encoding is also specified, the string is converted
11843 * to, and tagged with, that encoding.
11844 *
11845 * If any encoding is specified,
11846 * optional hash arguments specify the conversion option.
11847 *
11848 * Optional keyword arguments +opts+ specify:
11849 *
11850 * - {Open Options}[rdoc-ref:IO@Open+Options].
11851 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11852 *
11853 * With no block given, returns the two endpoints in an array:
11854 *
11855 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11856 *
11857 * With a block given, calls the block with the two endpoints;
11858 * closes both endpoints and returns the value of the block:
11859 *
11860 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11861 *
11862 * Output:
11863 *
11864 * #<IO:fd 6>
11865 * #<IO:fd 7>
11866 *
11867 * Not available on all platforms.
11868 *
11869 * In the example below, the two processes close the ends of the pipe
11870 * that they are not using. This is not just a cosmetic nicety. The
11871 * read end of a pipe will not generate an end of file condition if
11872 * there are any writers with the pipe still open. In the case of the
11873 * parent process, the <tt>rd.read</tt> will never return if it
11874 * does not first issue a <tt>wr.close</tt>:
11875 *
11876 * rd, wr = IO.pipe
11877 *
11878 * if fork
11879 * wr.close
11880 * puts "Parent got: <#{rd.read}>"
11881 * rd.close
11882 * Process.wait
11883 * else
11884 * rd.close
11885 * puts 'Sending message to parent'
11886 * wr.write "Hi Dad"
11887 * wr.close
11888 * end
11889 *
11890 * <em>produces:</em>
11891 *
11892 * Sending message to parent
11893 * Parent got: <Hi Dad>
11894 *
11895 */
11896
11897static VALUE
11898rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11899{
11900 int pipes[2], state;
11901 VALUE r, w, args[3], v1, v2;
11902 VALUE opt;
11903 rb_io_t *fptr, *fptr2;
11904 struct io_encoding_set_args ies_args;
11905 enum rb_io_mode fmode = 0;
11906 VALUE ret;
11907
11908 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11909 if (rb_pipe(pipes) < 0)
11910 rb_sys_fail(0);
11911
11912 args[0] = klass;
11913 args[1] = INT2NUM(pipes[0]);
11914 args[2] = INT2FIX(O_RDONLY);
11915 r = rb_protect(io_new_instance, (VALUE)args, &state);
11916 if (state) {
11917 close(pipes[0]);
11918 close(pipes[1]);
11919 rb_jump_tag(state);
11920 }
11921 GetOpenFile(r, fptr);
11922
11923 ies_args.fptr = fptr;
11924 ies_args.v1 = v1;
11925 ies_args.v2 = v2;
11926 ies_args.opt = opt;
11927 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11928 if (state) {
11929 close(pipes[1]);
11930 io_close(r);
11931 rb_jump_tag(state);
11932 }
11933
11934 args[1] = INT2NUM(pipes[1]);
11935 args[2] = INT2FIX(O_WRONLY);
11936 w = rb_protect(io_new_instance, (VALUE)args, &state);
11937 if (state) {
11938 close(pipes[1]);
11939 if (!NIL_P(r)) rb_io_close(r);
11940 rb_jump_tag(state);
11941 }
11942 GetOpenFile(w, fptr2);
11943 rb_io_synchronized(fptr2);
11944
11945 extract_binmode(opt, &fmode);
11946
11947 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11950 }
11951
11952#if DEFAULT_TEXTMODE
11953 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11954 fptr->mode &= ~FMODE_TEXTMODE;
11955 setmode(fptr->fd, O_BINARY);
11956 }
11957#if RUBY_CRLF_ENVIRONMENT
11960 }
11961#endif
11962#endif
11963 fptr->mode |= fmode;
11964#if DEFAULT_TEXTMODE
11965 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11966 fptr2->mode &= ~FMODE_TEXTMODE;
11967 setmode(fptr2->fd, O_BINARY);
11968 }
11969#endif
11970 fptr2->mode |= fmode;
11971
11972 ret = rb_assoc_new(r, w);
11973 if (rb_block_given_p()) {
11974 VALUE rw[2];
11975 rw[0] = r;
11976 rw[1] = w;
11977 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11978 }
11979 return ret;
11980}
11981
11983 int argc;
11984 VALUE *argv;
11985 VALUE io;
11986};
11987
11988static void
11989open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
11990{
11991 VALUE path, v;
11992 VALUE vmode = Qnil, vperm = Qnil;
11993
11994 path = *argv++;
11995 argc--;
11996 FilePathValue(path);
11997 arg->io = 0;
11998 arg->argc = argc;
11999 arg->argv = argv;
12000 if (NIL_P(opt)) {
12001 vmode = INT2NUM(O_RDONLY);
12002 vperm = INT2FIX(0666);
12003 }
12004 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12005 int n;
12006
12007 v = rb_to_array_type(v);
12008 n = RARRAY_LENINT(v);
12009 rb_check_arity(n, 0, 3); /* rb_io_open */
12010 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12011 }
12012 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12013}
12014
12015static VALUE
12016io_s_foreach(VALUE v)
12017{
12018 struct getline_arg *arg = (void *)v;
12019 VALUE str;
12020
12021 if (arg->limit == 0)
12022 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12023 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12024 rb_lastline_set(str);
12025 rb_yield(str);
12026 }
12028 return Qnil;
12029}
12030
12031/*
12032 * call-seq:
12033 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12034 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12035 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12036 * IO.foreach(...) -> an_enumerator
12037 *
12038 * Calls the block with each successive line read from the stream.
12039 *
12040 * When called from class \IO (but not subclasses of \IO),
12041 * this method has potential security vulnerabilities if called with untrusted input;
12042 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12043 *
12044 * The first argument must be a string that is the path to a file.
12045 *
12046 * With only argument +path+ given, parses lines from the file at the given +path+,
12047 * as determined by the default line separator,
12048 * and calls the block with each successive line:
12049 *
12050 * File.foreach('t.txt') {|line| p line }
12051 *
12052 * Output: the same as above.
12053 *
12054 * For both forms, command and path, the remaining arguments are the same.
12055 *
12056 * With argument +sep+ given, parses lines as determined by that line separator
12057 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12058 *
12059 * File.foreach('t.txt', 'li') {|line| p line }
12060 *
12061 * Output:
12062 *
12063 * "First li"
12064 * "ne\nSecond li"
12065 * "ne\n\nThird li"
12066 * "ne\nFourth li"
12067 * "ne\n"
12068 *
12069 * Each paragraph:
12070 *
12071 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12072 *
12073 * Output:
12074 *
12075 * "First line\nSecond line\n\n"
12076 * "Third line\nFourth line\n"
12077 *
12078 * With argument +limit+ given, parses lines as determined by the default
12079 * line separator and the given line-length limit
12080 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12081 *
12082 * File.foreach('t.txt', 7) {|line| p line }
12083 *
12084 * Output:
12085 *
12086 * "First l"
12087 * "ine\n"
12088 * "Second "
12089 * "line\n"
12090 * "\n"
12091 * "Third l"
12092 * "ine\n"
12093 * "Fourth l"
12094 * "line\n"
12095 *
12096 * With arguments +sep+ and +limit+ given,
12097 * combines the two behaviors
12098 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12099 *
12100 * Optional keyword arguments +opts+ specify:
12101 *
12102 * - {Open Options}[rdoc-ref:IO@Open+Options].
12103 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12104 * - {Line Options}[rdoc-ref:IO@Line+IO].
12105 *
12106 * Returns an Enumerator if no block is given.
12107 *
12108 */
12109
12110static VALUE
12111rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12112{
12113 VALUE opt;
12114 int orig_argc = argc;
12115 struct foreach_arg arg;
12116 struct getline_arg garg;
12117
12118 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12119 RETURN_ENUMERATOR(self, orig_argc, argv);
12120 extract_getline_args(argc-1, argv+1, &garg);
12121 open_key_args(self, argc, argv, opt, &arg);
12122 if (NIL_P(arg.io)) return Qnil;
12123 extract_getline_opts(opt, &garg);
12124 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12125 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12126}
12127
12128static VALUE
12129io_s_readlines(VALUE v)
12130{
12131 struct getline_arg *arg = (void *)v;
12132 return io_readlines(arg, arg->io);
12133}
12134
12135/*
12136 * call-seq:
12137 * IO.readlines(path, sep = $/, **opts) -> array
12138 * IO.readlines(path, limit, **opts) -> array
12139 * IO.readlines(path, sep, limit, **opts) -> array
12140 *
12141 * Returns an array of all lines read from the stream.
12142 *
12143 * When called from class \IO (but not subclasses of \IO),
12144 * this method has potential security vulnerabilities if called with untrusted input;
12145 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12146 *
12147 * The first argument must be a string that is the path to a file.
12148 *
12149 * With only argument +path+ given, parses lines from the file at the given +path+,
12150 * as determined by the default line separator,
12151 * and returns those lines in an array:
12152 *
12153 * IO.readlines('t.txt')
12154 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12155 *
12156 * With argument +sep+ given, parses lines as determined by that line separator
12157 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12158 *
12159 * # Ordinary separator.
12160 * IO.readlines('t.txt', 'li')
12161 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12162 * # Get-paragraphs separator.
12163 * IO.readlines('t.txt', '')
12164 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12165 * # Get-all separator.
12166 * IO.readlines('t.txt', nil)
12167 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12168 *
12169 * With argument +limit+ given, parses lines as determined by the default
12170 * line separator and the given line-length limit
12171 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12172 *
12173 * IO.readlines('t.txt', 7)
12174 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12175 *
12176 * With arguments +sep+ and +limit+ given,
12177 * combines the two behaviors
12178 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12179 *
12180 * Optional keyword arguments +opts+ specify:
12181 *
12182 * - {Open Options}[rdoc-ref:IO@Open+Options].
12183 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12184 * - {Line Options}[rdoc-ref:IO@Line+IO].
12185 *
12186 */
12187
12188static VALUE
12189rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12190{
12191 VALUE opt;
12192 struct foreach_arg arg;
12193 struct getline_arg garg;
12194
12195 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12196 extract_getline_args(argc-1, argv+1, &garg);
12197 open_key_args(io, argc, argv, opt, &arg);
12198 if (NIL_P(arg.io)) return Qnil;
12199 extract_getline_opts(opt, &garg);
12200 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12201 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12202}
12203
12204static VALUE
12205io_s_read(VALUE v)
12206{
12207 struct foreach_arg *arg = (void *)v;
12208 return io_read(arg->argc, arg->argv, arg->io);
12209}
12210
12211struct seek_arg {
12212 VALUE io;
12213 VALUE offset;
12214 int mode;
12215};
12216
12217static VALUE
12218seek_before_access(VALUE argp)
12219{
12220 struct seek_arg *arg = (struct seek_arg *)argp;
12221 rb_io_binmode(arg->io);
12222 return rb_io_seek(arg->io, arg->offset, arg->mode);
12223}
12224
12225/*
12226 * call-seq:
12227 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12228 *
12229 * Opens the stream, reads and returns some or all of its content,
12230 * and closes the stream; returns +nil+ if no bytes were read.
12231 *
12232 * When called from class \IO (but not subclasses of \IO),
12233 * this method has potential security vulnerabilities if called with untrusted input;
12234 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12235 *
12236 * The first argument must be a string that is the path to a file.
12237 *
12238 * With only argument +path+ given, reads in text mode and returns the entire content
12239 * of the file at the given path:
12240 *
12241 * IO.read('t.txt')
12242 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12243 *
12244 * On Windows, text mode can terminate reading and leave bytes in the file
12245 * unread when encountering certain special bytes. Consider using
12246 * IO.binread if all bytes in the file should be read.
12247 *
12248 * With argument +length+, returns +length+ bytes if available:
12249 *
12250 * IO.read('t.txt', 7) # => "First l"
12251 * IO.read('t.txt', 700)
12252 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12253 *
12254 * With arguments +length+ and +offset+, returns +length+ bytes
12255 * if available, beginning at the given +offset+:
12256 *
12257 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12258 * IO.read('t.txt', 10, 200) # => nil
12259 *
12260 * Optional keyword arguments +opts+ specify:
12261 *
12262 * - {Open Options}[rdoc-ref:IO@Open+Options].
12263 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12264 *
12265 */
12266
12267static VALUE
12268rb_io_s_read(int argc, VALUE *argv, VALUE io)
12269{
12270 VALUE opt, offset;
12271 long off;
12272 struct foreach_arg arg;
12273
12274 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12275 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12276 rb_raise(rb_eArgError, "negative offset %ld given", off);
12277 }
12278 open_key_args(io, argc, argv, opt, &arg);
12279 if (NIL_P(arg.io)) return Qnil;
12280 if (!NIL_P(offset)) {
12281 struct seek_arg sarg;
12282 int state = 0;
12283 sarg.io = arg.io;
12284 sarg.offset = offset;
12285 sarg.mode = SEEK_SET;
12286 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12287 if (state) {
12288 rb_io_close(arg.io);
12289 rb_jump_tag(state);
12290 }
12291 if (arg.argc == 2) arg.argc = 1;
12292 }
12293 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12294}
12295
12296/*
12297 * call-seq:
12298 * IO.binread(path, length = nil, offset = 0) -> string or nil
12299 *
12300 * Behaves like IO.read, except that the stream is opened in binary mode
12301 * with ASCII-8BIT encoding.
12302 *
12303 * When called from class \IO (but not subclasses of \IO),
12304 * this method has potential security vulnerabilities if called with untrusted input;
12305 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12306 *
12307 */
12308
12309static VALUE
12310rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12311{
12312 VALUE offset;
12313 struct foreach_arg arg;
12314 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12315 enum {
12316 oflags = O_RDONLY
12317#ifdef O_BINARY
12318 |O_BINARY
12319#endif
12320 };
12321 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12322
12323 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12324 FilePathValue(argv[0]);
12325 convconfig.enc = rb_ascii8bit_encoding();
12326 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12327 if (NIL_P(arg.io)) return Qnil;
12328 arg.argv = argv+1;
12329 arg.argc = (argc > 1) ? 1 : 0;
12330 if (!NIL_P(offset)) {
12331 struct seek_arg sarg;
12332 int state = 0;
12333 sarg.io = arg.io;
12334 sarg.offset = offset;
12335 sarg.mode = SEEK_SET;
12336 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12337 if (state) {
12338 rb_io_close(arg.io);
12339 rb_jump_tag(state);
12340 }
12341 }
12342 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12343}
12344
12345static VALUE
12346io_s_write0(VALUE v)
12347{
12348 struct write_arg *arg = (void *)v;
12349 return io_write(arg->io,arg->str,arg->nosync);
12350}
12351
12352static VALUE
12353io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12354{
12355 VALUE string, offset, opt;
12356 struct foreach_arg arg;
12357 struct write_arg warg;
12358
12359 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12360
12361 if (NIL_P(opt)) opt = rb_hash_new();
12362 else opt = rb_hash_dup(opt);
12363
12364
12365 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12366 int mode = O_WRONLY|O_CREAT;
12367#ifdef O_BINARY
12368 if (binary) mode |= O_BINARY;
12369#endif
12370 if (NIL_P(offset)) mode |= O_TRUNC;
12371 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12372 }
12373 open_key_args(klass, argc, argv, opt, &arg);
12374
12375#ifndef O_BINARY
12376 if (binary) rb_io_binmode_m(arg.io);
12377#endif
12378
12379 if (NIL_P(arg.io)) return Qnil;
12380 if (!NIL_P(offset)) {
12381 struct seek_arg sarg;
12382 int state = 0;
12383 sarg.io = arg.io;
12384 sarg.offset = offset;
12385 sarg.mode = SEEK_SET;
12386 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12387 if (state) {
12388 rb_io_close(arg.io);
12389 rb_jump_tag(state);
12390 }
12391 }
12392
12393 warg.io = arg.io;
12394 warg.str = string;
12395 warg.nosync = 0;
12396
12397 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12398}
12399
12400/*
12401 * call-seq:
12402 * IO.write(path, data, offset = 0, **opts) -> integer
12403 *
12404 * Opens the stream, writes the given +data+ to it,
12405 * and closes the stream; returns the number of bytes written.
12406 *
12407 * When called from class \IO (but not subclasses of \IO),
12408 * this method has potential security vulnerabilities if called with untrusted input;
12409 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12410 *
12411 * The first argument must be a string that is the path to a file.
12412 *
12413 * With only argument +path+ given, writes the given +data+ to the file at that path:
12414 *
12415 * IO.write('t.tmp', 'abc') # => 3
12416 * File.read('t.tmp') # => "abc"
12417 *
12418 * If +offset+ is zero (the default), the file is overwritten:
12419 *
12420 * IO.write('t.tmp', 'A') # => 1
12421 * File.read('t.tmp') # => "A"
12422 *
12423 * If +offset+ in within the file content, the file is partly overwritten:
12424 *
12425 * IO.write('t.tmp', 'abcdef') # => 3
12426 * File.read('t.tmp') # => "abcdef"
12427 * # Offset within content.
12428 * IO.write('t.tmp', '012', 2) # => 3
12429 * File.read('t.tmp') # => "ab012f"
12430 *
12431 * If +offset+ is outside the file content,
12432 * the file is padded with null characters <tt>"\u0000"</tt>:
12433 *
12434 * IO.write('t.tmp', 'xyz', 10) # => 3
12435 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12436 *
12437 * Optional keyword arguments +opts+ specify:
12438 *
12439 * - {Open Options}[rdoc-ref:IO@Open+Options].
12440 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12441 *
12442 */
12443
12444static VALUE
12445rb_io_s_write(int argc, VALUE *argv, VALUE io)
12446{
12447 return io_s_write(argc, argv, io, 0);
12448}
12449
12450/*
12451 * call-seq:
12452 * IO.binwrite(path, string, offset = 0) -> integer
12453 *
12454 * Behaves like IO.write, except that the stream is opened in binary mode
12455 * with ASCII-8BIT encoding.
12456 *
12457 * When called from class \IO (but not subclasses of \IO),
12458 * this method has potential security vulnerabilities if called with untrusted input;
12459 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12460 *
12461 */
12462
12463static VALUE
12464rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12465{
12466 return io_s_write(argc, argv, io, 1);
12467}
12468
12470 VALUE src;
12471 VALUE dst;
12472 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12473 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12474
12475 rb_io_t *src_fptr;
12476 rb_io_t *dst_fptr;
12477 unsigned close_src : 1;
12478 unsigned close_dst : 1;
12479 int error_no;
12480 rb_off_t total;
12481 const char *syserr;
12482 const char *notimp;
12483 VALUE th;
12484 struct stat src_stat;
12485 struct stat dst_stat;
12486#ifdef HAVE_FCOPYFILE
12487 copyfile_state_t copyfile_state;
12488#endif
12489};
12490
12491static void *
12492exec_interrupts(void *arg)
12493{
12494 VALUE th = (VALUE)arg;
12495 rb_thread_execute_interrupts(th);
12496 return NULL;
12497}
12498
12499/*
12500 * returns TRUE if the preceding system call was interrupted
12501 * so we can continue. If the thread was interrupted, we
12502 * reacquire the GVL to execute interrupts before continuing.
12503 */
12504static int
12505maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12506{
12507 switch (errno) {
12508 case EINTR:
12509#if defined(ERESTART)
12510 case ERESTART:
12511#endif
12512 if (rb_thread_interrupted(stp->th)) {
12513 if (has_gvl)
12514 rb_thread_execute_interrupts(stp->th);
12515 else
12516 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12517 }
12518 return TRUE;
12519 }
12520 return FALSE;
12521}
12522
12524 VALUE scheduler;
12525
12526 rb_io_t *fptr;
12527 short events;
12528
12529 VALUE result;
12530};
12531
12532static void *
12533fiber_scheduler_wait_for(void * _arguments)
12534{
12535 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12536
12537 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12538
12539 return NULL;
12540}
12541
12542#if USE_POLL
12543# define IOWAIT_SYSCALL "poll"
12544STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12545STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12546static int
12547nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12548{
12550 if (scheduler != Qnil) {
12551 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12552 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12553 return RTEST(args.result);
12554 }
12555
12556 int fd = fptr->fd;
12557 if (fd == -1) return 0;
12558
12559 struct pollfd fds;
12560
12561 fds.fd = fd;
12562 fds.events = events;
12563
12564 int timeout_milliseconds = -1;
12565
12566 if (timeout) {
12567 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12568 }
12569
12570 return poll(&fds, 1, timeout_milliseconds);
12571}
12572#else /* !USE_POLL */
12573# define IOWAIT_SYSCALL "select"
12574static int
12575nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12576{
12578 if (scheduler != Qnil) {
12579 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12580 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12581 return RTEST(args.result);
12582 }
12583
12584 int fd = fptr->fd;
12585
12586 if (fd == -1) {
12587 errno = EBADF;
12588 return -1;
12589 }
12590
12591 rb_fdset_t fds;
12592 int ret;
12593
12594 rb_fd_init(&fds);
12595 rb_fd_set(fd, &fds);
12596
12597 switch (events) {
12598 case RB_WAITFD_IN:
12599 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12600 break;
12601 case RB_WAITFD_OUT:
12602 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12603 break;
12604 default:
12605 VM_UNREACHABLE(nogvl_wait_for);
12606 }
12607
12608 rb_fd_term(&fds);
12609
12610 // On timeout, this returns 0.
12611 return ret;
12612}
12613#endif /* !USE_POLL */
12614
12615static int
12616maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12617{
12618 int ret;
12619
12620 do {
12621 if (has_gvl) {
12623 }
12624 else {
12625 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12626 }
12627 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12628
12629 if (ret < 0) {
12630 stp->syserr = IOWAIT_SYSCALL;
12631 stp->error_no = errno;
12632 return ret;
12633 }
12634 return 0;
12635}
12636
12637static int
12638nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12639{
12640 int ret;
12641
12642 do {
12643 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12644 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12645
12646 if (ret < 0) {
12647 stp->syserr = IOWAIT_SYSCALL;
12648 stp->error_no = errno;
12649 return ret;
12650 }
12651 return 0;
12652}
12653
12654#ifdef USE_COPY_FILE_RANGE
12655
12656static ssize_t
12657simple_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)
12658{
12659#ifdef HAVE_COPY_FILE_RANGE
12660 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12661#else
12662 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12663#endif
12664}
12665
12666static int
12667nogvl_copy_file_range(struct copy_stream_struct *stp)
12668{
12669 ssize_t ss;
12670 rb_off_t src_size;
12671 rb_off_t copy_length, src_offset, *src_offset_ptr;
12672
12673 if (!S_ISREG(stp->src_stat.st_mode))
12674 return 0;
12675
12676 src_size = stp->src_stat.st_size;
12677 src_offset = stp->src_offset;
12678 if (src_offset >= (rb_off_t)0) {
12679 src_offset_ptr = &src_offset;
12680 }
12681 else {
12682 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12683 }
12684
12685 copy_length = stp->copy_length;
12686 if (copy_length < (rb_off_t)0) {
12687 if (src_offset < (rb_off_t)0) {
12688 rb_off_t current_offset;
12689 errno = 0;
12690 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12691 if (current_offset < (rb_off_t)0 && errno) {
12692 stp->syserr = "lseek";
12693 stp->error_no = errno;
12694 return (int)current_offset;
12695 }
12696 copy_length = src_size - current_offset;
12697 }
12698 else {
12699 copy_length = src_size - src_offset;
12700 }
12701 }
12702
12703 retry_copy_file_range:
12704# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12705 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12706 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12707# else
12708 ss = (ssize_t)copy_length;
12709# endif
12710 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12711 if (0 < ss) {
12712 stp->total += ss;
12713 copy_length -= ss;
12714 if (0 < copy_length) {
12715 goto retry_copy_file_range;
12716 }
12717 }
12718 if (ss < 0) {
12719 if (maygvl_copy_stream_continue_p(0, stp)) {
12720 goto retry_copy_file_range;
12721 }
12722 switch (errno) {
12723 case EINVAL:
12724 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12725 docker container) */
12726#ifdef ENOSYS
12727 case ENOSYS:
12728#endif
12729#ifdef EXDEV
12730 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12731#endif
12732 return 0;
12733 case EAGAIN:
12734#if EWOULDBLOCK != EAGAIN
12735 case EWOULDBLOCK:
12736#endif
12737 {
12738 int ret = nogvl_copy_stream_wait_write(stp);
12739 if (ret < 0) return ret;
12740 }
12741 goto retry_copy_file_range;
12742 case EBADF:
12743 {
12744 int e = errno;
12745 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12746
12747 if (flags != -1 && flags & O_APPEND) {
12748 return 0;
12749 }
12750 errno = e;
12751 }
12752 }
12753 stp->syserr = "copy_file_range";
12754 stp->error_no = errno;
12755 return (int)ss;
12756 }
12757 return 1;
12758}
12759#endif
12760
12761#ifdef HAVE_FCOPYFILE
12762static int
12763nogvl_fcopyfile(struct copy_stream_struct *stp)
12764{
12765 rb_off_t cur, ss = 0;
12766 const rb_off_t src_offset = stp->src_offset;
12767 int ret;
12768
12769 if (stp->copy_length >= (rb_off_t)0) {
12770 /* copy_length can't be specified in fcopyfile(3) */
12771 return 0;
12772 }
12773
12774 if (!S_ISREG(stp->src_stat.st_mode))
12775 return 0;
12776
12777 if (!S_ISREG(stp->dst_stat.st_mode))
12778 return 0;
12779 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12780 return 0;
12781 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12782 /* fcopyfile(3) appends src IO to dst IO and then truncates
12783 * dst IO to src IO's original size. */
12784 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12785 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12786 if (end > (rb_off_t)0) return 0;
12787 }
12788
12789 if (src_offset > (rb_off_t)0) {
12790 rb_off_t r;
12791
12792 /* get current offset */
12793 errno = 0;
12794 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12795 if (cur < (rb_off_t)0 && errno) {
12796 stp->error_no = errno;
12797 return 1;
12798 }
12799
12800 errno = 0;
12801 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12802 if (r < (rb_off_t)0 && errno) {
12803 stp->error_no = errno;
12804 return 1;
12805 }
12806 }
12807
12808 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12809 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12810 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12811
12812 if (ret == 0) { /* success */
12813 stp->total = ss;
12814 if (src_offset > (rb_off_t)0) {
12815 rb_off_t r;
12816 errno = 0;
12817 /* reset offset */
12818 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12819 if (r < (rb_off_t)0 && errno) {
12820 stp->error_no = errno;
12821 return 1;
12822 }
12823 }
12824 }
12825 else {
12826 switch (errno) {
12827 case ENOTSUP:
12828 case EPERM:
12829 case EINVAL:
12830 return 0;
12831 }
12832 stp->syserr = "fcopyfile";
12833 stp->error_no = errno;
12834 return (int)ret;
12835 }
12836 return 1;
12837}
12838#endif
12839
12840#ifdef HAVE_SENDFILE
12841
12842# ifdef __linux__
12843# define USE_SENDFILE
12844
12845# ifdef HAVE_SYS_SENDFILE_H
12846# include <sys/sendfile.h>
12847# endif
12848
12849static ssize_t
12850simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12851{
12852 return sendfile(out_fd, in_fd, offset, (size_t)count);
12853}
12854
12855# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12856/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12857 * without cpuset -l 0.
12858 */
12859# define USE_SENDFILE
12860
12861static ssize_t
12862simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12863{
12864 int r;
12865 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12866 rb_off_t sbytes;
12867# ifdef __APPLE__
12868 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12869 sbytes = count;
12870# else
12871 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12872# endif
12873 if (r != 0 && sbytes == 0) return r;
12874 if (offset) {
12875 *offset += sbytes;
12876 }
12877 else {
12878 lseek(in_fd, sbytes, SEEK_CUR);
12879 }
12880 return (ssize_t)sbytes;
12881}
12882
12883# endif
12884
12885#endif
12886
12887#ifdef USE_SENDFILE
12888static int
12889nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12890{
12891 ssize_t ss;
12892 rb_off_t src_size;
12893 rb_off_t copy_length;
12894 rb_off_t src_offset;
12895 int use_pread;
12896
12897 if (!S_ISREG(stp->src_stat.st_mode))
12898 return 0;
12899
12900 src_size = stp->src_stat.st_size;
12901#ifndef __linux__
12902 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12903 return 0;
12904#endif
12905
12906 src_offset = stp->src_offset;
12907 use_pread = src_offset >= (rb_off_t)0;
12908
12909 copy_length = stp->copy_length;
12910 if (copy_length < (rb_off_t)0) {
12911 if (use_pread)
12912 copy_length = src_size - src_offset;
12913 else {
12914 rb_off_t cur;
12915 errno = 0;
12916 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12917 if (cur < (rb_off_t)0 && errno) {
12918 stp->syserr = "lseek";
12919 stp->error_no = errno;
12920 return (int)cur;
12921 }
12922 copy_length = src_size - cur;
12923 }
12924 }
12925
12926 retry_sendfile:
12927# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12928 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12929 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12930# else
12931 ss = (ssize_t)copy_length;
12932# endif
12933 if (use_pread) {
12934 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12935 }
12936 else {
12937 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12938 }
12939 if (0 < ss) {
12940 stp->total += ss;
12941 copy_length -= ss;
12942 if (0 < copy_length) {
12943 goto retry_sendfile;
12944 }
12945 }
12946 if (ss < 0) {
12947 if (maygvl_copy_stream_continue_p(0, stp))
12948 goto retry_sendfile;
12949 switch (errno) {
12950 case EINVAL:
12951#ifdef ENOSYS
12952 case ENOSYS:
12953#endif
12954#ifdef EOPNOTSUP
12955 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12956 see also: [Feature #16965] */
12957 case EOPNOTSUP:
12958#endif
12959 return 0;
12960 case EAGAIN:
12961#if EWOULDBLOCK != EAGAIN
12962 case EWOULDBLOCK:
12963#endif
12964 {
12965 int ret;
12966#ifndef __linux__
12967 /*
12968 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12969 * select() reports regular files to always be "ready", so
12970 * there is no need to select() on it.
12971 * Other OSes may have the same limitation for sendfile() which
12972 * allow us to bypass maygvl_copy_stream_wait_read()...
12973 */
12974 ret = maygvl_copy_stream_wait_read(0, stp);
12975 if (ret < 0) return ret;
12976#endif
12977 ret = nogvl_copy_stream_wait_write(stp);
12978 if (ret < 0) return ret;
12979 }
12980 goto retry_sendfile;
12981 }
12982 stp->syserr = "sendfile";
12983 stp->error_no = errno;
12984 return (int)ss;
12985 }
12986 return 1;
12987}
12988#endif
12989
12990static ssize_t
12991maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
12992{
12993 if (has_gvl)
12994 return rb_io_read_memory(fptr, buf, count);
12995 else
12996 return read(fptr->fd, buf, count);
12997}
12998
12999static ssize_t
13000maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13001{
13002 ssize_t ss;
13003 retry_read:
13004 if (offset < (rb_off_t)0) {
13005 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13006 }
13007 else {
13008 ss = pread(stp->src_fptr->fd, buf, len, offset);
13009 }
13010 if (ss == 0) {
13011 return 0;
13012 }
13013 if (ss < 0) {
13014 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13015 goto retry_read;
13016 switch (errno) {
13017 case EAGAIN:
13018#if EWOULDBLOCK != EAGAIN
13019 case EWOULDBLOCK:
13020#endif
13021 {
13022 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13023 if (ret < 0) return ret;
13024 }
13025 goto retry_read;
13026#ifdef ENOSYS
13027 case ENOSYS:
13028 stp->notimp = "pread";
13029 return ss;
13030#endif
13031 }
13032 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13033 stp->error_no = errno;
13034 }
13035 return ss;
13036}
13037
13038static int
13039nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13040{
13041 ssize_t ss;
13042 int off = 0;
13043 while (len) {
13044 ss = write(stp->dst_fptr->fd, buf+off, len);
13045 if (ss < 0) {
13046 if (maygvl_copy_stream_continue_p(0, stp))
13047 continue;
13048 if (io_again_p(errno)) {
13049 int ret = nogvl_copy_stream_wait_write(stp);
13050 if (ret < 0) return ret;
13051 continue;
13052 }
13053 stp->syserr = "write";
13054 stp->error_no = errno;
13055 return (int)ss;
13056 }
13057 off += (int)ss;
13058 len -= (int)ss;
13059 stp->total += ss;
13060 }
13061 return 0;
13062}
13063
13064static void
13065nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13066{
13067 char buf[1024*16];
13068 size_t len;
13069 ssize_t ss;
13070 int ret;
13071 rb_off_t copy_length;
13072 rb_off_t src_offset;
13073 int use_eof;
13074 int use_pread;
13075
13076 copy_length = stp->copy_length;
13077 use_eof = copy_length < (rb_off_t)0;
13078 src_offset = stp->src_offset;
13079 use_pread = src_offset >= (rb_off_t)0;
13080
13081 if (use_pread && stp->close_src) {
13082 rb_off_t r;
13083 errno = 0;
13084 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13085 if (r < (rb_off_t)0 && errno) {
13086 stp->syserr = "lseek";
13087 stp->error_no = errno;
13088 return;
13089 }
13090 src_offset = (rb_off_t)-1;
13091 use_pread = 0;
13092 }
13093
13094 while (use_eof || 0 < copy_length) {
13095 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13096 len = (size_t)copy_length;
13097 }
13098 else {
13099 len = sizeof(buf);
13100 }
13101 if (use_pread) {
13102 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13103 if (0 < ss)
13104 src_offset += ss;
13105 }
13106 else {
13107 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13108 }
13109 if (ss <= 0) /* EOF or error */
13110 return;
13111
13112 ret = nogvl_copy_stream_write(stp, buf, ss);
13113 if (ret < 0)
13114 return;
13115
13116 if (!use_eof)
13117 copy_length -= ss;
13118 }
13119}
13120
13121static void *
13122nogvl_copy_stream_func(void *arg)
13123{
13124 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13125#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13126 int ret;
13127#endif
13128
13129#ifdef USE_COPY_FILE_RANGE
13130 ret = nogvl_copy_file_range(stp);
13131 if (ret != 0)
13132 goto finish; /* error or success */
13133#endif
13134
13135#ifdef HAVE_FCOPYFILE
13136 ret = nogvl_fcopyfile(stp);
13137 if (ret != 0)
13138 goto finish; /* error or success */
13139#endif
13140
13141#ifdef USE_SENDFILE
13142 ret = nogvl_copy_stream_sendfile(stp);
13143 if (ret != 0)
13144 goto finish; /* error or success */
13145#endif
13146
13147 nogvl_copy_stream_read_write(stp);
13148
13149#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13150 finish:
13151#endif
13152 return 0;
13153}
13154
13155static VALUE
13156copy_stream_fallback_body(VALUE arg)
13157{
13158 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13159 const int buflen = 16*1024;
13160 VALUE n;
13161 VALUE buf = rb_str_buf_new(buflen);
13162 rb_off_t rest = stp->copy_length;
13163 rb_off_t off = stp->src_offset;
13164 ID read_method = id_readpartial;
13165
13166 if (!stp->src_fptr) {
13167 if (!rb_respond_to(stp->src, read_method)) {
13168 read_method = id_read;
13169 }
13170 }
13171
13172 while (1) {
13173 long numwrote;
13174 long l;
13175 rb_str_make_independent(buf);
13176 if (stp->copy_length < (rb_off_t)0) {
13177 l = buflen;
13178 }
13179 else {
13180 if (rest == 0) {
13181 rb_str_resize(buf, 0);
13182 break;
13183 }
13184 l = buflen < rest ? buflen : (long)rest;
13185 }
13186 if (!stp->src_fptr) {
13187 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13188
13189 if (read_method == id_read && NIL_P(rc))
13190 break;
13191 }
13192 else {
13193 ssize_t ss;
13194 rb_str_resize(buf, buflen);
13195 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13196 rb_str_resize(buf, ss > 0 ? ss : 0);
13197 if (ss < 0)
13198 return Qnil;
13199 if (ss == 0)
13200 rb_eof_error();
13201 if (off >= (rb_off_t)0)
13202 off += ss;
13203 }
13204 n = rb_io_write(stp->dst, buf);
13205 numwrote = NUM2LONG(n);
13206 stp->total += numwrote;
13207 rest -= numwrote;
13208 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13209 break;
13210 }
13211 }
13212
13213 return Qnil;
13214}
13215
13216static VALUE
13217copy_stream_fallback(struct copy_stream_struct *stp)
13218{
13219 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13220 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13221 }
13222 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13223 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13224 rb_eEOFError, (VALUE)0);
13225 return Qnil;
13226}
13227
13228static VALUE
13229copy_stream_body(VALUE arg)
13230{
13231 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13232 VALUE src_io = stp->src, dst_io = stp->dst;
13233 const int common_oflags = 0
13234#ifdef O_NOCTTY
13235 | O_NOCTTY
13236#endif
13237 ;
13238
13239 stp->th = rb_thread_current();
13240
13241 stp->total = 0;
13242
13243 if (src_io == argf ||
13244 !(RB_TYPE_P(src_io, T_FILE) ||
13245 RB_TYPE_P(src_io, T_STRING) ||
13246 rb_respond_to(src_io, rb_intern("to_path")))) {
13247 stp->src_fptr = NULL;
13248 }
13249 else {
13250 int stat_ret;
13251 VALUE tmp_io = rb_io_check_io(src_io);
13252 if (!NIL_P(tmp_io)) {
13253 src_io = tmp_io;
13254 }
13255 else if (!RB_TYPE_P(src_io, T_FILE)) {
13256 VALUE args[2];
13257 FilePathValue(src_io);
13258 args[0] = src_io;
13259 args[1] = INT2NUM(O_RDONLY|common_oflags);
13260 src_io = rb_class_new_instance(2, args, rb_cFile);
13261 stp->src = src_io;
13262 stp->close_src = 1;
13263 }
13264 RB_IO_POINTER(src_io, stp->src_fptr);
13265 rb_io_check_byte_readable(stp->src_fptr);
13266
13267 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13268 if (stat_ret < 0) {
13269 stp->syserr = "fstat";
13270 stp->error_no = errno;
13271 return Qnil;
13272 }
13273 }
13274
13275 if (dst_io == argf ||
13276 !(RB_TYPE_P(dst_io, T_FILE) ||
13277 RB_TYPE_P(dst_io, T_STRING) ||
13278 rb_respond_to(dst_io, rb_intern("to_path")))) {
13279 stp->dst_fptr = NULL;
13280 }
13281 else {
13282 int stat_ret;
13283 VALUE tmp_io = rb_io_check_io(dst_io);
13284 if (!NIL_P(tmp_io)) {
13285 dst_io = GetWriteIO(tmp_io);
13286 }
13287 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13288 VALUE args[3];
13289 FilePathValue(dst_io);
13290 args[0] = dst_io;
13291 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13292 args[2] = INT2FIX(0666);
13293 dst_io = rb_class_new_instance(3, args, rb_cFile);
13294 stp->dst = dst_io;
13295 stp->close_dst = 1;
13296 }
13297 else {
13298 dst_io = GetWriteIO(dst_io);
13299 stp->dst = dst_io;
13300 }
13301 RB_IO_POINTER(dst_io, stp->dst_fptr);
13302 rb_io_check_writable(stp->dst_fptr);
13303
13304 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13305 if (stat_ret < 0) {
13306 stp->syserr = "fstat";
13307 stp->error_no = errno;
13308 return Qnil;
13309 }
13310 }
13311
13312#ifdef O_BINARY
13313 if (stp->src_fptr)
13314 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13315#endif
13316 if (stp->dst_fptr)
13317 io_ascii8bit_binmode(stp->dst_fptr);
13318
13319 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13320 size_t len = stp->src_fptr->rbuf.len;
13321 VALUE str;
13322 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13323 len = (size_t)stp->copy_length;
13324 }
13325 str = rb_str_buf_new(len);
13326 rb_str_resize(str,len);
13327 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13328 if (stp->dst_fptr) { /* IO or filename */
13329 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13330 rb_sys_fail_on_write(stp->dst_fptr);
13331 }
13332 else /* others such as StringIO */
13333 rb_io_write(dst_io, str);
13334 rb_str_resize(str, 0);
13335 stp->total += len;
13336 if (stp->copy_length >= (rb_off_t)0)
13337 stp->copy_length -= len;
13338 }
13339
13340 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13341 rb_raise(rb_eIOError, "flush failed");
13342 }
13343
13344 if (stp->copy_length == 0)
13345 return Qnil;
13346
13347 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13348 return copy_stream_fallback(stp);
13349 }
13350
13351 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13352 return Qnil;
13353}
13354
13355static VALUE
13356copy_stream_finalize(VALUE arg)
13357{
13358 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13359
13360#ifdef HAVE_FCOPYFILE
13361 if (stp->copyfile_state) {
13362 copyfile_state_free(stp->copyfile_state);
13363 }
13364#endif
13365
13366 if (stp->close_src) {
13367 rb_io_close_m(stp->src);
13368 }
13369 if (stp->close_dst) {
13370 rb_io_close_m(stp->dst);
13371 }
13372 if (stp->syserr) {
13373 rb_syserr_fail(stp->error_no, stp->syserr);
13374 }
13375 if (stp->notimp) {
13376 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13377 }
13378 return Qnil;
13379}
13380
13381/*
13382 * call-seq:
13383 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13384 *
13385 * Copies from the given +src+ to the given +dst+,
13386 * returning the number of bytes copied.
13387 *
13388 * - The given +src+ must be one of the following:
13389 *
13390 * - The path to a readable file, from which source data is to be read.
13391 * - An \IO-like object, opened for reading and capable of responding
13392 * to method +:readpartial+ or method +:read+.
13393 *
13394 * - The given +dst+ must be one of the following:
13395 *
13396 * - The path to a writable file, to which data is to be written.
13397 * - An \IO-like object, opened for writing and capable of responding
13398 * to method +:write+.
13399 *
13400 * The examples here use file <tt>t.txt</tt> as source:
13401 *
13402 * File.read('t.txt')
13403 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13404 * File.read('t.txt').size # => 47
13405 *
13406 * If only arguments +src+ and +dst+ are given,
13407 * the entire source stream is copied:
13408 *
13409 * # Paths.
13410 * IO.copy_stream('t.txt', 't.tmp') # => 47
13411 *
13412 * # IOs (recall that a File is also an IO).
13413 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13414 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13415 * IO.copy_stream(src_io, dst_io) # => 47
13416 * src_io.close
13417 * dst_io.close
13418 *
13419 * With argument +src_length+ a non-negative integer,
13420 * no more than that many bytes are copied:
13421 *
13422 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13423 * File.read('t.tmp') # => "First line"
13424 *
13425 * With argument +src_offset+ also given,
13426 * the source stream is read beginning at that offset:
13427 *
13428 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13429 * IO.read('t.tmp') # => "Second line"
13430 *
13431 */
13432static VALUE
13433rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13434{
13435 VALUE src, dst, length, src_offset;
13436 struct copy_stream_struct st;
13437
13438 MEMZERO(&st, struct copy_stream_struct, 1);
13439
13440 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13441
13442 st.src = src;
13443 st.dst = dst;
13444
13445 st.src_fptr = NULL;
13446 st.dst_fptr = NULL;
13447
13448 if (NIL_P(length))
13449 st.copy_length = (rb_off_t)-1;
13450 else
13451 st.copy_length = NUM2OFFT(length);
13452
13453 if (NIL_P(src_offset))
13454 st.src_offset = (rb_off_t)-1;
13455 else
13456 st.src_offset = NUM2OFFT(src_offset);
13457
13458 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13459
13460 return OFFT2NUM(st.total);
13461}
13462
13463/*
13464 * call-seq:
13465 * external_encoding -> encoding or nil
13466 *
13467 * Returns the Encoding object that represents the encoding of the stream,
13468 * or +nil+ if the stream is in write mode and no encoding is specified.
13469 *
13470 * See {Encodings}[rdoc-ref:File@Encodings].
13471 *
13472 */
13473
13474static VALUE
13475rb_io_external_encoding(VALUE io)
13476{
13477 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13478
13479 if (fptr->encs.enc2) {
13480 return rb_enc_from_encoding(fptr->encs.enc2);
13481 }
13482 if (fptr->mode & FMODE_WRITABLE) {
13483 if (fptr->encs.enc)
13484 return rb_enc_from_encoding(fptr->encs.enc);
13485 return Qnil;
13486 }
13487 return rb_enc_from_encoding(io_read_encoding(fptr));
13488}
13489
13490/*
13491 * call-seq:
13492 * internal_encoding -> encoding or nil
13493 *
13494 * Returns the Encoding object that represents the encoding of the internal string,
13495 * if conversion is specified,
13496 * or +nil+ otherwise.
13497 *
13498 * See {Encodings}[rdoc-ref:File@Encodings].
13499 *
13500 */
13501
13502static VALUE
13503rb_io_internal_encoding(VALUE io)
13504{
13505 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13506
13507 if (!fptr->encs.enc2) return Qnil;
13508 return rb_enc_from_encoding(io_read_encoding(fptr));
13509}
13510
13511/*
13512 * call-seq:
13513 * set_encoding(ext_enc) -> self
13514 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13515 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13516 *
13517 * See {Encodings}[rdoc-ref:File@Encodings].
13518 *
13519 * Argument +ext_enc+, if given, must be an Encoding object
13520 * or a String with the encoding name;
13521 * it is assigned as the encoding for the stream.
13522 *
13523 * Argument +int_enc+, if given, must be an Encoding object
13524 * or a String with the encoding name;
13525 * it is assigned as the encoding for the internal string.
13526 *
13527 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13528 * containing two colon-separated encoding names;
13529 * corresponding Encoding objects are assigned as the external
13530 * and internal encodings for the stream.
13531 *
13532 * If the external encoding of a string is binary/ASCII-8BIT,
13533 * the internal encoding of the string is set to nil, since no
13534 * transcoding is needed.
13535 *
13536 * Optional keyword arguments +enc_opts+ specify
13537 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13538 *
13539 */
13540
13541static VALUE
13542rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13543{
13544 rb_io_t *fptr;
13545 VALUE v1, v2, opt;
13546
13547 if (!RB_TYPE_P(io, T_FILE)) {
13548 return forward(io, id_set_encoding, argc, argv);
13549 }
13550
13551 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13552 GetOpenFile(io, fptr);
13553 io_encoding_set(fptr, v1, v2, opt);
13554 return io;
13555}
13556
13557void
13558rb_stdio_set_default_encoding(void)
13559{
13560 VALUE val = Qnil;
13561
13562#ifdef _WIN32
13563 if (isatty(fileno(stdin))) {
13564 rb_encoding *external = rb_locale_encoding();
13565 rb_encoding *internal = rb_default_internal_encoding();
13566 if (!internal) internal = rb_default_external_encoding();
13567 io_encoding_set(RFILE(rb_stdin)->fptr,
13568 rb_enc_from_encoding(external),
13569 rb_enc_from_encoding(internal),
13570 Qnil);
13571 }
13572 else
13573#endif
13574 rb_io_set_encoding(1, &val, rb_stdin);
13575 rb_io_set_encoding(1, &val, rb_stdout);
13576 rb_io_set_encoding(1, &val, rb_stderr);
13577}
13578
13579static inline int
13580global_argf_p(VALUE arg)
13581{
13582 return arg == argf;
13583}
13584
13585typedef VALUE (*argf_encoding_func)(VALUE io);
13586
13587static VALUE
13588argf_encoding(VALUE argf, argf_encoding_func func)
13589{
13590 if (!RTEST(ARGF.current_file)) {
13591 return rb_enc_default_external();
13592 }
13593 return func(rb_io_check_io(ARGF.current_file));
13594}
13595
13596/*
13597 * call-seq:
13598 * ARGF.external_encoding -> encoding
13599 *
13600 * Returns the external encoding for files read from ARGF as an Encoding
13601 * object. The external encoding is the encoding of the text as stored in a
13602 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13603 * represent this text within Ruby.
13604 *
13605 * To set the external encoding use ARGF.set_encoding.
13606 *
13607 * For example:
13608 *
13609 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13610 *
13611 */
13612static VALUE
13613argf_external_encoding(VALUE argf)
13614{
13615 return argf_encoding(argf, rb_io_external_encoding);
13616}
13617
13618/*
13619 * call-seq:
13620 * ARGF.internal_encoding -> encoding
13621 *
13622 * Returns the internal encoding for strings read from ARGF as an
13623 * Encoding object.
13624 *
13625 * If ARGF.set_encoding has been called with two encoding names, the second
13626 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13627 * value is returned. Failing that, if a default external encoding was
13628 * specified on the command-line, that value is used. If the encoding is
13629 * unknown, +nil+ is returned.
13630 */
13631static VALUE
13632argf_internal_encoding(VALUE argf)
13633{
13634 return argf_encoding(argf, rb_io_internal_encoding);
13635}
13636
13637/*
13638 * call-seq:
13639 * ARGF.set_encoding(ext_enc) -> ARGF
13640 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13641 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13642 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13643 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13644 *
13645 * If single argument is specified, strings read from ARGF are tagged with
13646 * the encoding specified.
13647 *
13648 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13649 * the read string is converted from the first encoding (external encoding)
13650 * to the second encoding (internal encoding), then tagged with the second
13651 * encoding.
13652 *
13653 * If two arguments are specified, they must be encoding objects or encoding
13654 * names. Again, the first specifies the external encoding; the second
13655 * specifies the internal encoding.
13656 *
13657 * If the external encoding and the internal encoding are specified, the
13658 * optional Hash argument can be used to adjust the conversion process. The
13659 * structure of this hash is explained in the String#encode documentation.
13660 *
13661 * For example:
13662 *
13663 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13664 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13665 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13666 * # to UTF-8.
13667 */
13668static VALUE
13669argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13670{
13671 rb_io_t *fptr;
13672
13673 if (!next_argv()) {
13674 rb_raise(rb_eArgError, "no stream to set encoding");
13675 }
13676 rb_io_set_encoding(argc, argv, ARGF.current_file);
13677 GetOpenFile(ARGF.current_file, fptr);
13678 ARGF.encs = fptr->encs;
13679 return argf;
13680}
13681
13682/*
13683 * call-seq:
13684 * ARGF.tell -> Integer
13685 * ARGF.pos -> Integer
13686 *
13687 * Returns the current offset (in bytes) of the current file in ARGF.
13688 *
13689 * ARGF.pos #=> 0
13690 * ARGF.gets #=> "This is line one\n"
13691 * ARGF.pos #=> 17
13692 *
13693 */
13694static VALUE
13695argf_tell(VALUE argf)
13696{
13697 if (!next_argv()) {
13698 rb_raise(rb_eArgError, "no stream to tell");
13699 }
13700 ARGF_FORWARD(0, 0);
13701 return rb_io_tell(ARGF.current_file);
13702}
13703
13704/*
13705 * call-seq:
13706 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13707 *
13708 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13709 * the value of _whence_. See IO#seek for further details.
13710 */
13711static VALUE
13712argf_seek_m(int argc, VALUE *argv, VALUE argf)
13713{
13714 if (!next_argv()) {
13715 rb_raise(rb_eArgError, "no stream to seek");
13716 }
13717 ARGF_FORWARD(argc, argv);
13718 return rb_io_seek_m(argc, argv, ARGF.current_file);
13719}
13720
13721/*
13722 * call-seq:
13723 * ARGF.pos = position -> Integer
13724 *
13725 * Seeks to the position given by _position_ (in bytes) in ARGF.
13726 *
13727 * For example:
13728 *
13729 * ARGF.pos = 17
13730 * ARGF.gets #=> "This is line two\n"
13731 */
13732static VALUE
13733argf_set_pos(VALUE argf, VALUE offset)
13734{
13735 if (!next_argv()) {
13736 rb_raise(rb_eArgError, "no stream to set position");
13737 }
13738 ARGF_FORWARD(1, &offset);
13739 return rb_io_set_pos(ARGF.current_file, offset);
13740}
13741
13742/*
13743 * call-seq:
13744 * ARGF.rewind -> 0
13745 *
13746 * Positions the current file to the beginning of input, resetting
13747 * ARGF.lineno to zero.
13748 *
13749 * ARGF.readline #=> "This is line one\n"
13750 * ARGF.rewind #=> 0
13751 * ARGF.lineno #=> 0
13752 * ARGF.readline #=> "This is line one\n"
13753 */
13754static VALUE
13755argf_rewind(VALUE argf)
13756{
13757 VALUE ret;
13758 int old_lineno;
13759
13760 if (!next_argv()) {
13761 rb_raise(rb_eArgError, "no stream to rewind");
13762 }
13763 ARGF_FORWARD(0, 0);
13764 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13765 ret = rb_io_rewind(ARGF.current_file);
13766 if (!global_argf_p(argf)) {
13767 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13768 }
13769 return ret;
13770}
13771
13772/*
13773 * call-seq:
13774 * ARGF.fileno -> integer
13775 * ARGF.to_i -> integer
13776 *
13777 * Returns an integer representing the numeric file descriptor for
13778 * the current file. Raises an ArgumentError if there isn't a current file.
13779 *
13780 * ARGF.fileno #=> 3
13781 */
13782static VALUE
13783argf_fileno(VALUE argf)
13784{
13785 if (!next_argv()) {
13786 rb_raise(rb_eArgError, "no stream");
13787 }
13788 ARGF_FORWARD(0, 0);
13789 return rb_io_fileno(ARGF.current_file);
13790}
13791
13792/*
13793 * call-seq:
13794 * ARGF.to_io -> IO
13795 *
13796 * Returns an IO object representing the current file. This will be a
13797 * File object unless the current file is a stream such as STDIN.
13798 *
13799 * For example:
13800 *
13801 * ARGF.to_io #=> #<File:glark.txt>
13802 * ARGF.to_io #=> #<IO:<STDIN>>
13803 */
13804static VALUE
13805argf_to_io(VALUE argf)
13806{
13807 next_argv();
13808 ARGF_FORWARD(0, 0);
13809 return ARGF.current_file;
13810}
13811
13812/*
13813 * call-seq:
13814 * ARGF.eof? -> true or false
13815 * ARGF.eof -> true or false
13816 *
13817 * Returns true if the current file in ARGF is at end of file, i.e. it has
13818 * no data to read. The stream must be opened for reading or an IOError
13819 * will be raised.
13820 *
13821 * $ echo "eof" | ruby argf.rb
13822 *
13823 * ARGF.eof? #=> false
13824 * 3.times { ARGF.readchar }
13825 * ARGF.eof? #=> false
13826 * ARGF.readchar #=> "\n"
13827 * ARGF.eof? #=> true
13828 */
13829
13830static VALUE
13831argf_eof(VALUE argf)
13832{
13833 next_argv();
13834 if (RTEST(ARGF.current_file)) {
13835 if (ARGF.init_p == 0) return Qtrue;
13836 next_argv();
13837 ARGF_FORWARD(0, 0);
13838 if (rb_io_eof(ARGF.current_file)) {
13839 return Qtrue;
13840 }
13841 }
13842 return Qfalse;
13843}
13844
13845/*
13846 * call-seq:
13847 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13848 *
13849 * Reads _length_ bytes from ARGF. The files named on the command line
13850 * are concatenated and treated as a single file by this method, so when
13851 * called without arguments the contents of this pseudo file are returned in
13852 * their entirety.
13853 *
13854 * _length_ must be a non-negative integer or +nil+.
13855 *
13856 * If _length_ is a positive integer, +read+ tries to read
13857 * _length_ bytes without any conversion (binary mode).
13858 * It returns +nil+ if an EOF is encountered before anything can be read.
13859 * Fewer than _length_ bytes are returned if an EOF is encountered during
13860 * the read.
13861 * In the case of an integer _length_, the resulting string is always
13862 * in ASCII-8BIT encoding.
13863 *
13864 * If _length_ is omitted or is +nil+, it reads until EOF
13865 * and the encoding conversion is applied, if applicable.
13866 * A string is returned even if EOF is encountered before any data is read.
13867 *
13868 * If _length_ is zero, it returns an empty string (<code>""</code>).
13869 *
13870 * If the optional _outbuf_ argument is present,
13871 * it must reference a String, which will receive the data.
13872 * The _outbuf_ will contain only the received data after the method call
13873 * even if it is not empty at the beginning.
13874 *
13875 * For example:
13876 *
13877 * $ echo "small" > small.txt
13878 * $ echo "large" > large.txt
13879 * $ ./glark.rb small.txt large.txt
13880 *
13881 * ARGF.read #=> "small\nlarge"
13882 * ARGF.read(200) #=> "small\nlarge"
13883 * ARGF.read(2) #=> "sm"
13884 * ARGF.read(0) #=> ""
13885 *
13886 * Note that this method behaves like the fread() function in C.
13887 * This means it retries to invoke read(2) system calls to read data
13888 * with the specified length.
13889 * If you need the behavior like a single read(2) system call,
13890 * consider ARGF#readpartial or ARGF#read_nonblock.
13891 */
13892
13893static VALUE
13894argf_read(int argc, VALUE *argv, VALUE argf)
13895{
13896 VALUE tmp, str, length;
13897 long len = 0;
13898
13899 rb_scan_args(argc, argv, "02", &length, &str);
13900 if (!NIL_P(length)) {
13901 len = NUM2LONG(argv[0]);
13902 }
13903 if (!NIL_P(str)) {
13904 StringValue(str);
13905 rb_str_resize(str,0);
13906 argv[1] = Qnil;
13907 }
13908
13909 retry:
13910 if (!next_argv()) {
13911 return str;
13912 }
13913 if (ARGF_GENERIC_INPUT_P()) {
13914 tmp = argf_forward(argc, argv, argf);
13915 }
13916 else {
13917 tmp = io_read(argc, argv, ARGF.current_file);
13918 }
13919 if (NIL_P(str)) str = tmp;
13920 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13921 if (NIL_P(tmp) || NIL_P(length)) {
13922 if (ARGF.next_p != -1) {
13923 argf_close(argf);
13924 ARGF.next_p = 1;
13925 goto retry;
13926 }
13927 }
13928 else if (argc >= 1) {
13929 long slen = RSTRING_LEN(str);
13930 if (slen < len) {
13931 argv[0] = LONG2NUM(len - slen);
13932 goto retry;
13933 }
13934 }
13935 return str;
13936}
13937
13939 int argc;
13940 VALUE *argv;
13941 VALUE argf;
13942};
13943
13944static VALUE
13945argf_forward_call(VALUE arg)
13946{
13947 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13948 argf_forward(p->argc, p->argv, p->argf);
13949 return Qnil;
13950}
13951
13952static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13953 int nonblock);
13954
13955/*
13956 * call-seq:
13957 * ARGF.readpartial(maxlen) -> string
13958 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13959 *
13960 * Reads at most _maxlen_ bytes from the ARGF stream.
13961 *
13962 * If the optional _outbuf_ argument is present,
13963 * it must reference a String, which will receive the data.
13964 * The _outbuf_ will contain only the received data after the method call
13965 * even if it is not empty at the beginning.
13966 *
13967 * It raises EOFError on end of ARGF stream.
13968 * Since ARGF stream is a concatenation of multiple files,
13969 * internally EOF is occur for each file.
13970 * ARGF.readpartial returns empty strings for EOFs except the last one and
13971 * raises EOFError for the last one.
13972 *
13973 */
13974
13975static VALUE
13976argf_readpartial(int argc, VALUE *argv, VALUE argf)
13977{
13978 return argf_getpartial(argc, argv, argf, Qnil, 0);
13979}
13980
13981/*
13982 * call-seq:
13983 * ARGF.read_nonblock(maxlen[, options]) -> string
13984 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13985 *
13986 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13987 */
13988
13989static VALUE
13990argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13991{
13992 VALUE opts;
13993
13994 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
13995
13996 if (!NIL_P(opts))
13997 argc--;
13998
13999 return argf_getpartial(argc, argv, argf, opts, 1);
14000}
14001
14002static VALUE
14003argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14004{
14005 VALUE tmp, str, length;
14006 int no_exception;
14007
14008 rb_scan_args(argc, argv, "11", &length, &str);
14009 if (!NIL_P(str)) {
14010 StringValue(str);
14011 argv[1] = str;
14012 }
14013 no_exception = no_exception_p(opts);
14014
14015 if (!next_argv()) {
14016 if (!NIL_P(str)) {
14017 rb_str_resize(str, 0);
14018 }
14019 rb_eof_error();
14020 }
14021 if (ARGF_GENERIC_INPUT_P()) {
14022 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14023 struct argf_call_arg arg;
14024 arg.argc = argc;
14025 arg.argv = argv;
14026 arg.argf = argf;
14027 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14028 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14029 }
14030 else {
14031 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14032 }
14033 if (NIL_P(tmp)) {
14034 if (ARGF.next_p == -1) {
14035 return io_nonblock_eof(no_exception);
14036 }
14037 argf_close(argf);
14038 ARGF.next_p = 1;
14039 if (RARRAY_LEN(ARGF.argv) == 0) {
14040 return io_nonblock_eof(no_exception);
14041 }
14042 if (NIL_P(str))
14043 str = rb_str_new(NULL, 0);
14044 return str;
14045 }
14046 return tmp;
14047}
14048
14049/*
14050 * call-seq:
14051 * ARGF.getc -> String or nil
14052 *
14053 * Reads the next character from ARGF and returns it as a String. Returns
14054 * +nil+ at the end of the stream.
14055 *
14056 * ARGF treats the files named on the command line as a single file created
14057 * by concatenating their contents. After returning the last character of the
14058 * first file, it returns the first character of the second file, and so on.
14059 *
14060 * For example:
14061 *
14062 * $ echo "foo" > file
14063 * $ ruby argf.rb file
14064 *
14065 * ARGF.getc #=> "f"
14066 * ARGF.getc #=> "o"
14067 * ARGF.getc #=> "o"
14068 * ARGF.getc #=> "\n"
14069 * ARGF.getc #=> nil
14070 * ARGF.getc #=> nil
14071 */
14072static VALUE
14073argf_getc(VALUE argf)
14074{
14075 VALUE ch;
14076
14077 retry:
14078 if (!next_argv()) return Qnil;
14079 if (ARGF_GENERIC_INPUT_P()) {
14080 ch = forward_current(rb_intern("getc"), 0, 0);
14081 }
14082 else {
14083 ch = rb_io_getc(ARGF.current_file);
14084 }
14085 if (NIL_P(ch) && ARGF.next_p != -1) {
14086 argf_close(argf);
14087 ARGF.next_p = 1;
14088 goto retry;
14089 }
14090
14091 return ch;
14092}
14093
14094/*
14095 * call-seq:
14096 * ARGF.getbyte -> Integer or nil
14097 *
14098 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14099 * the end of the stream.
14100 *
14101 * For example:
14102 *
14103 * $ echo "foo" > file
14104 * $ ruby argf.rb file
14105 *
14106 * ARGF.getbyte #=> 102
14107 * ARGF.getbyte #=> 111
14108 * ARGF.getbyte #=> 111
14109 * ARGF.getbyte #=> 10
14110 * ARGF.getbyte #=> nil
14111 */
14112static VALUE
14113argf_getbyte(VALUE argf)
14114{
14115 VALUE ch;
14116
14117 retry:
14118 if (!next_argv()) return Qnil;
14119 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14120 ch = forward_current(rb_intern("getbyte"), 0, 0);
14121 }
14122 else {
14123 ch = rb_io_getbyte(ARGF.current_file);
14124 }
14125 if (NIL_P(ch) && ARGF.next_p != -1) {
14126 argf_close(argf);
14127 ARGF.next_p = 1;
14128 goto retry;
14129 }
14130
14131 return ch;
14132}
14133
14134/*
14135 * call-seq:
14136 * ARGF.readchar -> String or nil
14137 *
14138 * Reads the next character from ARGF and returns it as a String. Raises
14139 * an EOFError after the last character of the last file has been read.
14140 *
14141 * For example:
14142 *
14143 * $ echo "foo" > file
14144 * $ ruby argf.rb file
14145 *
14146 * ARGF.readchar #=> "f"
14147 * ARGF.readchar #=> "o"
14148 * ARGF.readchar #=> "o"
14149 * ARGF.readchar #=> "\n"
14150 * ARGF.readchar #=> end of file reached (EOFError)
14151 */
14152static VALUE
14153argf_readchar(VALUE argf)
14154{
14155 VALUE ch;
14156
14157 retry:
14158 if (!next_argv()) rb_eof_error();
14159 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14160 ch = forward_current(rb_intern("getc"), 0, 0);
14161 }
14162 else {
14163 ch = rb_io_getc(ARGF.current_file);
14164 }
14165 if (NIL_P(ch) && ARGF.next_p != -1) {
14166 argf_close(argf);
14167 ARGF.next_p = 1;
14168 goto retry;
14169 }
14170
14171 return ch;
14172}
14173
14174/*
14175 * call-seq:
14176 * ARGF.readbyte -> Integer
14177 *
14178 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14179 * an EOFError after the last byte of the last file has been read.
14180 *
14181 * For example:
14182 *
14183 * $ echo "foo" > file
14184 * $ ruby argf.rb file
14185 *
14186 * ARGF.readbyte #=> 102
14187 * ARGF.readbyte #=> 111
14188 * ARGF.readbyte #=> 111
14189 * ARGF.readbyte #=> 10
14190 * ARGF.readbyte #=> end of file reached (EOFError)
14191 */
14192static VALUE
14193argf_readbyte(VALUE argf)
14194{
14195 VALUE c;
14196
14197 NEXT_ARGF_FORWARD(0, 0);
14198 c = argf_getbyte(argf);
14199 if (NIL_P(c)) {
14200 rb_eof_error();
14201 }
14202 return c;
14203}
14204
14205#define FOREACH_ARGF() while (next_argv())
14206
14207static VALUE
14208argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14209{
14210 const VALUE current = ARGF.current_file;
14211 rb_yield_values2(argc, argv);
14212 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14214 }
14215 return Qnil;
14216}
14217
14218#define ARGF_block_call(mid, argc, argv, func, argf) \
14219 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14220 func, argf, rb_keyword_given_p())
14221
14222static void
14223argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14224{
14225 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14226 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14227}
14228
14229static VALUE
14230argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14231{
14232 if (!global_argf_p(argf)) {
14233 ARGF.last_lineno = ++ARGF.lineno;
14234 }
14235 return argf_block_call_i(i, argf, argc, argv, blockarg);
14236}
14237
14238static void
14239argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14240{
14241 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14242 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14243}
14244
14245/*
14246 * call-seq:
14247 * ARGF.each(sep=$/) {|line| block } -> ARGF
14248 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14249 * ARGF.each(...) -> an_enumerator
14250 *
14251 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14252 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14253 * ARGF.each_line(...) -> an_enumerator
14254 *
14255 * Returns an enumerator which iterates over each line (separated by _sep_,
14256 * which defaults to your platform's newline character) of each file in
14257 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14258 * block, otherwise an enumerator is returned.
14259 * The optional _limit_ argument is an Integer specifying the maximum
14260 * length of each line; longer lines will be split according to this limit.
14261 *
14262 * This method allows you to treat the files supplied on the command line as
14263 * a single file consisting of the concatenation of each named file. After
14264 * the last line of the first file has been returned, the first line of the
14265 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14266 * used to determine the filename of the current line and line number of the
14267 * whole input, respectively.
14268 *
14269 * For example, the following code prints out each line of each named file
14270 * prefixed with its line number, displaying the filename once per file:
14271 *
14272 * ARGF.each_line do |line|
14273 * puts ARGF.filename if ARGF.file.lineno == 1
14274 * puts "#{ARGF.file.lineno}: #{line}"
14275 * end
14276 *
14277 * While the following code prints only the first file's name at first, and
14278 * the contents with line number counted through all named files.
14279 *
14280 * ARGF.each_line do |line|
14281 * puts ARGF.filename if ARGF.lineno == 1
14282 * puts "#{ARGF.lineno}: #{line}"
14283 * end
14284 */
14285static VALUE
14286argf_each_line(int argc, VALUE *argv, VALUE argf)
14287{
14288 RETURN_ENUMERATOR(argf, argc, argv);
14289 FOREACH_ARGF() {
14290 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14291 }
14292 return argf;
14293}
14294
14295/*
14296 * call-seq:
14297 * ARGF.each_byte {|byte| block } -> ARGF
14298 * ARGF.each_byte -> an_enumerator
14299 *
14300 * Iterates over each byte of each file in +ARGV+.
14301 * A byte is returned as an Integer in the range 0..255.
14302 *
14303 * This method allows you to treat the files supplied on the command line as
14304 * a single file consisting of the concatenation of each named file. After
14305 * the last byte of the first file has been returned, the first byte of the
14306 * second file is returned. The ARGF.filename method can be used to
14307 * determine the filename of the current byte.
14308 *
14309 * If no block is given, an enumerator is returned instead.
14310 *
14311 * For example:
14312 *
14313 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14314 *
14315 */
14316static VALUE
14317argf_each_byte(VALUE argf)
14318{
14319 RETURN_ENUMERATOR(argf, 0, 0);
14320 FOREACH_ARGF() {
14321 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14322 }
14323 return argf;
14324}
14325
14326/*
14327 * call-seq:
14328 * ARGF.each_char {|char| block } -> ARGF
14329 * ARGF.each_char -> an_enumerator
14330 *
14331 * Iterates over each character of each file in ARGF.
14332 *
14333 * This method allows you to treat the files supplied on the command line as
14334 * a single file consisting of the concatenation of each named file. After
14335 * the last character of the first file has been returned, the first
14336 * character of the second file is returned. The ARGF.filename method can
14337 * be used to determine the name of the file in which the current character
14338 * appears.
14339 *
14340 * If no block is given, an enumerator is returned instead.
14341 */
14342static VALUE
14343argf_each_char(VALUE argf)
14344{
14345 RETURN_ENUMERATOR(argf, 0, 0);
14346 FOREACH_ARGF() {
14347 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14348 }
14349 return argf;
14350}
14351
14352/*
14353 * call-seq:
14354 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14355 * ARGF.each_codepoint -> an_enumerator
14356 *
14357 * Iterates over each codepoint of each file in ARGF.
14358 *
14359 * This method allows you to treat the files supplied on the command line as
14360 * a single file consisting of the concatenation of each named file. After
14361 * the last codepoint of the first file has been returned, the first
14362 * codepoint of the second file is returned. The ARGF.filename method can
14363 * be used to determine the name of the file in which the current codepoint
14364 * appears.
14365 *
14366 * If no block is given, an enumerator is returned instead.
14367 */
14368static VALUE
14369argf_each_codepoint(VALUE argf)
14370{
14371 RETURN_ENUMERATOR(argf, 0, 0);
14372 FOREACH_ARGF() {
14373 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14374 }
14375 return argf;
14376}
14377
14378/*
14379 * call-seq:
14380 * ARGF.filename -> String
14381 * ARGF.path -> String
14382 *
14383 * Returns the current filename. "-" is returned when the current file is
14384 * STDIN.
14385 *
14386 * For example:
14387 *
14388 * $ echo "foo" > foo
14389 * $ echo "bar" > bar
14390 * $ echo "glark" > glark
14391 *
14392 * $ ruby argf.rb foo bar glark
14393 *
14394 * ARGF.filename #=> "foo"
14395 * ARGF.read(5) #=> "foo\nb"
14396 * ARGF.filename #=> "bar"
14397 * ARGF.skip
14398 * ARGF.filename #=> "glark"
14399 */
14400static VALUE
14401argf_filename(VALUE argf)
14402{
14403 next_argv();
14404 return ARGF.filename;
14405}
14406
14407static VALUE
14408argf_filename_getter(ID id, VALUE *var)
14409{
14410 return argf_filename(*var);
14411}
14412
14413/*
14414 * call-seq:
14415 * ARGF.file -> IO or File object
14416 *
14417 * Returns the current file as an IO or File object.
14418 * <code>$stdin</code> is returned when the current file is STDIN.
14419 *
14420 * For example:
14421 *
14422 * $ echo "foo" > foo
14423 * $ echo "bar" > bar
14424 *
14425 * $ ruby argf.rb foo bar
14426 *
14427 * ARGF.file #=> #<File:foo>
14428 * ARGF.read(5) #=> "foo\nb"
14429 * ARGF.file #=> #<File:bar>
14430 */
14431static VALUE
14432argf_file(VALUE argf)
14433{
14434 next_argv();
14435 return ARGF.current_file;
14436}
14437
14438/*
14439 * call-seq:
14440 * ARGF.binmode -> ARGF
14441 *
14442 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14443 * be reset to non-binary mode. This option has the following effects:
14444 *
14445 * * Newline conversion is disabled.
14446 * * Encoding conversion is disabled.
14447 * * Content is treated as ASCII-8BIT.
14448 */
14449static VALUE
14450argf_binmode_m(VALUE argf)
14451{
14452 ARGF.binmode = 1;
14453 next_argv();
14454 ARGF_FORWARD(0, 0);
14455 rb_io_ascii8bit_binmode(ARGF.current_file);
14456 return argf;
14457}
14458
14459/*
14460 * call-seq:
14461 * ARGF.binmode? -> true or false
14462 *
14463 * Returns true if ARGF is being read in binary mode; false otherwise.
14464 * To enable binary mode use ARGF.binmode.
14465 *
14466 * For example:
14467 *
14468 * ARGF.binmode? #=> false
14469 * ARGF.binmode
14470 * ARGF.binmode? #=> true
14471 */
14472static VALUE
14473argf_binmode_p(VALUE argf)
14474{
14475 return RBOOL(ARGF.binmode);
14476}
14477
14478/*
14479 * call-seq:
14480 * ARGF.skip -> ARGF
14481 *
14482 * Sets the current file to the next file in ARGV. If there aren't any more
14483 * files it has no effect.
14484 *
14485 * For example:
14486 *
14487 * $ ruby argf.rb foo bar
14488 * ARGF.filename #=> "foo"
14489 * ARGF.skip
14490 * ARGF.filename #=> "bar"
14491 */
14492static VALUE
14493argf_skip(VALUE argf)
14494{
14495 if (ARGF.init_p && ARGF.next_p == 0) {
14496 argf_close(argf);
14497 ARGF.next_p = 1;
14498 }
14499 return argf;
14500}
14501
14502/*
14503 * call-seq:
14504 * ARGF.close -> ARGF
14505 *
14506 * Closes the current file and skips to the next file in ARGV. If there are
14507 * no more files to open, just closes the current file. STDIN will not be
14508 * closed.
14509 *
14510 * For example:
14511 *
14512 * $ ruby argf.rb foo bar
14513 *
14514 * ARGF.filename #=> "foo"
14515 * ARGF.close
14516 * ARGF.filename #=> "bar"
14517 * ARGF.close
14518 */
14519static VALUE
14520argf_close_m(VALUE argf)
14521{
14522 next_argv();
14523 argf_close(argf);
14524 if (ARGF.next_p != -1) {
14525 ARGF.next_p = 1;
14526 }
14527 ARGF.lineno = 0;
14528 return argf;
14529}
14530
14531/*
14532 * call-seq:
14533 * ARGF.closed? -> true or false
14534 *
14535 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14536 * ARGF.close to actually close the current file.
14537 */
14538static VALUE
14539argf_closed(VALUE argf)
14540{
14541 next_argv();
14542 ARGF_FORWARD(0, 0);
14543 return rb_io_closed_p(ARGF.current_file);
14544}
14545
14546/*
14547 * call-seq:
14548 * ARGF.to_s -> String
14549 *
14550 * Returns "ARGF".
14551 */
14552static VALUE
14553argf_to_s(VALUE argf)
14554{
14555 return rb_str_new2("ARGF");
14556}
14557
14558/*
14559 * call-seq:
14560 * ARGF.inplace_mode -> String
14561 *
14562 * Returns the file extension appended to the names of backup copies of
14563 * modified files under in-place edit mode. This value can be set using
14564 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14565 */
14566static VALUE
14567argf_inplace_mode_get(VALUE argf)
14568{
14569 if (!ARGF.inplace) return Qnil;
14570 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14571 return rb_str_dup(ARGF.inplace);
14572}
14573
14574static VALUE
14575opt_i_get(ID id, VALUE *var)
14576{
14577 return argf_inplace_mode_get(*var);
14578}
14579
14580/*
14581 * call-seq:
14582 * ARGF.inplace_mode = ext -> ARGF
14583 *
14584 * Sets the filename extension for in-place editing mode to the given String.
14585 * The backup copy of each file being edited has this value appended to its
14586 * filename.
14587 *
14588 * For example:
14589 *
14590 * $ ruby argf.rb file.txt
14591 *
14592 * ARGF.inplace_mode = '.bak'
14593 * ARGF.each_line do |line|
14594 * print line.sub("foo","bar")
14595 * end
14596 *
14597 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14598 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14599 * "bar".
14600 */
14601static VALUE
14602argf_inplace_mode_set(VALUE argf, VALUE val)
14603{
14604 if (!RTEST(val)) {
14605 ARGF.inplace = Qfalse;
14606 }
14607 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14608 ARGF.inplace = Qnil;
14609 }
14610 else {
14611 ARGF.inplace = rb_str_new_frozen(val);
14612 }
14613 return argf;
14614}
14615
14616static void
14617opt_i_set(VALUE val, ID id, VALUE *var)
14618{
14619 argf_inplace_mode_set(*var, val);
14620}
14621
14622void
14623ruby_set_inplace_mode(const char *suffix)
14624{
14625 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14626}
14627
14628/*
14629 * call-seq:
14630 * ARGF.argv -> ARGV
14631 *
14632 * Returns the +ARGV+ array, which contains the arguments passed to your
14633 * script, one per element.
14634 *
14635 * For example:
14636 *
14637 * $ ruby argf.rb -v glark.txt
14638 *
14639 * ARGF.argv #=> ["-v", "glark.txt"]
14640 *
14641 */
14642static VALUE
14643argf_argv(VALUE argf)
14644{
14645 return ARGF.argv;
14646}
14647
14648static VALUE
14649argf_argv_getter(ID id, VALUE *var)
14650{
14651 return argf_argv(*var);
14652}
14653
14654VALUE
14656{
14657 return ARGF.argv;
14658}
14659
14660/*
14661 * call-seq:
14662 * ARGF.to_write_io -> io
14663 *
14664 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14665 * enabled.
14666 */
14667static VALUE
14668argf_write_io(VALUE argf)
14669{
14670 if (!RTEST(ARGF.current_file)) {
14671 rb_raise(rb_eIOError, "not opened for writing");
14672 }
14673 return GetWriteIO(ARGF.current_file);
14674}
14675
14676/*
14677 * call-seq:
14678 * ARGF.write(*objects) -> integer
14679 *
14680 * Writes each of the given +objects+ if inplace mode.
14681 */
14682static VALUE
14683argf_write(int argc, VALUE *argv, VALUE argf)
14684{
14685 return rb_io_writev(argf_write_io(argf), argc, argv);
14686}
14687
14688void
14689rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14690{
14691 rb_readwrite_syserr_fail(waiting, errno, mesg);
14692}
14693
14694void
14695rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14696{
14697 VALUE arg, c = Qnil;
14698 arg = mesg ? rb_str_new2(mesg) : Qnil;
14699 switch (waiting) {
14700 case RB_IO_WAIT_WRITABLE:
14701 switch (n) {
14702 case EAGAIN:
14703 c = rb_eEAGAINWaitWritable;
14704 break;
14705#if EAGAIN != EWOULDBLOCK
14706 case EWOULDBLOCK:
14707 c = rb_eEWOULDBLOCKWaitWritable;
14708 break;
14709#endif
14710 case EINPROGRESS:
14711 c = rb_eEINPROGRESSWaitWritable;
14712 break;
14713 default:
14715 }
14716 break;
14717 case RB_IO_WAIT_READABLE:
14718 switch (n) {
14719 case EAGAIN:
14720 c = rb_eEAGAINWaitReadable;
14721 break;
14722#if EAGAIN != EWOULDBLOCK
14723 case EWOULDBLOCK:
14724 c = rb_eEWOULDBLOCKWaitReadable;
14725 break;
14726#endif
14727 case EINPROGRESS:
14728 c = rb_eEINPROGRESSWaitReadable;
14729 break;
14730 default:
14732 }
14733 break;
14734 default:
14735 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14736 }
14738}
14739
14740static VALUE
14741get_LAST_READ_LINE(ID _x, VALUE *_y)
14742{
14743 return rb_lastline_get();
14744}
14745
14746static void
14747set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14748{
14749 rb_lastline_set(val);
14750}
14751
14752/*
14753 * Document-class: IOError
14754 *
14755 * Raised when an IO operation fails.
14756 *
14757 * File.open("/etc/hosts") {|f| f << "example"}
14758 * #=> IOError: not opened for writing
14759 *
14760 * File.open("/etc/hosts") {|f| f.close; f.read }
14761 * #=> IOError: closed stream
14762 *
14763 * Note that some IO failures raise <code>SystemCallError</code>s
14764 * and these are not subclasses of IOError:
14765 *
14766 * File.open("does/not/exist")
14767 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14768 */
14769
14770/*
14771 * Document-class: EOFError
14772 *
14773 * Raised by some IO operations when reaching the end of file. Many IO
14774 * methods exist in two forms,
14775 *
14776 * one that returns +nil+ when the end of file is reached, the other
14777 * raises EOFError.
14778 *
14779 * EOFError is a subclass of IOError.
14780 *
14781 * file = File.open("/etc/hosts")
14782 * file.read
14783 * file.gets #=> nil
14784 * file.readline #=> EOFError: end of file reached
14785 * file.close
14786 */
14787
14788/*
14789 * Document-class: ARGF
14790 *
14791 * == \ARGF and +ARGV+
14792 *
14793 * The \ARGF object works with the array at global variable +ARGV+
14794 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14795 *
14796 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14797 *
14798 * Initially, it contains the command-line arguments and options
14799 * that are passed to the Ruby program;
14800 * the program can modify that array as it likes.
14801 *
14802 * - **ARGF** may be thought of as the <b>argument files</b> object.
14803 *
14804 * It can access file streams and/or the <tt>$stdin</tt> stream,
14805 * based on what it finds in +ARGV+.
14806 * This provides a convenient way for the command line
14807 * to specify streams for a Ruby program to read.
14808 *
14809 * == Reading
14810 *
14811 * \ARGF may read from _source_ streams,
14812 * which at any particular time are determined by the content of +ARGV+.
14813 *
14814 * === Simplest Case
14815 *
14816 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14817 * the source is <tt>$stdin</tt>:
14818 *
14819 * - \File +t.rb+:
14820 *
14821 * p ['ARGV', ARGV]
14822 * p ['ARGF.read', ARGF.read]
14823 *
14824 * - Commands and outputs
14825 * (see below for the content of files +foo.txt+ and +bar.txt+):
14826 *
14827 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14828 * ["ARGV", []]
14829 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14830 *
14831 * $ cat foo.txt bar.txt | ruby t.rb
14832 * ["ARGV", []]
14833 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14834 *
14835 * === About the Examples
14836 *
14837 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14838 *
14839 * $ cat foo.txt
14840 * Foo 0
14841 * Foo 1
14842 * $ cat bar.txt
14843 * Bar 0
14844 * Bar 1
14845 * Bar 2
14846 * Bar 3
14847 *
14848 * === Sources in +ARGV+
14849 *
14850 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14851 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14852 * the sources are found in +ARGV+.
14853 *
14854 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14855 * and is one of:
14856 *
14857 * - The string path to a file that may be opened as a stream.
14858 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14859 *
14860 * Each element that is _not_ one of these
14861 * should be removed from +ARGV+ before \ARGF accesses that source.
14862 *
14863 * In the following example:
14864 *
14865 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14866 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14867 *
14868 * Example:
14869 *
14870 * - \File +t.rb+:
14871 *
14872 * # Print arguments (and options, if any) found on command line.
14873 * p ['ARGV', ARGV]
14874 *
14875 * - Command and output:
14876 *
14877 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14878 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14879 *
14880 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14881 *
14882 * - \File +t.rb+:
14883 *
14884 * p "ARGV: #{ARGV}"
14885 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
14886 *
14887 * - Command and output:
14888 *
14889 * $ ruby t.rb foo.txt bar.txt
14890 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14891 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14892 *
14893 * Because the value at +ARGV+ is an ordinary array,
14894 * you can manipulate it to control which sources \ARGF considers:
14895 *
14896 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14897 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14898 *
14899 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14900 * when all sources have been accessed, the array is empty:
14901 *
14902 * - \File +t.rb+:
14903 *
14904 * until ARGV.empty? && ARGF.eof?
14905 * p "ARGV: #{ARGV}"
14906 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14907 * end
14908 *
14909 * - Command and output:
14910 *
14911 * $ ruby t.rb foo.txt bar.txt
14912 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14913 * "Line: Foo 0\n"
14914 * "ARGV: [\"bar.txt\"]"
14915 * "Line: Foo 1\n"
14916 * "ARGV: [\"bar.txt\"]"
14917 * "Line: Bar 0\n"
14918 * "ARGV: []"
14919 * "Line: Bar 1\n"
14920 * "ARGV: []"
14921 * "Line: Bar 2\n"
14922 * "ARGV: []"
14923 * "Line: Bar 3\n"
14924 *
14925 * ==== Filepaths in +ARGV+
14926 *
14927 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14928 *
14929 * This program prints what it reads from files at the paths specified
14930 * on the command line:
14931 *
14932 * - \File +t.rb+:
14933 *
14934 * p ['ARGV', ARGV]
14935 * # Read and print all content from the specified sources.
14936 * p ['ARGF.read', ARGF.read]
14937 *
14938 * - Command and output:
14939 *
14940 * $ ruby t.rb foo.txt bar.txt
14941 * ["ARGV", [foo.txt, bar.txt]
14942 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14943 *
14944 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14945 *
14946 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14947 *
14948 * - \File +t.rb+:
14949 *
14950 * p ['ARGV', ARGV]
14951 * p ['ARGF.read', ARGF.read]
14952 *
14953 * - Command and output:
14954 *
14955 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14956 * ["ARGV", ["-"]]
14957 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14958 *
14959 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
14960 * (exception:
14961 * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
14962 *
14963 * - Command and output:
14964 *
14965 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
14966 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14967 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14968 *
14969 * ==== Mixtures and Repetitions in +ARGV+
14970 *
14971 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
14972 * and character <tt>'-'</tt>, including repetitions.
14973 *
14974 * ==== Modifications to +ARGV+
14975 *
14976 * The running Ruby program may make any modifications to the +ARGV+ array;
14977 * the current value of +ARGV+ affects \ARGF reading.
14978 *
14979 * ==== Empty +ARGV+
14980 *
14981 * For an empty +ARGV+, an \ARGF read method either returns +nil+
14982 * or raises an exception, depending on the specific method.
14983 *
14984 * === More Read Methods
14985 *
14986 * As seen above, method ARGF#read reads the content of all sources
14987 * into a single string.
14988 * Other \ARGF methods provide other ways to access that content;
14989 * these include:
14990 *
14991 * - Byte access: #each_byte, #getbyte, #readbyte.
14992 * - Character access: #each_char, #getc, #readchar.
14993 * - Codepoint access: #each_codepoint.
14994 * - Line access: #each_line, #gets, #readline, #readlines.
14995 * - Source access: #read, #read_nonblock, #readpartial.
14996 *
14997 * === About \Enumerable
14998 *
14999 * \ARGF includes module Enumerable.
15000 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15001 *
15002 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15003 * _not_ from +ARGV+;
15004 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15005 * not an array of the strings from +ARGV+:
15006 *
15007 * - \File +t.rb+:
15008 *
15009 * p ['ARGV', ARGV]
15010 * p ['ARGF.entries', ARGF.entries]
15011 *
15012 * - Command and output:
15013 *
15014 * $ ruby t.rb foo.txt bar.txt
15015 * ["ARGV", ["foo.txt", "bar.txt"]]
15016 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15017 *
15018 * == Writing
15019 *
15020 * If <i>inplace mode</i> is in effect,
15021 * \ARGF may write to target streams,
15022 * which at any particular time are determined by the content of ARGV.
15023 *
15024 * Methods about inplace mode:
15025 *
15026 * - #inplace_mode
15027 * - #inplace_mode=
15028 * - #to_write_io
15029 *
15030 * Methods for writing:
15031 *
15032 * - #print
15033 * - #printf
15034 * - #putc
15035 * - #puts
15036 * - #write
15037 *
15038 */
15039
15040/*
15041 * An instance of class \IO (commonly called a _stream_)
15042 * represents an input/output stream in the underlying operating system.
15043 * Class \IO is the basis for input and output in Ruby.
15044 *
15045 * Class File is the only class in the Ruby core that is a subclass of \IO.
15046 * Some classes in the Ruby standard library are also subclasses of \IO;
15047 * these include TCPSocket and UDPSocket.
15048 *
15049 * The global constant ARGF (also accessible as <tt>$<</tt>)
15050 * provides an IO-like stream that allows access to all file paths
15051 * found in ARGV (or found in STDIN if ARGV is empty).
15052 * ARGF is not itself a subclass of \IO.
15053 *
15054 * Class StringIO provides an IO-like stream that handles a String.
15055 * StringIO is not itself a subclass of \IO.
15056 *
15057 * Important objects based on \IO include:
15058 *
15059 * - $stdin.
15060 * - $stdout.
15061 * - $stderr.
15062 * - Instances of class File.
15063 *
15064 * An instance of \IO may be created using:
15065 *
15066 * - IO.new: returns a new \IO object for the given integer file descriptor.
15067 * - IO.open: passes a new \IO object to the given block.
15068 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15069 * of a newly-launched subprocess.
15070 * - Kernel#open: Returns a new \IO object connected to a given source:
15071 * stream, file, or subprocess.
15072 *
15073 * Like a File stream, an \IO stream has:
15074 *
15075 * - A read/write mode, which may be read-only, write-only, or read/write;
15076 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
15077 * - A data mode, which may be text-only or binary;
15078 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15079 * - Internal and external encodings;
15080 * see {Encodings}[rdoc-ref:File@Encodings].
15081 *
15082 * And like other \IO streams, it has:
15083 *
15084 * - A position, which determines where in the stream the next
15085 * read or write is to occur;
15086 * see {Position}[rdoc-ref:IO@Position].
15087 * - A line number, which is a special, line-oriented, "position"
15088 * (different from the position mentioned above);
15089 * see {Line Number}[rdoc-ref:IO@Line+Number].
15090 *
15091 * == Extension <tt>io/console</tt>
15092 *
15093 * Extension <tt>io/console</tt> provides numerous methods
15094 * for interacting with the console;
15095 * requiring it adds numerous methods to class \IO.
15096 *
15097 * == Example Files
15098 *
15099 * Many examples here use these variables:
15100 *
15101 * :include: doc/examples/files.rdoc
15102 *
15103 * == Open Options
15104 *
15105 * A number of \IO methods accept optional keyword arguments
15106 * that determine how a new stream is to be opened:
15107 *
15108 * - +:mode+: Stream mode.
15109 * - +:flags+: Integer file open flags;
15110 * If +mode+ is also given, the two are bitwise-ORed.
15111 * - +:external_encoding+: External encoding for the stream.
15112 * - +:internal_encoding+: Internal encoding for the stream.
15113 * <tt>'-'</tt> is a synonym for the default internal encoding.
15114 * If the value is +nil+ no conversion occurs.
15115 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15116 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15117 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15118 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15119 * when the stream closes; otherwise it remains open.
15120 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15121 * #path method.
15122 *
15123 * Also available are the options offered in String#encode,
15124 * which may control conversion between external and internal encoding.
15125 *
15126 * == Basic \IO
15127 *
15128 * You can perform basic stream \IO with these methods,
15129 * which typically operate on multi-byte strings:
15130 *
15131 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15132 * - IO#write: Writes zero or more strings to the stream;
15133 * each given object that is not already a string is converted via +to_s+.
15134 *
15135 * === Position
15136 *
15137 * An \IO stream has a nonnegative integer _position_,
15138 * which is the byte offset at which the next read or write is to occur.
15139 * A new stream has position zero (and line number zero);
15140 * method +rewind+ resets the position (and line number) to zero.
15141 *
15142 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15143 * Encoding::Converter instances used for that \IO.
15144 *
15145 * The relevant methods:
15146 *
15147 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15148 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15149 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15150 * relative to a given position +whence+
15151 * (indicating the beginning, end, or current position).
15152 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15153 *
15154 * === Open and Closed Streams
15155 *
15156 * A new \IO stream may be open for reading, open for writing, or both.
15157 *
15158 * A stream is automatically closed when claimed by the garbage collector.
15159 *
15160 * Attempted reading or writing on a closed stream raises an exception.
15161 *
15162 * The relevant methods:
15163 *
15164 * - IO#close: Closes the stream for both reading and writing.
15165 * - IO#close_read: Closes the stream for reading.
15166 * - IO#close_write: Closes the stream for writing.
15167 * - IO#closed?: Returns whether the stream is closed.
15168 *
15169 * === End-of-Stream
15170 *
15171 * You can query whether a stream is positioned at its end:
15172 *
15173 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15174 *
15175 * You can reposition to end-of-stream by using method IO#seek:
15176 *
15177 * f = File.new('t.txt')
15178 * f.eof? # => false
15179 * f.seek(0, :END)
15180 * f.eof? # => true
15181 * f.close
15182 *
15183 * Or by reading all stream content (which is slower than using IO#seek):
15184 *
15185 * f.rewind
15186 * f.eof? # => false
15187 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15188 * f.eof? # => true
15189 *
15190 * == Line \IO
15191 *
15192 * Class \IO supports line-oriented
15193 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15194 *
15195 * === Line Input
15196 *
15197 * Class \IO supports line-oriented input for
15198 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15199 *
15200 * ==== \File Line Input
15201 *
15202 * You can read lines from a file using these methods:
15203 *
15204 * - IO.foreach: Reads each line and passes it to the given block.
15205 * - IO.readlines: Reads and returns all lines in an array.
15206 *
15207 * For each of these methods:
15208 *
15209 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15210 * - Line parsing depends on the effective <i>line separator</i>;
15211 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15212 * - The length of each returned line depends on the effective <i>line limit</i>;
15213 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15214 *
15215 * ==== Stream Line Input
15216 *
15217 * You can read lines from an \IO stream using these methods:
15218 *
15219 * - IO#each_line: Reads each remaining line, passing it to the given block.
15220 * - IO#gets: Returns the next line.
15221 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15222 * - IO#readlines: Returns all remaining lines in an array.
15223 *
15224 * For each of these methods:
15225 *
15226 * - Reading may begin mid-line,
15227 * depending on the stream's _position_;
15228 * see {Position}[rdoc-ref:IO@Position].
15229 * - Line parsing depends on the effective <i>line separator</i>;
15230 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15231 * - The length of each returned line depends on the effective <i>line limit</i>;
15232 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15233 *
15234 * ===== Line Separator
15235 *
15236 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15237 * the string that determines what is considered a line;
15238 * it is sometimes called the <i>input record separator</i>.
15239 *
15240 * The default line separator is taken from global variable <tt>$/</tt>,
15241 * whose initial value is <tt>"\n"</tt>.
15242 *
15243 * Generally, the line to be read next is all data
15244 * from the current {position}[rdoc-ref:IO@Position]
15245 * to the next line separator
15246 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15247 *
15248 * f = File.new('t.txt')
15249 * # Method gets with no sep argument returns the next line, according to $/.
15250 * f.gets # => "First line\n"
15251 * f.gets # => "Second line\n"
15252 * f.gets # => "\n"
15253 * f.gets # => "Fourth line\n"
15254 * f.gets # => "Fifth line\n"
15255 * f.close
15256 *
15257 * You can use a different line separator by passing argument +sep+:
15258 *
15259 * f = File.new('t.txt')
15260 * f.gets('l') # => "First l"
15261 * f.gets('li') # => "ine\nSecond li"
15262 * f.gets('lin') # => "ne\n\nFourth lin"
15263 * f.gets # => "e\n"
15264 * f.close
15265 *
15266 * Or by setting global variable <tt>$/</tt>:
15267 *
15268 * f = File.new('t.txt')
15269 * $/ = 'l'
15270 * f.gets # => "First l"
15271 * f.gets # => "ine\nSecond l"
15272 * f.gets # => "ine\n\nFourth l"
15273 * f.close
15274 *
15275 * ===== Special Line Separator Values
15276 *
15277 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15278 * accepts two special values for parameter +sep+:
15279 *
15280 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15281 *
15282 * f = File.new('t.txt')
15283 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15284 * f.close
15285 *
15286 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15287 * (paragraphs being separated by two consecutive line separators):
15288 *
15289 * f = File.new('t.txt')
15290 * f.gets('') # => "First line\nSecond line\n\n"
15291 * f.gets('') # => "Fourth line\nFifth line\n"
15292 * f.close
15293 *
15294 * ===== Line Limit
15295 *
15296 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15297 * uses an integer <i>line limit</i>,
15298 * which restricts the number of bytes that may be returned.
15299 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15300 * than the limit).
15301 *
15302 * The default limit value is <tt>-1</tt>;
15303 * any negative limit value means that there is no limit.
15304 *
15305 * If there is no limit, the line is determined only by +sep+.
15306 *
15307 * # Text with 1-byte characters.
15308 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15309 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15310 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15311 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15312 * # No more than one line.
15313 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15314 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15315 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15316 *
15317 * # Text with 2-byte characters, which will not be split.
15318 * File.open('t.rus') {|f| f.gets(1).size } # => 1
15319 * File.open('t.rus') {|f| f.gets(2).size } # => 1
15320 * File.open('t.rus') {|f| f.gets(3).size } # => 2
15321 * File.open('t.rus') {|f| f.gets(4).size } # => 2
15322 *
15323 * ===== Line Separator and Line Limit
15324 *
15325 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15326 *
15327 * - Returns the next line as determined by line separator +sep+.
15328 * - But returns no more bytes than are allowed by the limit +limit+.
15329 *
15330 * Example:
15331 *
15332 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15333 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15334 *
15335 * ===== Line Number
15336 *
15337 * A readable \IO stream has a non-negative integer <i>line number</i>:
15338 *
15339 * - IO#lineno: Returns the line number.
15340 * - IO#lineno=: Resets and returns the line number.
15341 *
15342 * Unless modified by a call to method IO#lineno=,
15343 * the line number is the number of lines read
15344 * by certain line-oriented methods,
15345 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15346 *
15347 * - IO.foreach: Increments the line number on each call to the block.
15348 * - IO#each_line: Increments the line number on each call to the block.
15349 * - IO#gets: Increments the line number.
15350 * - IO#readline: Increments the line number.
15351 * - IO#readlines: Increments the line number for each line read.
15352 *
15353 * A new stream is initially has line number zero (and position zero);
15354 * method +rewind+ resets the line number (and position) to zero:
15355 *
15356 * f = File.new('t.txt')
15357 * f.lineno # => 0
15358 * f.gets # => "First line\n"
15359 * f.lineno # => 1
15360 * f.rewind
15361 * f.lineno # => 0
15362 * f.close
15363 *
15364 * Reading lines from a stream usually changes its line number:
15365 *
15366 * f = File.new('t.txt', 'r')
15367 * f.lineno # => 0
15368 * f.readline # => "This is line one.\n"
15369 * f.lineno # => 1
15370 * f.readline # => "This is the second line.\n"
15371 * f.lineno # => 2
15372 * f.readline # => "Here's the third line.\n"
15373 * f.lineno # => 3
15374 * f.eof? # => true
15375 * f.close
15376 *
15377 * Iterating over lines in a stream usually changes its line number:
15378 *
15379 * File.open('t.txt') do |f|
15380 * f.each_line do |line|
15381 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15382 * end
15383 * end
15384 *
15385 * Output:
15386 *
15387 * "position=11 eof?=false lineno=1"
15388 * "position=23 eof?=false lineno=2"
15389 * "position=24 eof?=false lineno=3"
15390 * "position=36 eof?=false lineno=4"
15391 * "position=47 eof?=true lineno=5"
15392 *
15393 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15394 * the line number does not affect where the next read or write will occur:
15395 *
15396 * f = File.new('t.txt')
15397 * f.lineno = 1000
15398 * f.lineno # => 1000
15399 * f.gets # => "First line\n"
15400 * f.lineno # => 1001
15401 * f.close
15402 *
15403 * Associated with the line number is the global variable <tt>$.</tt>:
15404 *
15405 * - When a stream is opened, <tt>$.</tt> is not set;
15406 * its value is left over from previous activity in the process:
15407 *
15408 * $. = 41
15409 * f = File.new('t.txt')
15410 * $. = 41
15411 * # => 41
15412 * f.close
15413 *
15414 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15415 *
15416 * f0 = File.new('t.txt')
15417 * f1 = File.new('t.dat')
15418 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15419 * $. # => 5
15420 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15421 * $. # => 1
15422 * f0.close
15423 * f1.close
15424 *
15425 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15426 *
15427 * f = File.new('t.txt')
15428 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15429 * $. # => 5
15430 * f.rewind
15431 * f.seek(0, :SET)
15432 * $. # => 5
15433 * f.close
15434 *
15435 * === Line Output
15436 *
15437 * You can write to an \IO stream line-by-line using this method:
15438 *
15439 * - IO#puts: Writes objects to the stream.
15440 *
15441 * == Character \IO
15442 *
15443 * You can process an \IO stream character-by-character using these methods:
15444 *
15445 * - IO#getc: Reads and returns the next character from the stream.
15446 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15447 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15448 * - IO#putc: Writes a character to the stream.
15449 * - IO#each_char: Reads each remaining character in the stream,
15450 * passing the character to the given block.
15451 *
15452 * == Byte \IO
15453 *
15454 * You can process an \IO stream byte-by-byte using these methods:
15455 *
15456 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15457 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15458 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15459 * - IO#each_byte: Reads each remaining byte in the stream,
15460 * passing the byte to the given block.
15461 *
15462 * == Codepoint \IO
15463 *
15464 * You can process an \IO stream codepoint-by-codepoint:
15465 *
15466 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15467 *
15468 * == What's Here
15469 *
15470 * First, what's elsewhere. Class \IO:
15471 *
15472 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15473 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15474 * which provides dozens of additional methods.
15475 *
15476 * Here, class \IO provides methods that are useful for:
15477 *
15478 * - {Creating}[rdoc-ref:IO@Creating]
15479 * - {Reading}[rdoc-ref:IO@Reading]
15480 * - {Writing}[rdoc-ref:IO@Writing]
15481 * - {Positioning}[rdoc-ref:IO@Positioning]
15482 * - {Iterating}[rdoc-ref:IO@Iterating]
15483 * - {Settings}[rdoc-ref:IO@Settings]
15484 * - {Querying}[rdoc-ref:IO@Querying]
15485 * - {Buffering}[rdoc-ref:IO@Buffering]
15486 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15487 * - {Other}[rdoc-ref:IO@Other]
15488 *
15489 * === Creating
15490 *
15491 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15492 * integer file descriptor.
15493 * - ::open: Creates a new \IO object.
15494 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15495 * - ::popen: Creates an \IO object to interact with a subprocess.
15496 * - ::select: Selects which given \IO instances are ready for reading,
15497 * writing, or have pending exceptions.
15498 *
15499 * === Reading
15500 *
15501 * - ::binread: Returns a binary string with all or a subset of bytes
15502 * from the given file.
15503 * - ::read: Returns a string with all or a subset of bytes from the given file.
15504 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15505 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15506 * - #getc: Returns the next character read from +self+ as a string.
15507 * - #gets: Returns the line read from +self+.
15508 * - #pread: Returns all or the next _n_ bytes read from +self+,
15509 * not updating the receiver's offset.
15510 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15511 * for a given _n_.
15512 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15513 * in non-block mode.
15514 * - #readbyte: Returns the next byte read from +self+;
15515 * same as #getbyte, but raises an exception on end-of-stream.
15516 * - #readchar: Returns the next character read from +self+;
15517 * same as #getc, but raises an exception on end-of-stream.
15518 * - #readline: Returns the next line read from +self+;
15519 * same as #getline, but raises an exception of end-of-stream.
15520 * - #readlines: Returns an array of all lines read read from +self+.
15521 * - #readpartial: Returns up to the given number of bytes from +self+.
15522 *
15523 * === Writing
15524 *
15525 * - ::binwrite: Writes the given string to the file at the given filepath,
15526 * in binary mode.
15527 * - ::write: Writes the given string to +self+.
15528 * - #<<: Appends the given string to +self+.
15529 * - #print: Prints last read line or given objects to +self+.
15530 * - #printf: Writes to +self+ based on the given format string and objects.
15531 * - #putc: Writes a character to +self+.
15532 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15533 * - #pwrite: Writes the given string at the given offset,
15534 * not updating the receiver's offset.
15535 * - #write: Writes one or more given strings to +self+.
15536 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15537 *
15538 * === Positioning
15539 *
15540 * - #lineno: Returns the current line number in +self+.
15541 * - #lineno=: Sets the line number is +self+.
15542 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15543 * - #pos=: Sets the byte offset in +self+.
15544 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15545 * - #rewind: Positions +self+ to the beginning of input.
15546 * - #seek: Sets the offset for +self+ relative to given position.
15547 *
15548 * === Iterating
15549 *
15550 * - ::foreach: Yields each line of given file to the block.
15551 * - #each (aliased as #each_line): Calls the given block
15552 * with each successive line in +self+.
15553 * - #each_byte: Calls the given block with each successive byte in +self+
15554 * as an integer.
15555 * - #each_char: Calls the given block with each successive character in +self+
15556 * as a string.
15557 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15558 * as an integer.
15559 *
15560 * === Settings
15561 *
15562 * - #autoclose=: Sets whether +self+ auto-closes.
15563 * - #binmode: Sets +self+ to binary mode.
15564 * - #close: Closes +self+.
15565 * - #close_on_exec=: Sets the close-on-exec flag.
15566 * - #close_read: Closes +self+ for reading.
15567 * - #close_write: Closes +self+ for writing.
15568 * - #set_encoding: Sets the encoding for +self+.
15569 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15570 * Unicode byte-order-mark.
15571 * - #sync=: Sets the sync-mode to the given value.
15572 *
15573 * === Querying
15574 *
15575 * - #autoclose?: Returns whether +self+ auto-closes.
15576 * - #binmode?: Returns whether +self+ is in binary mode.
15577 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15578 * - #closed?: Returns whether +self+ is closed.
15579 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15580 * - #external_encoding: Returns the external encoding object for +self+.
15581 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15582 * - #internal_encoding: Returns the internal encoding object for +self+.
15583 * - #pid: Returns the process ID of a child process associated with +self+,
15584 * if +self+ was created by ::popen.
15585 * - #stat: Returns the File::Stat object containing status information for +self+.
15586 * - #sync: Returns whether +self+ is in sync-mode.
15587 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15588 *
15589 * === Buffering
15590 *
15591 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15592 * - #flush: Flushes any buffered data within +self+ to the underlying
15593 * operating system.
15594 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15595 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15596 * - #ungetc: Prepends buffer for +self+ with given string.
15597 *
15598 * === Low-Level Access
15599 *
15600 * - ::sysopen: Opens the file given by its path,
15601 * returning the integer file descriptor.
15602 * - #advise: Announces the intention to access data from +self+ in a specific way.
15603 * - #fcntl: Passes a low-level command to the file specified
15604 * by the given file descriptor.
15605 * - #ioctl: Passes a low-level command to the device specified
15606 * by the given file descriptor.
15607 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15608 * - #sysseek: Sets the offset for +self+.
15609 * - #syswrite: Writes the given string to +self+ using a low-level write.
15610 *
15611 * === Other
15612 *
15613 * - ::copy_stream: Copies data from a source to a destination,
15614 * each of which is a filepath or an \IO-like object.
15615 * - ::try_convert: Returns a new \IO object resulting from converting
15616 * the given object.
15617 * - #inspect: Returns the string representation of +self+.
15618 *
15619 */
15620
15621void
15622Init_IO(void)
15623{
15624 VALUE rb_cARGF;
15625#ifdef __CYGWIN__
15626#include <sys/cygwin.h>
15627 static struct __cygwin_perfile pf[] =
15628 {
15629 {"", O_RDONLY | O_BINARY},
15630 {"", O_WRONLY | O_BINARY},
15631 {"", O_RDWR | O_BINARY},
15632 {"", O_APPEND | O_BINARY},
15633 {NULL, 0}
15634 };
15635 cygwin_internal(CW_PERFILE, pf);
15636#endif
15637
15640
15641 id_write = rb_intern_const("write");
15642 id_read = rb_intern_const("read");
15643 id_getc = rb_intern_const("getc");
15644 id_flush = rb_intern_const("flush");
15645 id_readpartial = rb_intern_const("readpartial");
15646 id_set_encoding = rb_intern_const("set_encoding");
15647 id_fileno = rb_intern_const("fileno");
15648
15649 rb_define_global_function("syscall", rb_f_syscall, -1);
15650
15651 rb_define_global_function("open", rb_f_open, -1);
15652 rb_define_global_function("printf", rb_f_printf, -1);
15653 rb_define_global_function("print", rb_f_print, -1);
15654 rb_define_global_function("putc", rb_f_putc, 1);
15655 rb_define_global_function("puts", rb_f_puts, -1);
15656 rb_define_global_function("gets", rb_f_gets, -1);
15657 rb_define_global_function("readline", rb_f_readline, -1);
15658 rb_define_global_function("select", rb_f_select, -1);
15659
15660 rb_define_global_function("readlines", rb_f_readlines, -1);
15661
15662 rb_define_global_function("`", rb_f_backquote, 1);
15663
15664 rb_define_global_function("p", rb_f_p, -1);
15665 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15666
15667 rb_cIO = rb_define_class("IO", rb_cObject);
15669
15670 /* Can be raised by IO operations when IO#timeout= is set. */
15672
15673 /* Readable event mask for IO#wait. */
15674 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15675 /* Writable event mask for IO#wait. */
15676 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15677 /* Priority event mask for IO#wait. */
15678 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15679
15680 /* exception to wait for reading. see IO.select. */
15682 /* exception to wait for writing. see IO.select. */
15684 /* exception to wait for reading by EAGAIN. see IO.select. */
15685 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15686 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15687 /* exception to wait for writing by EAGAIN. see IO.select. */
15688 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15689 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15690#if EAGAIN == EWOULDBLOCK
15691 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15692 /* same as IO::EAGAINWaitReadable */
15693 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15694 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15695 /* same as IO::EAGAINWaitWritable */
15696 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15697#else
15698 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15699 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15700 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15701 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15702 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15703 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15704#endif
15705 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15706 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15707 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15708 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15709 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15710 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15711
15712#if 0
15713 /* This is necessary only for forcing rdoc handle File::open */
15714 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15715#endif
15716
15717 rb_define_alloc_func(rb_cIO, io_alloc);
15718 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15719 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15720 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15721 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15722 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15723 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15724 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15725 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15726 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15727 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15728 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15729 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15730 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15731 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15732 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15733
15734 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15735
15737 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
15738
15739 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15740 rb_vm_register_global_object(rb_default_rs);
15741 rb_rs = rb_default_rs;
15743 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15744 rb_gvar_ractor_local("$/"); // not local but ractor safe
15745 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15746 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15747 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
15748
15749 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15750 rb_gvar_ractor_local("$_");
15751
15752 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15753 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15754
15755 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15756 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15757 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15758 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15759
15760 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15761 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15762 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15763 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15764 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15765
15766 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15767 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15768
15769 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15770 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15771
15772 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15773 rb_define_alias(rb_cIO, "to_i", "fileno");
15774 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15775
15776 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15777 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15778
15779 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15780 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15781 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15782 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15783
15784 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15785 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15786
15787 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15788
15789 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15790 rb_define_method(rb_cIO, "read", io_read, -1);
15791 rb_define_method(rb_cIO, "write", io_write_m, -1);
15792 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15793 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15794 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15795 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15796 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15797 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15798 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15800 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15801 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15802 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15803 /* Set I/O position from the beginning */
15804 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15805 /* Set I/O position from the current position */
15806 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15807 /* Set I/O position from the end */
15808 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15809#ifdef SEEK_DATA
15810 /* Set I/O position to the next location containing data */
15811 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15812#endif
15813#ifdef SEEK_HOLE
15814 /* Set I/O position to the next hole */
15815 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15816#endif
15817 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15818 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15819 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15820 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15821 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15822
15823 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15824 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15825
15826 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15827 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15828 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15829 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15830
15831 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15832 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15833 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15834 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15835 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15836 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15837
15838 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15839 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15840 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15841
15842 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15843 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15844
15845 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15846
15847 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15848 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15849 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15850 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15851
15852 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15853 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15854
15855 rb_define_method(rb_cIO, "wait", io_wait, -1);
15856
15857 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15858 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15859 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15860
15861 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15862 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15863 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15864 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15865
15866 rb_gvar_ractor_local("$stdin");
15867 rb_gvar_ractor_local("$stdout");
15868 rb_gvar_ractor_local("$>");
15869 rb_gvar_ractor_local("$stderr");
15870
15872 rb_stdin = rb_io_prep_stdin();
15874 rb_stdout = rb_io_prep_stdout();
15876 rb_stderr = rb_io_prep_stderr();
15877
15878 orig_stdout = rb_stdout;
15879 orig_stderr = rb_stderr;
15880
15881 /* Holds the original stdin */
15883 /* Holds the original stdout */
15885 /* Holds the original stderr */
15887
15888#if 0
15889 /* Hack to get rdoc to regard ARGF as a class: */
15890 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15891#endif
15892
15893 rb_cARGF = rb_class_new(rb_cObject);
15894 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15895 rb_define_alloc_func(rb_cARGF, argf_alloc);
15896
15898
15899 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15900 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15901 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15902 rb_define_alias(rb_cARGF, "inspect", "to_s");
15903 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15904
15905 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15906 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15907 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15908 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15909 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15910 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15911 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15912 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15913 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15914
15915 rb_define_method(rb_cARGF, "read", argf_read, -1);
15916 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15917 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15918 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15919 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15920 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15921 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15922 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15923 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15924 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15925 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15926 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15927 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15928 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15929 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15930 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15931 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15932 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15933 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15934 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15935
15936 rb_define_method(rb_cARGF, "write", argf_write, -1);
15937 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15938 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15939 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15940 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15941
15942 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15943 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15944 rb_define_method(rb_cARGF, "file", argf_file, 0);
15945 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15946 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15947 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15948
15949 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15950 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15951
15952 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15953 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15954
15955 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15956 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15957 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15958
15959 argf = rb_class_new_instance(0, 0, rb_cARGF);
15960
15962 /*
15963 * ARGF is a stream designed for use in scripts that process files given
15964 * as command-line arguments or passed in via STDIN.
15965 *
15966 * See ARGF (the class) for more details.
15967 */
15969
15970 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15971 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15972 ARGF.filename = rb_str_new2("-");
15973
15974 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15975 rb_gvar_ractor_local("$-i");
15976
15977 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15978
15979#if defined (_WIN32) || defined(__CYGWIN__)
15980 atexit(pipe_atexit);
15981#endif
15982
15983 Init_File();
15984
15985 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
15986
15987 sym_mode = ID2SYM(rb_intern_const("mode"));
15988 sym_perm = ID2SYM(rb_intern_const("perm"));
15989 sym_flags = ID2SYM(rb_intern_const("flags"));
15990 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
15991 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
15992 sym_encoding = ID2SYM(rb_id_encoding());
15993 sym_open_args = ID2SYM(rb_intern_const("open_args"));
15994 sym_textmode = ID2SYM(rb_intern_const("textmode"));
15995 sym_binmode = ID2SYM(rb_intern_const("binmode"));
15996 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
15997 sym_normal = ID2SYM(rb_intern_const("normal"));
15998 sym_sequential = ID2SYM(rb_intern_const("sequential"));
15999 sym_random = ID2SYM(rb_intern_const("random"));
16000 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16001 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16002 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16003 sym_SET = ID2SYM(rb_intern_const("SET"));
16004 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16005 sym_END = ID2SYM(rb_intern_const("END"));
16006#ifdef SEEK_DATA
16007 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16008#endif
16009#ifdef SEEK_HOLE
16010 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16011#endif
16012 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16013 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16014}
16015
16016#include "io.rbinc"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:117
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1795
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1588
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:968
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1619
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1724
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2947
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:3250
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:3237
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1007
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:3026
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1674
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:400
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1682
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:134
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:111
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:520
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:109
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition ctype.h:103
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:518
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition transcode.h:538
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:519
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1676
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
void rb_notimplement(void)
Definition error.c:3840
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:476
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:508
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1441
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:653
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3909
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
Definition io.c:14695
VALUE rb_eIOError
IOError exception.
Definition io.c:189
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1428
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3999
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3915
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:475
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1431
VALUE rb_eEOFError
EOFError exception.
Definition io.c:188
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14689
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2283
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1429
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1451
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:60
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3295
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:675
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2191
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2232
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:2220
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:264
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:582
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:686
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:1342
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:3276
VALUE rb_cFile
File class.
Definition file.c:191
VALUE rb_stdout
STDOUT constant.
Definition io.c:201
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3289
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
Definition encoding.h:571
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1340
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3922
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c:829
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
Definition transcode.c:2660
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
Definition transcode.c:2123
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
Definition transcode.c:1485
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
Definition transcode.h:69
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
Definition transcode.h:41
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1780
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1824
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
Definition transcode.c:1959
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
Definition transcode.c:2711
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
Definition transcode.c:2022
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
Definition transcode.c:2974
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4340
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4346
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1741
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1791
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1117
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
Definition vm_eval.c:1084
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:239
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8601
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4309
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:8734
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2358
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9163
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:5174
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5080
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:9344
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:2703
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:9143
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:6389
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6343
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5238
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7391
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10422
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:461
VALUE rb_output_fs
The field separator character for outputs, or the $,.
Definition io.c:204
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
Definition io.c:7274
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:7281
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5756
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:2045
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:2039
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:3121
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1168
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:682
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3795
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1497
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1680
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1531
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:999
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1516
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1994
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3563
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4265
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3385
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
Definition string.c:3737
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2948
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3248
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3367
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2742
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1716
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1513
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c:1848
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1481
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:1611
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
Definition thread.c:1464
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:3178
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1605
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1487
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2949
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:441
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:2013
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:500
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3382
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
Definition vm_eval.c:686
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:284
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
Definition variable.c:4026
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
Definition variable.c:846
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:162
enum rb_io_mode rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
Definition io.c:6475
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:6608
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
Definition io.h:260
rb_io_event
Type of events that an IO can wait.
Definition io.h:96
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:97
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition io.h:99
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition io.h:98
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:168
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
Definition io.h:252
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:442
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
Definition io.c:1015
#define FMODE_TTY
The IO is a TTY.
Definition io.h:192
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:215
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition io.c:1024
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
Definition io.c:1597
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:7091
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
Definition io.c:6757
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2906
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:165
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
Definition io.c:9390
#define FMODE_APPEND
The IO is opened for appending.
Definition io.h:207
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition io.h:465
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition io.h:200
#define FMODE_BINMODE
The IO is in "binary mode".
Definition io.h:179
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
Definition io.c:1658
int capa
Designed capacity of the buffer.
Definition io.h:11
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition io.h:436
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
Definition io.c:1617
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:190
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:2
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:186
int off
Offset inside of ptr.
Definition io.h:5
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
Definition io.c:2980
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, enum rb_io_mode *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
Definition io.c:6882
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:788
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
Definition io.h:223
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition io.h:243
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
Definition io.c:5676
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:5864
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:2023
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:996
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
Definition io.h:229
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:823
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3430
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1553
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:9256
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:1673
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:796
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1518
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7378
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1458
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:1062
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:1122
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:1110
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:1098
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:2061
#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:1417
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1372
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition off_t.h:55
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:409
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:450
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:80
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:508
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14655
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9042
#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:466
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:1001
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:517
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:751
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:977
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:737
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:72
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:781
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:1013
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread value inst...
Definition scheduler.c:474
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:989
VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread)
Identical to rb_fiber_scheduler_current_for_thread(), except it expects a threadptr instead of a thre...
Definition scheduler.c:479
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:757
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
Definition scheduler.c:1025
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:4531
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
@ RUBY_Qfalse
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
C99 shim for <stdbool.h>
Ruby's File and IO.
Definition rfile.h:35
Definition io.c:236
Definition win32.h:230
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:208
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
Decomposed encoding flags (e.g.
Definition io.h:134
int ecflags
Flags.
Definition io.h:144
VALUE ecopts
Flags as Ruby hash.
Definition io.h:152
rb_encoding * enc2
External encoding.
Definition io.h:138
rb_encoding * enc
Internal encoding.
Definition io.h:136
IO buffers.
Definition io.h:109
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:112
int off
Offset inside of ptr.
Definition io.h:115
int len
Length of the buffer.
Definition io.h:118
int capa
Designed capacity of the buffer.
Definition io.h:121
Ruby's IO, metadata and buffers.
Definition io.h:295
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:330
enum rb_io_mode mode
mode flags: FMODE_XXXs
Definition io.h:310
void(* finalize)(struct rb_io *, int)
finalize proc
Definition io.h:326
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:352
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:363
struct rb_io_encoding encs
Decomposed encoding flags.
Definition io.h:348
VALUE self
The IO's Ruby level counterpart.
Definition io.h:298
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:400
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:406
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:302
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
Definition io.h:390
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:345
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:376
int fd
file descriptor.
Definition io.h:306
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:337
int lineno
number of lines read
Definition io.h:318
struct ccan_list_head blocking_operations
Threads that are performing a blocking operation without the GVL using this IO.
Definition io.h:131
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:372
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:359
rb_pid_t pid
child's pid (for pipes)
Definition io.h:314
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
Definition io.h:383
VALUE pathv
pathname for file
Definition io.h:322
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
Definition value_type.h:307
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:433
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376