Ruby 3.5.0dev (2025-05-16 revision 04f538c1441e65def90d5b4224010e7d4f4ffab3)
io.c (04f538c1441e65def90d5b4224010e7d4f4ffab3)
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17#include "ruby/io/buffer.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <stddef.h>
22
23/* non-Linux poll may not work on all FDs */
24#if defined(HAVE_POLL)
25# if defined(__linux__)
26# define USE_POLL 1
27# endif
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29# define USE_POLL 1
30# endif
31#endif
32
33#ifndef USE_POLL
34# define USE_POLL 0
35#endif
36
37#undef free
38#define free(x) xfree(x)
39
40#if defined(DOSISH) || defined(__CYGWIN__)
41#include <io.h>
42#endif
43
44#include <sys/types.h>
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
49#endif
50
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
53#endif
54
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
56# define USE_SETVBUF
57#endif
58
59#ifdef __QNXNTO__
60#include <unix.h>
61#endif
62
63#include <sys/types.h>
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
65#include <sys/ioctl.h>
66#endif
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
68#include <fcntl.h>
69#elif defined(HAVE_SYS_FCNTL_H)
70#include <sys/fcntl.h>
71#endif
72
73#ifdef HAVE_SYS_TIME_H
74# include <sys/time.h>
75#endif
76
77#include <sys/stat.h>
78
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
81#endif
82
83#if !defined NOFILE
84# define NOFILE 64
85#endif
86
87#ifdef HAVE_UNISTD_H
88#include <unistd.h>
89#endif
90
91#ifdef HAVE_SYSCALL_H
92#include <syscall.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
95#endif
96
97#ifdef HAVE_SYS_UIO_H
98#include <sys/uio.h>
99#endif
100
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h> /* for WNOHANG on BSD */
103#endif
104
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
107
108# ifndef COPYFILE_STATE_COPIED
109/*
110 * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
111 * COPYFILE_STATE_COPIED. Since the only use of the former here
112 * requires the latter, we disable the former when the latter is undefined.
113 */
114# undef HAVE_FCOPYFILE
115# endif
116
117#endif
118
120#include "ccan/list/list.h"
121#include "dln.h"
122#include "encindex.h"
123#include "id.h"
124#include "internal.h"
125#include "internal/class.h"
126#include "internal/encoding.h"
127#include "internal/error.h"
128#include "internal/inits.h"
129#include "internal/io.h"
130#include "internal/numeric.h"
131#include "internal/object.h"
132#include "internal/process.h"
133#include "internal/thread.h"
134#include "internal/transcode.h"
135#include "internal/variable.h"
136#include "ruby/io.h"
137#include "ruby/io/buffer.h"
138#include "ruby/missing.h"
139#include "ruby/thread.h"
140#include "ruby/util.h"
141#include "ruby_atomic.h"
142#include "ruby/ractor.h"
143
144#if !USE_POLL
145# include "vm_core.h"
146#endif
147
148#include "builtin.h"
149
150#ifndef O_ACCMODE
151#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
152#endif
153
154#ifndef PIPE_BUF
155# ifdef _POSIX_PIPE_BUF
156# define PIPE_BUF _POSIX_PIPE_BUF
157# else
158# define PIPE_BUF 512 /* is this ok? */
159# endif
160#endif
161
162#ifndef EWOULDBLOCK
163# define EWOULDBLOCK EAGAIN
164#endif
165
166#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
167/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
168off_t __syscall(quad_t number, ...);
169#endif
170
171#define IO_RBUF_CAPA_MIN 8192
172#define IO_CBUF_CAPA_MIN (128*1024)
173#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174#define IO_WBUF_CAPA_MIN 8192
175
176#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
177
178/* define system APIs */
179#ifdef _WIN32
180#undef open
181#define open rb_w32_uopen
182#undef rename
183#define rename(f, t) rb_w32_urename((f), (t))
184#include "win32/file.h"
185#endif
186
193
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196static VALUE rb_eEWOULDBLOCKWaitReadable;
197static VALUE rb_eEWOULDBLOCKWaitWritable;
198static VALUE rb_eEINPROGRESSWaitWritable;
199static VALUE rb_eEINPROGRESSWaitReadable;
200
202static VALUE orig_stdout, orig_stderr;
203
205VALUE rb_rs;
208
209static VALUE argf;
210
211static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
212static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
213static VALUE sym_textmode, sym_binmode, sym_autoclose;
214static VALUE sym_SET, sym_CUR, sym_END;
215static VALUE sym_wait_readable, sym_wait_writable;
216#ifdef SEEK_DATA
217static VALUE sym_DATA;
218#endif
219#ifdef SEEK_HOLE
220static VALUE sym_HOLE;
221#endif
222
223static VALUE prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path);
224
225VALUE
226rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
227{
228 return rb_thread_io_blocking_call(io, function, argument, events);
229}
230
231VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
232{
233 return rb_io_blocking_region_wait(io, function, argument, 0);
234}
235
236struct argf {
237 VALUE filename, current_file;
238 long last_lineno; /* $. */
239 long lineno;
240 VALUE argv;
241 VALUE inplace;
242 struct rb_io_encoding encs;
243 int8_t init_p, next_p, binmode;
244};
245
246static rb_atomic_t max_file_descriptor = NOFILE;
247void
249{
250 rb_atomic_t afd = (rb_atomic_t)fd;
251 rb_atomic_t max_fd = max_file_descriptor;
252 int err;
253
254 if (fd < 0 || afd <= max_fd)
255 return;
256
257#if defined(HAVE_FCNTL) && defined(F_GETFL)
258 err = fcntl(fd, F_GETFL) == -1;
259#else
260 {
261 struct stat buf;
262 err = fstat(fd, &buf) != 0;
263 }
264#endif
265 if (err && errno == EBADF) {
266 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
267 }
268
269 while (max_fd < afd) {
270 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
271 }
272}
273
274void
275rb_maygvl_fd_fix_cloexec(int fd)
276{
277 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
278#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
279 int flags, flags2, ret;
280 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
281 if (flags == -1) {
282 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
283 }
284 if (fd <= 2)
285 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
286 else
287 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
288 if (flags != flags2) {
289 ret = fcntl(fd, F_SETFD, flags2);
290 if (ret != 0) {
291 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
292 }
293 }
294#endif
295}
296
297void
299{
300 rb_maygvl_fd_fix_cloexec(fd);
302}
303
304/* this is only called once */
305static int
306rb_fix_detect_o_cloexec(int fd)
307{
308#if defined(O_CLOEXEC) && defined(F_GETFD)
309 int flags = fcntl(fd, F_GETFD);
310
311 if (flags == -1)
312 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
313
314 if (flags & FD_CLOEXEC)
315 return 1;
316#endif /* fall through if O_CLOEXEC does not work: */
317 rb_maygvl_fd_fix_cloexec(fd);
318 return 0;
319}
320
321static inline bool
322io_again_p(int e)
323{
324 return (e == EWOULDBLOCK) || (e == EAGAIN);
325}
326
327int
328rb_cloexec_open(const char *pathname, int flags, mode_t mode)
329{
330 int ret;
331 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
332
333 static const int retry_interval = 0;
334 static const int retry_max_count = 10000;
335
336 int retry_count = 0;
337
338#ifdef O_CLOEXEC
339 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
340 flags |= O_CLOEXEC;
341#elif defined O_NOINHERIT
342 flags |= O_NOINHERIT;
343#endif
344
345 while ((ret = open(pathname, flags, mode)) == -1) {
346 int e = errno;
347 if (!io_again_p(e)) break;
348 if (retry_count++ >= retry_max_count) break;
349
350 sleep(retry_interval);
351 }
352
353 if (ret < 0) return ret;
354 if (ret <= 2 || o_cloexec_state == 0) {
355 rb_maygvl_fd_fix_cloexec(ret);
356 }
357 else if (o_cloexec_state > 0) {
358 return ret;
359 }
360 else {
361 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
362 }
363 return ret;
364}
365
366int
368{
369 /* Don't allocate standard file descriptors: 0, 1, 2 */
370 return rb_cloexec_fcntl_dupfd(oldfd, 3);
371}
372
373int
374rb_cloexec_dup2(int oldfd, int newfd)
375{
376 int ret;
377
378 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
379 * rb_cloexec_dup2 succeeds as dup2. */
380 if (oldfd == newfd) {
381 ret = newfd;
382 }
383 else {
384#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
385 static int try_dup3 = 1;
386 if (2 < newfd && try_dup3) {
387 ret = dup3(oldfd, newfd, O_CLOEXEC);
388 if (ret != -1)
389 return ret;
390 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
391 if (errno == ENOSYS) {
392 try_dup3 = 0;
393 ret = dup2(oldfd, newfd);
394 }
395 }
396 else {
397 ret = dup2(oldfd, newfd);
398 }
399#else
400 ret = dup2(oldfd, newfd);
401#endif
402 if (ret < 0) return ret;
403 }
404 rb_maygvl_fd_fix_cloexec(ret);
405 return ret;
406}
407
408static int
409rb_fd_set_nonblock(int fd)
410{
411#ifdef _WIN32
412 return rb_w32_set_nonblock(fd);
413#elif defined(F_GETFL)
414 int oflags = fcntl(fd, F_GETFL);
415
416 if (oflags == -1)
417 return -1;
418 if (oflags & O_NONBLOCK)
419 return 0;
420 oflags |= O_NONBLOCK;
421 return fcntl(fd, F_SETFL, oflags);
422#endif
423 return 0;
424}
425
426int
427rb_cloexec_pipe(int descriptors[2])
428{
429#ifdef HAVE_PIPE2
430 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
431#else
432 int result = pipe(descriptors);
433#endif
434
435 if (result < 0)
436 return result;
437
438#ifdef __CYGWIN__
439 if (result == 0 && descriptors[1] == -1) {
440 close(descriptors[0]);
441 descriptors[0] = -1;
442 errno = ENFILE;
443 return -1;
444 }
445#endif
446
447#ifndef HAVE_PIPE2
448 rb_maygvl_fd_fix_cloexec(descriptors[0]);
449 rb_maygvl_fd_fix_cloexec(descriptors[1]);
450
451#ifndef _WIN32
452 rb_fd_set_nonblock(descriptors[0]);
453 rb_fd_set_nonblock(descriptors[1]);
454#endif
455#endif
456
457 return result;
458}
459
460int
461rb_cloexec_fcntl_dupfd(int fd, int minfd)
462{
463 int ret;
464
465#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
466 static int try_dupfd_cloexec = 1;
467 if (try_dupfd_cloexec) {
468 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
469 if (ret != -1) {
470 if (ret <= 2)
471 rb_maygvl_fd_fix_cloexec(ret);
472 return ret;
473 }
474 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
475 if (errno == EINVAL) {
476 ret = fcntl(fd, F_DUPFD, minfd);
477 if (ret != -1) {
478 try_dupfd_cloexec = 0;
479 }
480 }
481 }
482 else {
483 ret = fcntl(fd, F_DUPFD, minfd);
484 }
485#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
486 ret = fcntl(fd, F_DUPFD, minfd);
487#else
488 ret = dup(fd);
489 if (ret >= 0 && ret < minfd) {
490 const int prev_fd = ret;
491 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
492 close(prev_fd);
493 }
494 return ret;
495#endif
496 if (ret < 0) return ret;
497 rb_maygvl_fd_fix_cloexec(ret);
498 return ret;
499}
500
501#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
502#define ARGF argf_of(argf)
503
504#define GetWriteIO(io) rb_io_get_write_io(io)
505
506#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
507#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
508#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
509#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
510
511#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
512#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
513#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
514
515#if defined(_WIN32)
516#define WAIT_FD_IN_WIN32(fptr) \
517 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
518#else
519#define WAIT_FD_IN_WIN32(fptr)
520#endif
521
522#define READ_CHECK(fptr) do {\
523 if (!READ_DATA_PENDING(fptr)) {\
524 WAIT_FD_IN_WIN32(fptr);\
525 rb_io_check_closed(fptr);\
526 }\
527} while(0)
528
529#ifndef S_ISSOCK
530# ifdef _S_ISSOCK
531# define S_ISSOCK(m) _S_ISSOCK(m)
532# else
533# ifdef _S_IFSOCK
534# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
535# else
536# ifdef S_IFSOCK
537# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
538# endif
539# endif
540# endif
541#endif
542
543static int io_fflush(rb_io_t *);
544static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
545static void clear_codeconv(rb_io_t *fptr);
546
547#define FMODE_SIGNAL_ON_EPIPE (1<<17)
548
549#define fptr_signal_on_epipe(fptr) \
550 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
551
552#define fptr_set_signal_on_epipe(fptr, flag) \
553 ((flag) ? \
554 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
555 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
556
557extern ID ruby_static_id_signo;
558
559NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
560static void
561rb_sys_fail_on_write(rb_io_t *fptr)
562{
563 int e = errno;
564 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
565#if defined EPIPE
566 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
567 const VALUE sig =
568# if defined SIGPIPE
569 INT2FIX(SIGPIPE) - INT2FIX(0) +
570# endif
571 INT2FIX(0);
572 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
573 }
574#endif
575 rb_exc_raise(errinfo);
576}
577
578#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
579#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
580#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
581# define RUBY_CRLF_ENVIRONMENT 1
582#else
583# define RUBY_CRLF_ENVIRONMENT 0
584#endif
585
586#if RUBY_CRLF_ENVIRONMENT
587/* Windows */
588# define DEFAULT_TEXTMODE FMODE_TEXTMODE
589# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
590/*
591 * CRLF newline is set as default newline decorator.
592 * If only CRLF newline conversion is needed, we use binary IO process
593 * with OS's text mode for IO performance improvement.
594 * If encoding conversion is needed or a user sets text mode, we use encoding
595 * conversion IO process and universal newline decorator by default.
596 */
597#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
598#define WRITECONV_MASK ( \
599 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
600 ECONV_STATEFUL_DECORATOR_MASK|\
601 0)
602#define NEED_WRITECONV(fptr) ( \
603 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
604 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
605 0)
606#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
607
608#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
609 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
610 if (((fptr)->mode & FMODE_READABLE) &&\
611 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
612 setmode((fptr)->fd, O_BINARY);\
613 }\
614 else {\
615 setmode((fptr)->fd, O_TEXT);\
616 }\
617 }\
618} while(0)
619
620#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
621 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
622 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
623 }\
624} while(0)
625
626/*
627 * IO unread with taking care of removed '\r' in text mode.
628 */
629static void
630io_unread(rb_io_t *fptr, bool discard_rbuf)
631{
632 rb_off_t r, pos;
633 ssize_t read_size;
634 long i;
635 long newlines = 0;
636 long extra_max;
637 char *p;
638 char *buf;
639
640 rb_io_check_closed(fptr);
641 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
642 return;
643 }
644
645 errno = 0;
646 if (!rb_w32_fd_is_text(fptr->fd)) {
647 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
648 if (r < 0 && errno) {
649 if (errno == ESPIPE)
650 fptr->mode |= FMODE_DUPLEX;
651 if (!discard_rbuf) return;
652 }
653
654 goto end;
655 }
656
657 pos = lseek(fptr->fd, 0, SEEK_CUR);
658 if (pos < 0 && errno) {
659 if (errno == ESPIPE)
660 fptr->mode |= FMODE_DUPLEX;
661 if (!discard_rbuf) goto end;
662 }
663
664 /* add extra offset for removed '\r' in rbuf */
665 extra_max = (long)(pos - fptr->rbuf.len);
666 p = fptr->rbuf.ptr + fptr->rbuf.off;
667
668 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
669 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
670 newlines++;
671 }
672
673 for (i = 0; i < fptr->rbuf.len; i++) {
674 if (*p == '\n') newlines++;
675 if (extra_max == newlines) break;
676 p++;
677 }
678
679 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
680 while (newlines >= 0) {
681 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
682 if (newlines == 0) break;
683 if (r < 0) {
684 newlines--;
685 continue;
686 }
687 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
688 if (read_size < 0) {
689 int e = errno;
690 free(buf);
691 rb_syserr_fail_path(e, fptr->pathv);
692 }
693 if (read_size == fptr->rbuf.len) {
694 lseek(fptr->fd, r, SEEK_SET);
695 break;
696 }
697 else {
698 newlines--;
699 }
700 }
701 free(buf);
702 end:
703 fptr->rbuf.off = 0;
704 fptr->rbuf.len = 0;
705 clear_codeconv(fptr);
706 return;
707}
708
709/*
710 * We use io_seek to back cursor position when changing mode from text to binary,
711 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
712 * conversion for working properly with mode change.
713 *
714 * Return previous translation mode.
715 */
716static inline int
717set_binary_mode_with_seek_cur(rb_io_t *fptr)
718{
719 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
720
721 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
722 return setmode(fptr->fd, O_BINARY);
723 }
724 flush_before_seek(fptr, false);
725 return setmode(fptr->fd, O_BINARY);
726}
727#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
728
729#else
730/* Unix */
731# define DEFAULT_TEXTMODE 0
732#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
733#define NEED_WRITECONV(fptr) ( \
734 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
735 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
736 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
737 0)
738#define SET_BINARY_MODE(fptr) (void)(fptr)
739#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
740#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
741#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
742#endif
743
744#if !defined HAVE_SHUTDOWN && !defined shutdown
745#define shutdown(a,b) 0
746#endif
747
748#if defined(_WIN32)
749#define is_socket(fd, path) rb_w32_is_socket(fd)
750#elif !defined(S_ISSOCK)
751#define is_socket(fd, path) 0
752#else
753static int
754is_socket(int fd, VALUE path)
755{
756 struct stat sbuf;
757 if (fstat(fd, &sbuf) < 0)
758 rb_sys_fail_path(path);
759 return S_ISSOCK(sbuf.st_mode);
760}
761#endif
762
763static const char closed_stream[] = "closed stream";
764
765static void
766io_fd_check_closed(int fd)
767{
768 if (fd < 0) {
769 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
770 rb_raise(rb_eIOError, closed_stream);
771 }
772}
773
774void
775rb_eof_error(void)
776{
777 rb_raise(rb_eEOFError, "end of file reached");
778}
779
780VALUE
782{
783 rb_check_frozen(io);
784 return io;
785}
786
787void
789{
790 if (!fptr) {
791 rb_raise(rb_eIOError, "uninitialized stream");
792 }
793}
794
795void
797{
799 io_fd_check_closed(fptr->fd);
800}
801
802static rb_io_t *
803rb_io_get_fptr(VALUE io)
804{
805 rb_io_t *fptr = RFILE(io)->fptr;
807 return fptr;
808}
809
810VALUE
812{
813 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
814}
815
816VALUE
818{
819 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
820}
821
822VALUE
824{
825 VALUE write_io;
826 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
827 if (write_io) {
828 return write_io;
829 }
830 return io;
831}
832
833VALUE
835{
836 VALUE write_io;
837 rb_io_t *fptr = rb_io_get_fptr(io);
838 if (!RTEST(w)) {
839 w = 0;
840 }
841 else {
842 GetWriteIO(w);
843 }
844 write_io = fptr->tied_io_for_writing;
845 fptr->tied_io_for_writing = w;
846 return write_io ? write_io : Qnil;
847}
848
849/*
850 * call-seq:
851 * timeout -> duration or nil
852 *
853 * Get the internal timeout duration or nil if it was not set.
854 *
855 */
856VALUE
858{
859 rb_io_t *fptr = rb_io_get_fptr(self);
860
861 return fptr->timeout;
862}
863
864/*
865 * call-seq:
866 * timeout = duration -> duration
867 * timeout = nil -> nil
868 *
869 * Sets the internal timeout to the specified duration or nil. The timeout
870 * applies to all blocking operations where possible.
871 *
872 * When the operation performs longer than the timeout set, IO::TimeoutError
873 * is raised.
874 *
875 * This affects the following methods (but is not limited to): #gets, #puts,
876 * #read, #write, #wait_readable and #wait_writable. This also affects
877 * blocking socket operations like Socket#accept and Socket#connect.
878 *
879 * Some operations like File#open and IO#close are not affected by the
880 * timeout. A timeout during a write operation may leave the IO in an
881 * inconsistent state, e.g. data was partially written. Generally speaking, a
882 * timeout is a last ditch effort to prevent an application from hanging on
883 * slow I/O operations, such as those that occur during a slowloris attack.
884 */
885VALUE
887{
888 // Validate it:
889 if (RTEST(timeout)) {
890 rb_time_interval(timeout);
891 }
892
893 rb_io_t *fptr = rb_io_get_fptr(self);
894
895 fptr->timeout = timeout;
896
897 return self;
898}
899
900/*
901 * call-seq:
902 * IO.try_convert(object) -> new_io or nil
903 *
904 * Attempts to convert +object+ into an \IO object via method +to_io+;
905 * returns the new \IO object if successful, or +nil+ otherwise:
906 *
907 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
908 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
909 * IO.try_convert('STDOUT') # => nil
910 *
911 */
912static VALUE
913rb_io_s_try_convert(VALUE dummy, VALUE io)
914{
915 return rb_io_check_io(io);
916}
917
918#if !RUBY_CRLF_ENVIRONMENT
919static void
920io_unread(rb_io_t *fptr, bool discard_rbuf)
921{
922 rb_off_t r;
923 rb_io_check_closed(fptr);
924 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
925 return;
926 /* xxx: target position may be negative if buffer is filled by ungetc */
927 errno = 0;
928 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
929 if (r < 0 && errno) {
930 if (errno == ESPIPE)
931 fptr->mode |= FMODE_DUPLEX;
932 if (!discard_rbuf) return;
933 }
934 fptr->rbuf.off = 0;
935 fptr->rbuf.len = 0;
936 clear_codeconv(fptr);
937 return;
938}
939#endif
940
941static rb_encoding *io_input_encoding(rb_io_t *fptr);
942
943static void
944io_ungetbyte(VALUE str, rb_io_t *fptr)
945{
946 long len = RSTRING_LEN(str);
947
948 if (fptr->rbuf.ptr == NULL) {
949 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
950 fptr->rbuf.off = 0;
951 fptr->rbuf.len = 0;
952#if SIZEOF_LONG > SIZEOF_INT
953 if (len > INT_MAX)
954 rb_raise(rb_eIOError, "ungetbyte failed");
955#endif
956 if (len > min_capa)
957 fptr->rbuf.capa = (int)len;
958 else
959 fptr->rbuf.capa = min_capa;
960 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
961 }
962 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
963 rb_raise(rb_eIOError, "ungetbyte failed");
964 }
965 if (fptr->rbuf.off < len) {
966 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
967 fptr->rbuf.ptr+fptr->rbuf.off,
968 char, fptr->rbuf.len);
969 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
970 }
971 fptr->rbuf.off-=(int)len;
972 fptr->rbuf.len+=(int)len;
973 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
974}
975
976static rb_io_t *
977flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
978{
979 if (io_fflush(fptr) < 0)
980 rb_sys_fail_on_write(fptr);
981 io_unread(fptr, discard_rbuf);
982 errno = 0;
983 return fptr;
984}
985
986#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
987#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
988
989#ifndef SEEK_CUR
990# define SEEK_SET 0
991# define SEEK_CUR 1
992# define SEEK_END 2
993#endif
994
995void
997{
998 rb_io_check_closed(fptr);
999 if (!(fptr->mode & FMODE_READABLE)) {
1000 rb_raise(rb_eIOError, "not opened for reading");
1001 }
1002 if (fptr->wbuf.len) {
1003 if (io_fflush(fptr) < 0)
1004 rb_sys_fail_on_write(fptr);
1005 }
1006 if (fptr->tied_io_for_writing) {
1007 rb_io_t *wfptr;
1008 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1009 if (io_fflush(wfptr) < 0)
1010 rb_sys_fail_on_write(wfptr);
1011 }
1012}
1013
1014void
1016{
1018 if (READ_CHAR_PENDING(fptr)) {
1019 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1020 }
1021}
1022
1023void
1028
1029static rb_encoding*
1030io_read_encoding(rb_io_t *fptr)
1031{
1032 if (fptr->encs.enc) {
1033 return fptr->encs.enc;
1034 }
1035 return rb_default_external_encoding();
1036}
1037
1038static rb_encoding*
1039io_input_encoding(rb_io_t *fptr)
1040{
1041 if (fptr->encs.enc2) {
1042 return fptr->encs.enc2;
1043 }
1044 return io_read_encoding(fptr);
1045}
1046
1047void
1049{
1050 rb_io_check_closed(fptr);
1051 if (!(fptr->mode & FMODE_WRITABLE)) {
1052 rb_raise(rb_eIOError, "not opened for writing");
1053 }
1054 if (fptr->rbuf.len) {
1055 io_unread(fptr, true);
1056 }
1057}
1058
1059int
1060rb_io_read_pending(rb_io_t *fptr)
1061{
1062 /* This function is used for bytes and chars. Confusing. */
1063 if (READ_CHAR_PENDING(fptr))
1064 return 1; /* should raise? */
1065 return READ_DATA_PENDING(fptr);
1066}
1067
1068void
1070{
1071 if (!READ_DATA_PENDING(fptr)) {
1072 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1073 }
1074 return;
1075}
1076
1077int
1078rb_gc_for_fd(int err)
1079{
1080 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1081 rb_gc();
1082 return 1;
1083 }
1084 return 0;
1085}
1086
1087/* try `expr` upto twice while it returns false and `errno`
1088 * is to GC. Each `errno`s are available as `first_errno` and
1089 * `retried_errno` respectively */
1090#define TRY_WITH_GC(expr) \
1091 for (int first_errno, retried_errno = 0, retried = 0; \
1092 (!retried && \
1093 !(expr) && \
1094 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1095 (retried_errno = errno, 1)); \
1096 (void)retried_errno, retried = 1)
1097
1098static int
1099ruby_dup(int orig)
1100{
1101 int fd = -1;
1102
1103 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1104 rb_syserr_fail(first_errno, 0);
1105 }
1106 rb_update_max_fd(fd);
1107 return fd;
1108}
1109
1110static VALUE
1111io_alloc(VALUE klass)
1112{
1113 NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
1114
1115 io->fptr = 0;
1116
1117 return (VALUE)io;
1118}
1119
1120#ifndef S_ISREG
1121# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1122#endif
1123
1125 VALUE th;
1126 rb_io_t *fptr;
1127 int nonblock;
1128 int fd;
1129
1130 void *buf;
1131 size_t capa;
1132 struct timeval *timeout;
1133};
1134
1136 VALUE th;
1137 rb_io_t *fptr;
1138 int nonblock;
1139 int fd;
1140
1141 const void *buf;
1142 size_t capa;
1143 struct timeval *timeout;
1144};
1145
1146#ifdef HAVE_WRITEV
1147struct io_internal_writev_struct {
1148 VALUE th;
1149 rb_io_t *fptr;
1150 int nonblock;
1151 int fd;
1152
1153 int iovcnt;
1154 const struct iovec *iov;
1155 struct timeval *timeout;
1156};
1157#endif
1158
1159static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1160
1166static inline int
1167io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1168{
1169 if (!timeout && rb_thread_mn_schedulable(thread)) {
1170 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1171 return -1;
1172 }
1173
1174 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1175
1176 if (ready > 0) {
1177 return ready;
1178 }
1179 else if (ready == 0) {
1180 errno = ETIMEDOUT;
1181 return -1;
1182 }
1183
1184 // If there was an error BEFORE we started waiting, return it:
1185 if (error) {
1186 errno = error;
1187 return -1;
1188 }
1189 else {
1190 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1191 return ready;
1192 }
1193}
1194
1195static VALUE
1196internal_read_func(void *ptr)
1197{
1198 struct io_internal_read_struct *iis = ptr;
1199 ssize_t result;
1200
1201 if (iis->timeout && !iis->nonblock) {
1202 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1203 return -1;
1204 }
1205 }
1206
1207 retry:
1208 result = read(iis->fd, iis->buf, iis->capa);
1209
1210 if (result < 0 && !iis->nonblock) {
1211 if (io_again_p(errno)) {
1212 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1213 return -1;
1214 }
1215 else {
1216 goto retry;
1217 }
1218 }
1219 }
1220
1221 return result;
1222}
1223
1224#if defined __APPLE__
1225# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1226#else
1227# define do_write_retry(code) result = code
1228#endif
1229
1230static VALUE
1231internal_write_func(void *ptr)
1232{
1233 struct io_internal_write_struct *iis = ptr;
1234 ssize_t result;
1235
1236 if (iis->timeout && !iis->nonblock) {
1237 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1238 return -1;
1239 }
1240 }
1241
1242 retry:
1243 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1244
1245 if (result < 0 && !iis->nonblock) {
1246 int e = errno;
1247 if (io_again_p(e)) {
1248 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1249 return -1;
1250 }
1251 else {
1252 goto retry;
1253 }
1254 }
1255 }
1256
1257 return result;
1258}
1259
1260#ifdef HAVE_WRITEV
1261static VALUE
1262internal_writev_func(void *ptr)
1263{
1264 struct io_internal_writev_struct *iis = ptr;
1265 ssize_t result;
1266
1267 if (iis->timeout && !iis->nonblock) {
1268 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1269 return -1;
1270 }
1271 }
1272
1273 retry:
1274 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1275
1276 if (result < 0 && !iis->nonblock) {
1277 if (io_again_p(errno)) {
1278 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1279 return -1;
1280 }
1281 else {
1282 goto retry;
1283 }
1284 }
1285 }
1286
1287 return result;
1288}
1289#endif
1290
1291static ssize_t
1292rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1293{
1294 VALUE scheduler = rb_fiber_scheduler_current();
1295 if (scheduler != Qnil) {
1296 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1297
1298 if (!UNDEF_P(result)) {
1300 }
1301 }
1302
1303 struct io_internal_read_struct iis = {
1304 .th = rb_thread_current(),
1305 .fptr = fptr,
1306 .nonblock = 0,
1307 .fd = fptr->fd,
1308
1309 .buf = buf,
1310 .capa = count,
1311 .timeout = NULL,
1312 };
1313
1314 struct timeval timeout_storage;
1315
1316 if (fptr->timeout != Qnil) {
1317 timeout_storage = rb_time_interval(fptr->timeout);
1318 iis.timeout = &timeout_storage;
1319 }
1320
1321 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1322}
1323
1324static ssize_t
1325rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1326{
1327 VALUE scheduler = rb_fiber_scheduler_current();
1328 if (scheduler != Qnil) {
1329 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1330
1331 if (!UNDEF_P(result)) {
1333 }
1334 }
1335
1336 struct io_internal_write_struct iis = {
1337 .th = rb_thread_current(),
1338 .fptr = fptr,
1339 .nonblock = 0,
1340 .fd = fptr->fd,
1341
1342 .buf = buf,
1343 .capa = count,
1344 .timeout = NULL
1345 };
1346
1347 struct timeval timeout_storage;
1348
1349 if (fptr->timeout != Qnil) {
1350 timeout_storage = rb_time_interval(fptr->timeout);
1351 iis.timeout = &timeout_storage;
1352 }
1353
1354 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1355}
1356
1357#ifdef HAVE_WRITEV
1358static ssize_t
1359rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1360{
1361 if (!iovcnt) return 0;
1362
1363 VALUE scheduler = rb_fiber_scheduler_current();
1364 if (scheduler != Qnil) {
1365 // This path assumes at least one `iov`:
1366 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1367
1368 if (!UNDEF_P(result)) {
1370 }
1371 }
1372
1373 struct io_internal_writev_struct iis = {
1374 .th = rb_thread_current(),
1375 .fptr = fptr,
1376 .nonblock = 0,
1377 .fd = fptr->fd,
1378
1379 .iov = iov,
1380 .iovcnt = iovcnt,
1381 .timeout = NULL
1382 };
1383
1384 struct timeval timeout_storage;
1385
1386 if (fptr->timeout != Qnil) {
1387 timeout_storage = rb_time_interval(fptr->timeout);
1388 iis.timeout = &timeout_storage;
1389 }
1390
1391 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1392}
1393#endif
1394
1395static VALUE
1396io_flush_buffer_sync(void *arg)
1397{
1398 rb_io_t *fptr = arg;
1399 long l = fptr->wbuf.len;
1400 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1401
1402 if (fptr->wbuf.len <= r) {
1403 fptr->wbuf.off = 0;
1404 fptr->wbuf.len = 0;
1405 return 0;
1406 }
1407
1408 if (0 <= r) {
1409 fptr->wbuf.off += (int)r;
1410 fptr->wbuf.len -= (int)r;
1411 errno = EAGAIN;
1412 }
1413
1414 return (VALUE)-1;
1415}
1416
1417static VALUE
1418io_flush_buffer_async(VALUE arg)
1419{
1420 rb_io_t *fptr = (rb_io_t *)arg;
1421 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1422}
1423
1424static inline int
1425io_flush_buffer(rb_io_t *fptr)
1426{
1427 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1428 return (int)io_flush_buffer_async((VALUE)fptr);
1429 }
1430 else {
1431 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1432 }
1433}
1434
1435static int
1436io_fflush(rb_io_t *fptr)
1437{
1438 rb_io_check_closed(fptr);
1439
1440 if (fptr->wbuf.len == 0)
1441 return 0;
1442
1443 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1444 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1445 return -1;
1446
1447 rb_io_check_closed(fptr);
1448 }
1449
1450 return 0;
1451}
1452
1453VALUE
1454rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1455{
1456 VALUE scheduler = rb_fiber_scheduler_current();
1457
1458 if (scheduler != Qnil) {
1459 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1460 }
1461
1462 rb_io_t * fptr = NULL;
1463 RB_IO_POINTER(io, fptr);
1464
1465 struct timeval tv_storage;
1466 struct timeval *tv = NULL;
1467
1468 if (NIL_OR_UNDEF_P(timeout)) {
1469 timeout = fptr->timeout;
1470 }
1471
1472 if (timeout != Qnil) {
1473 tv_storage = rb_time_interval(timeout);
1474 tv = &tv_storage;
1475 }
1476
1477 int ready = rb_thread_io_wait(fptr, RB_NUM2INT(events), tv);
1478
1479 if (ready < 0) {
1480 rb_sys_fail(0);
1481 }
1482
1483 // Not sure if this is necessary:
1484 rb_io_check_closed(fptr);
1485
1486 if (ready) {
1487 return RB_INT2NUM(ready);
1488 }
1489 else {
1490 return Qfalse;
1491 }
1492}
1493
1494static VALUE
1495io_from_fd(int fd)
1496{
1497 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1498}
1499
1500static int
1501io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1502{
1503 VALUE scheduler = rb_fiber_scheduler_current();
1504
1505 if (scheduler != Qnil) {
1506 return RTEST(
1507 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1508 );
1509 }
1510
1511 return rb_thread_wait_for_single_fd(fd, events, timeout);
1512}
1513
1514int
1516{
1517 io_fd_check_closed(f);
1518
1519 VALUE scheduler = rb_fiber_scheduler_current();
1520
1521 switch (errno) {
1522 case EINTR:
1523#if defined(ERESTART)
1524 case ERESTART:
1525#endif
1527 return TRUE;
1528
1529 case EAGAIN:
1530#if EWOULDBLOCK != EAGAIN
1531 case EWOULDBLOCK:
1532#endif
1533 if (scheduler != Qnil) {
1534 return RTEST(
1535 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1536 );
1537 }
1538 else {
1539 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1540 }
1541 return TRUE;
1542
1543 default:
1544 return FALSE;
1545 }
1546}
1547
1548int
1550{
1551 io_fd_check_closed(f);
1552
1553 VALUE scheduler = rb_fiber_scheduler_current();
1554
1555 switch (errno) {
1556 case EINTR:
1557#if defined(ERESTART)
1558 case ERESTART:
1559#endif
1560 /*
1561 * In old Linux, several special files under /proc and /sys don't handle
1562 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1563 * Otherwise, we face nasty hang up. Sigh.
1564 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1565 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1566 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1567 * Then rb_thread_check_ints() is enough.
1568 */
1570 return TRUE;
1571
1572 case EAGAIN:
1573#if EWOULDBLOCK != EAGAIN
1574 case EWOULDBLOCK:
1575#endif
1576 if (scheduler != Qnil) {
1577 return RTEST(
1578 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1579 );
1580 }
1581 else {
1582 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1583 }
1584 return TRUE;
1585
1586 default:
1587 return FALSE;
1588 }
1589}
1590
1591int
1592rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1593{
1594 return io_wait_for_single_fd(fd, events, timeout);
1595}
1596
1597int
1599{
1600 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1601}
1602
1603int
1605{
1606 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1607}
1608
1609VALUE
1610rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1611{
1612 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1613 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1614 // instead relies on `read(-1) -> -1` which causes this code path. We then
1615 // check here whether the IO was in fact closed. Probably it's better to
1616 // check that `fptr->fd != -1` before using it in syscall.
1617 rb_io_check_closed(RFILE(io)->fptr);
1618
1619 switch (error) {
1620 // In old Linux, several special files under /proc and /sys don't handle
1621 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1622 // Otherwise, we face nasty hang up. Sigh.
1623 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1624 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1625 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1626 // Then rb_thread_check_ints() is enough.
1627 case EINTR:
1628#if defined(ERESTART)
1629 case ERESTART:
1630#endif
1631 // We might have pending interrupts since the previous syscall was interrupted:
1633
1634 // The operation was interrupted, so retry it immediately:
1635 return events;
1636
1637 case EAGAIN:
1638#if EWOULDBLOCK != EAGAIN
1639 case EWOULDBLOCK:
1640#endif
1641 // The operation would block, so wait for the specified events:
1642 return rb_io_wait(io, events, timeout);
1643
1644 default:
1645 // Non-specific error, no event is ready:
1646 return Qnil;
1647 }
1648}
1649
1650int
1652{
1653 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1654
1655 if (RTEST(result)) {
1656 return RB_NUM2INT(result);
1657 }
1658 else if (result == RUBY_Qfalse) {
1659 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1660 }
1661
1662 return 0;
1663}
1664
1665int
1667{
1668 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1669
1670 if (RTEST(result)) {
1671 return RB_NUM2INT(result);
1672 }
1673 else if (result == RUBY_Qfalse) {
1674 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1675 }
1676
1677 return 0;
1678}
1679
1680static void
1681make_writeconv(rb_io_t *fptr)
1682{
1683 if (!fptr->writeconv_initialized) {
1684 const char *senc, *denc;
1685 rb_encoding *enc;
1686 int ecflags;
1687 VALUE ecopts;
1688
1689 fptr->writeconv_initialized = 1;
1690
1691 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1692 ecopts = fptr->encs.ecopts;
1693
1694 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1695 /* no encoding conversion */
1696 fptr->writeconv_pre_ecflags = 0;
1697 fptr->writeconv_pre_ecopts = Qnil;
1698 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1699 if (!fptr->writeconv)
1700 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1702 }
1703 else {
1704 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1705 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1706 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1707 /* single conversion */
1708 fptr->writeconv_pre_ecflags = ecflags;
1709 fptr->writeconv_pre_ecopts = ecopts;
1710 fptr->writeconv = NULL;
1712 }
1713 else {
1714 /* double conversion */
1715 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1716 fptr->writeconv_pre_ecopts = ecopts;
1717 if (senc) {
1718 denc = rb_enc_name(enc);
1719 fptr->writeconv_asciicompat = rb_str_new2(senc);
1720 }
1721 else {
1722 senc = denc = "";
1723 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1724 }
1726 ecopts = fptr->encs.ecopts;
1727 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1728 if (!fptr->writeconv)
1729 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1730 }
1731 }
1732 }
1733}
1734
1735/* writing functions */
1737 rb_io_t *fptr;
1738 const char *ptr;
1739 long length;
1740};
1741
1743 VALUE io;
1744 VALUE str;
1745 int nosync;
1746};
1747
1748#ifdef HAVE_WRITEV
1749static ssize_t
1750io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1751{
1752 if (fptr->wbuf.len) {
1753 struct iovec iov[2];
1754
1755 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1756 iov[0].iov_len = fptr->wbuf.len;
1757 iov[1].iov_base = (void*)ptr;
1758 iov[1].iov_len = length;
1759
1760 ssize_t result = rb_writev_internal(fptr, iov, 2);
1761
1762 if (result < 0)
1763 return result;
1764
1765 if (result >= fptr->wbuf.len) {
1766 // We wrote more than the internal buffer:
1767 result -= fptr->wbuf.len;
1768 fptr->wbuf.off = 0;
1769 fptr->wbuf.len = 0;
1770 }
1771 else {
1772 // We only wrote less data than the internal buffer:
1773 fptr->wbuf.off += (int)result;
1774 fptr->wbuf.len -= (int)result;
1775
1776 result = 0;
1777 }
1778
1779 return result;
1780 }
1781 else {
1782 return rb_io_write_memory(fptr, ptr, length);
1783 }
1784}
1785#else
1786static ssize_t
1787io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1788{
1789 long remaining = length;
1790
1791 if (fptr->wbuf.len) {
1792 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1793 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1794 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1795 fptr->wbuf.off = 0;
1796 }
1797
1798 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1799 fptr->wbuf.len += (int)length;
1800
1801 // We copied the entire incoming data to the internal buffer:
1802 remaining = 0;
1803 }
1804
1805 // Flush the internal buffer:
1806 if (io_fflush(fptr) < 0) {
1807 return -1;
1808 }
1809
1810 // If all the data was buffered, we are done:
1811 if (remaining == 0) {
1812 return length;
1813 }
1814 }
1815
1816 // Otherwise, we should write the data directly:
1817 return rb_io_write_memory(fptr, ptr, length);
1818}
1819#endif
1820
1821static VALUE
1822io_binwrite_string(VALUE arg)
1823{
1824 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1825
1826 const char *ptr = p->ptr;
1827 size_t remaining = p->length;
1828
1829 while (remaining) {
1830 // Write as much as possible:
1831 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1832
1833 if (result == 0) {
1834 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1835 // should try again immediately.
1836 }
1837 else if (result > 0) {
1838 if ((size_t)result == remaining) break;
1839 ptr += result;
1840 remaining -= result;
1841 }
1842 // Wait for it to become writable:
1843 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1844 rb_io_check_closed(p->fptr);
1845 }
1846 else {
1847 // The error was unrelated to waiting for it to become writable, so we fail:
1848 return -1;
1849 }
1850 }
1851
1852 return p->length;
1853}
1854
1855inline static void
1856io_allocate_write_buffer(rb_io_t *fptr, int sync)
1857{
1858 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1859 fptr->wbuf.off = 0;
1860 fptr->wbuf.len = 0;
1861 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1862 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1863 }
1864
1865 if (NIL_P(fptr->write_lock)) {
1866 fptr->write_lock = rb_mutex_new();
1867 rb_mutex_allow_trap(fptr->write_lock, 1);
1868 }
1869}
1870
1871static inline int
1872io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1873{
1874 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1875 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1876 return 1;
1877
1878 // If the amount of data we want to write exceeds the internal buffer:
1879 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1880 return 1;
1881
1882 // Otherwise, we can append to the internal buffer:
1883 return 0;
1884}
1885
1886static long
1887io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1888{
1889 if (len <= 0) return len;
1890
1891 // Don't write anything if current thread has a pending interrupt:
1893
1894 io_allocate_write_buffer(fptr, !nosync);
1895
1896 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1897 struct binwrite_arg arg;
1898
1899 arg.fptr = fptr;
1900 arg.ptr = ptr;
1901 arg.length = len;
1902
1903 if (!NIL_P(fptr->write_lock)) {
1904 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1905 }
1906 else {
1907 return io_binwrite_string((VALUE)&arg);
1908 }
1909 }
1910 else {
1911 if (fptr->wbuf.off) {
1912 if (fptr->wbuf.len)
1913 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1914 fptr->wbuf.off = 0;
1915 }
1916
1917 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1918 fptr->wbuf.len += (int)len;
1919
1920 return len;
1921 }
1922}
1923
1924# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1925 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1926
1927#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1928 MODE_BTMODE(d, e, f) : \
1929 MODE_BTMODE(a, b, c))
1930
1931static VALUE
1932do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1933{
1934 if (NEED_WRITECONV(fptr)) {
1935 VALUE common_encoding = Qnil;
1936 SET_BINARY_MODE(fptr);
1937
1938 make_writeconv(fptr);
1939
1940 if (fptr->writeconv) {
1941#define fmode (fptr->mode)
1942 if (!NIL_P(fptr->writeconv_asciicompat))
1943 common_encoding = fptr->writeconv_asciicompat;
1944 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1945 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1946 rb_enc_name(rb_enc_get(str)));
1947 }
1948#undef fmode
1949 }
1950 else {
1951 if (fptr->encs.enc2)
1952 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1953 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1954 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1955 }
1956
1957 if (!NIL_P(common_encoding)) {
1958 str = rb_str_encode(str, common_encoding,
1960 *converted = 1;
1961 }
1962
1963 if (fptr->writeconv) {
1965 *converted = 1;
1966 }
1967 }
1968#if RUBY_CRLF_ENVIRONMENT
1969#define fmode (fptr->mode)
1970 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1971 if ((fptr->mode & FMODE_READABLE) &&
1973 setmode(fptr->fd, O_BINARY);
1974 }
1975 else {
1976 setmode(fptr->fd, O_TEXT);
1977 }
1978 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1979 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1980 rb_enc_name(rb_enc_get(str)));
1981 }
1982 }
1983#undef fmode
1984#endif
1985 return str;
1986}
1987
1988static long
1989io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1990{
1991 int converted = 0;
1992 VALUE tmp;
1993 long n, len;
1994 const char *ptr;
1995
1996#ifdef _WIN32
1997 if (fptr->mode & FMODE_TTY) {
1998 long len = rb_w32_write_console(str, fptr->fd);
1999 if (len > 0) return len;
2000 }
2001#endif
2002
2003 str = do_writeconv(str, fptr, &converted);
2004 if (converted)
2005 OBJ_FREEZE(str);
2006
2007 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2008 RSTRING_GETMEM(tmp, ptr, len);
2009 n = io_binwrite(ptr, len, fptr, nosync);
2010 rb_str_tmp_frozen_release(str, tmp);
2011
2012 return n;
2013}
2014
2015ssize_t
2016rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2017{
2018 rb_io_t *fptr;
2019
2020 GetOpenFile(io, fptr);
2022 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2023}
2024
2025static VALUE
2026io_write(VALUE io, VALUE str, int nosync)
2027{
2028 rb_io_t *fptr;
2029 long n;
2030 VALUE tmp;
2031
2032 io = GetWriteIO(io);
2033 str = rb_obj_as_string(str);
2034 tmp = rb_io_check_io(io);
2035
2036 if (NIL_P(tmp)) {
2037 /* port is not IO, call write method for it. */
2038 return rb_funcall(io, id_write, 1, str);
2039 }
2040
2041 io = tmp;
2042 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2043
2044 GetOpenFile(io, fptr);
2046
2047 n = io_fwrite(str, fptr, nosync);
2048 if (n < 0L) rb_sys_fail_on_write(fptr);
2049
2050 return LONG2FIX(n);
2051}
2052
2053#ifdef HAVE_WRITEV
2054struct binwritev_arg {
2055 rb_io_t *fptr;
2056 struct iovec *iov;
2057 int iovcnt;
2058 size_t total;
2059};
2060
2061static VALUE
2062io_binwritev_internal(VALUE arg)
2063{
2064 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2065
2066 size_t remaining = p->total;
2067 size_t offset = 0;
2068
2069 rb_io_t *fptr = p->fptr;
2070 struct iovec *iov = p->iov;
2071 int iovcnt = p->iovcnt;
2072
2073 while (remaining) {
2074 long result = rb_writev_internal(fptr, iov, iovcnt);
2075
2076 if (result >= 0) {
2077 offset += result;
2078 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2079 if (offset < (size_t)fptr->wbuf.len) {
2080 fptr->wbuf.off += result;
2081 fptr->wbuf.len -= result;
2082 }
2083 else {
2084 offset -= (size_t)fptr->wbuf.len;
2085 fptr->wbuf.off = 0;
2086 fptr->wbuf.len = 0;
2087 }
2088 }
2089
2090 if (offset == p->total) {
2091 return p->total;
2092 }
2093
2094 while (result >= (ssize_t)iov->iov_len) {
2095 /* iovcnt > 0 */
2096 result -= iov->iov_len;
2097 iov->iov_len = 0;
2098 iov++;
2099
2100 if (!--iovcnt) {
2101 // I don't believe this code path can ever occur.
2102 return offset;
2103 }
2104 }
2105
2106 iov->iov_base = (char *)iov->iov_base + result;
2107 iov->iov_len -= result;
2108 }
2109 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2110 rb_io_check_closed(fptr);
2111 }
2112 else {
2113 return -1;
2114 }
2115 }
2116
2117 return offset;
2118}
2119
2120static long
2121io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2122{
2123 // Don't write anything if current thread has a pending interrupt:
2125
2126 if (iovcnt == 0) return 0;
2127
2128 size_t total = 0;
2129 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2130
2131 io_allocate_write_buffer(fptr, 1);
2132
2133 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2134 // The end of the buffered data:
2135 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2136
2137 if (offset + total <= (size_t)fptr->wbuf.capa) {
2138 for (int i = 1; i < iovcnt; i++) {
2139 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2140 offset += iov[i].iov_len;
2141 }
2142
2143 fptr->wbuf.len += total;
2144
2145 return total;
2146 }
2147 else {
2148 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2149 iov[0].iov_len = fptr->wbuf.len;
2150 }
2151 }
2152 else {
2153 // The first iov is reserved for the internal buffer, and it's empty.
2154 iov++;
2155
2156 if (!--iovcnt) {
2157 // If there are no other io vectors we are done.
2158 return 0;
2159 }
2160 }
2161
2162 struct binwritev_arg arg;
2163 arg.fptr = fptr;
2164 arg.iov = iov;
2165 arg.iovcnt = iovcnt;
2166 arg.total = total;
2167
2168 if (!NIL_P(fptr->write_lock)) {
2169 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2170 }
2171 else {
2172 return io_binwritev_internal((VALUE)&arg);
2173 }
2174}
2175
2176static long
2177io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2178{
2179 int i, converted, iovcnt = argc + 1;
2180 long n;
2181 VALUE v1, v2, str, tmp, *tmp_array;
2182 struct iovec *iov;
2183
2184 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2185 tmp_array = ALLOCV_N(VALUE, v2, argc);
2186
2187 for (i = 0; i < argc; i++) {
2188 str = rb_obj_as_string(argv[i]);
2189 converted = 0;
2190 str = do_writeconv(str, fptr, &converted);
2191
2192 if (converted)
2193 OBJ_FREEZE(str);
2194
2195 tmp = rb_str_tmp_frozen_acquire(str);
2196 tmp_array[i] = tmp;
2197
2198 /* iov[0] is reserved for buffer of fptr */
2199 iov[i+1].iov_base = RSTRING_PTR(tmp);
2200 iov[i+1].iov_len = RSTRING_LEN(tmp);
2201 }
2202
2203 n = io_binwritev(iov, iovcnt, fptr);
2204 if (v1) ALLOCV_END(v1);
2205
2206 for (i = 0; i < argc; i++) {
2207 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2208 }
2209
2210 if (v2) ALLOCV_END(v2);
2211
2212 return n;
2213}
2214
2215static int
2216iovcnt_ok(int iovcnt)
2217{
2218#ifdef IOV_MAX
2219 return iovcnt < IOV_MAX;
2220#else /* GNU/Hurd has writev, but no IOV_MAX */
2221 return 1;
2222#endif
2223}
2224#endif /* HAVE_WRITEV */
2225
2226static VALUE
2227io_writev(int argc, const VALUE *argv, VALUE io)
2228{
2229 rb_io_t *fptr;
2230 long n;
2231 VALUE tmp, total = INT2FIX(0);
2232 int i, cnt = 1;
2233
2234 io = GetWriteIO(io);
2235 tmp = rb_io_check_io(io);
2236
2237 if (NIL_P(tmp)) {
2238 /* port is not IO, call write method for it. */
2239 return rb_funcallv(io, id_write, argc, argv);
2240 }
2241
2242 io = tmp;
2243
2244 GetOpenFile(io, fptr);
2246
2247 for (i = 0; i < argc; i += cnt) {
2248#ifdef HAVE_WRITEV
2249 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2250 n = io_fwritev(cnt, &argv[i], fptr);
2251 }
2252 else
2253#endif
2254 {
2255 cnt = 1;
2256 /* sync at last item */
2257 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2258 }
2259
2260 if (n < 0L)
2261 rb_sys_fail_on_write(fptr);
2262
2263 total = rb_fix_plus(LONG2FIX(n), total);
2264 }
2265
2266 return total;
2267}
2268
2269/*
2270 * call-seq:
2271 * write(*objects) -> integer
2272 *
2273 * Writes each of the given +objects+ to +self+,
2274 * which must be opened for writing
2275 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2276 * returns the total number bytes written;
2277 * each of +objects+ that is not a string is converted via method +to_s+:
2278 *
2279 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2280 * $stdout.write('foo', :bar, 2, "\n") # => 8
2281 *
2282 * Output:
2283 *
2284 * Hello, World!
2285 * foobar2
2286 *
2287 * Related: IO#read.
2288 */
2289
2290static VALUE
2291io_write_m(int argc, VALUE *argv, VALUE io)
2292{
2293 if (argc != 1) {
2294 return io_writev(argc, argv, io);
2295 }
2296 else {
2297 VALUE str = argv[0];
2298 return io_write(io, str, 0);
2299 }
2300}
2301
2302VALUE
2303rb_io_write(VALUE io, VALUE str)
2304{
2305 return rb_funcallv(io, id_write, 1, &str);
2306}
2307
2308static VALUE
2309rb_io_writev(VALUE io, int argc, const VALUE *argv)
2310{
2311 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2312 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2313 VALUE klass = CLASS_OF(io);
2314 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2316 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2317 " which accepts just one argument",
2318 klass, sep
2319 );
2320 }
2321
2322 do rb_io_write(io, *argv++); while (--argc);
2323
2324 return Qnil;
2325 }
2326
2327 return rb_funcallv(io, id_write, argc, argv);
2328}
2329
2330/*
2331 * call-seq:
2332 * self << object -> self
2333 *
2334 * Writes the given +object+ to +self+,
2335 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2336 * returns +self+;
2337 * if +object+ is not a string, it is converted via method +to_s+:
2338 *
2339 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2340 * $stdout << 'foo' << :bar << 2 << "\n"
2341 *
2342 * Output:
2343 *
2344 * Hello, World!
2345 * foobar2
2346 *
2347 */
2348
2349
2350VALUE
2352{
2353 rb_io_write(io, str);
2354 return io;
2355}
2356
2357#ifdef HAVE_FSYNC
2358static VALUE
2359nogvl_fsync(void *ptr)
2360{
2361 rb_io_t *fptr = ptr;
2362
2363#ifdef _WIN32
2364 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2365 return 0;
2366#endif
2367 return (VALUE)fsync(fptr->fd);
2368}
2369#endif
2370
2371VALUE
2372rb_io_flush_raw(VALUE io, int sync)
2373{
2374 rb_io_t *fptr;
2375
2376 if (!RB_TYPE_P(io, T_FILE)) {
2377 return rb_funcall(io, id_flush, 0);
2378 }
2379
2380 io = GetWriteIO(io);
2381 GetOpenFile(io, fptr);
2382
2383 if (fptr->mode & FMODE_WRITABLE) {
2384 if (io_fflush(fptr) < 0)
2385 rb_sys_fail_on_write(fptr);
2386 }
2387 if (fptr->mode & FMODE_READABLE) {
2388 io_unread(fptr, true);
2389 }
2390
2391 return io;
2392}
2393
2394/*
2395 * call-seq:
2396 * flush -> self
2397 *
2398 * Flushes data buffered in +self+ to the operating system
2399 * (but does not necessarily flush data buffered in the operating system):
2400 *
2401 * $stdout.print 'no newline' # Not necessarily flushed.
2402 * $stdout.flush # Flushed.
2403 *
2404 */
2405
2406VALUE
2407rb_io_flush(VALUE io)
2408{
2409 return rb_io_flush_raw(io, 1);
2410}
2411
2412/*
2413 * call-seq:
2414 * tell -> integer
2415 *
2416 * Returns the current position (in bytes) in +self+
2417 * (see {Position}[rdoc-ref:IO@Position]):
2418 *
2419 * f = File.open('t.txt')
2420 * f.tell # => 0
2421 * f.gets # => "First line\n"
2422 * f.tell # => 12
2423 * f.close
2424 *
2425 * Related: IO#pos=, IO#seek.
2426 */
2427
2428static VALUE
2429rb_io_tell(VALUE io)
2430{
2431 rb_io_t *fptr;
2432 rb_off_t pos;
2433
2434 GetOpenFile(io, fptr);
2435 pos = io_tell(fptr);
2436 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2437 pos -= fptr->rbuf.len;
2438 return OFFT2NUM(pos);
2439}
2440
2441static VALUE
2442rb_io_seek(VALUE io, VALUE offset, int whence)
2443{
2444 rb_io_t *fptr;
2445 rb_off_t pos;
2446
2447 pos = NUM2OFFT(offset);
2448 GetOpenFile(io, fptr);
2449 pos = io_seek(fptr, pos, whence);
2450 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2451
2452 return INT2FIX(0);
2453}
2454
2455static int
2456interpret_seek_whence(VALUE vwhence)
2457{
2458 if (vwhence == sym_SET)
2459 return SEEK_SET;
2460 if (vwhence == sym_CUR)
2461 return SEEK_CUR;
2462 if (vwhence == sym_END)
2463 return SEEK_END;
2464#ifdef SEEK_DATA
2465 if (vwhence == sym_DATA)
2466 return SEEK_DATA;
2467#endif
2468#ifdef SEEK_HOLE
2469 if (vwhence == sym_HOLE)
2470 return SEEK_HOLE;
2471#endif
2472 return NUM2INT(vwhence);
2473}
2474
2475/*
2476 * call-seq:
2477 * seek(offset, whence = IO::SEEK_SET) -> 0
2478 *
2479 * Seeks to the position given by integer +offset+
2480 * (see {Position}[rdoc-ref:IO@Position])
2481 * and constant +whence+, which is one of:
2482 *
2483 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2484 * Repositions the stream to its current position plus the given +offset+:
2485 *
2486 * f = File.open('t.txt')
2487 * f.tell # => 0
2488 * f.seek(20, :CUR) # => 0
2489 * f.tell # => 20
2490 * f.seek(-10, :CUR) # => 0
2491 * f.tell # => 10
2492 * f.close
2493 *
2494 * - +:END+ or <tt>IO::SEEK_END</tt>:
2495 * Repositions the stream to its end plus the given +offset+:
2496 *
2497 * f = File.open('t.txt')
2498 * f.tell # => 0
2499 * f.seek(0, :END) # => 0 # Repositions to stream end.
2500 * f.tell # => 52
2501 * f.seek(-20, :END) # => 0
2502 * f.tell # => 32
2503 * f.seek(-40, :END) # => 0
2504 * f.tell # => 12
2505 * f.close
2506 *
2507 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2508 * Repositions the stream to the given +offset+:
2509 *
2510 * f = File.open('t.txt')
2511 * f.tell # => 0
2512 * f.seek(20, :SET) # => 0
2513 * f.tell # => 20
2514 * f.seek(40, :SET) # => 0
2515 * f.tell # => 40
2516 * f.close
2517 *
2518 * Related: IO#pos=, IO#tell.
2519 *
2520 */
2521
2522static VALUE
2523rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2524{
2525 VALUE offset, ptrname;
2526 int whence = SEEK_SET;
2527
2528 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2529 whence = interpret_seek_whence(ptrname);
2530 }
2531
2532 return rb_io_seek(io, offset, whence);
2533}
2534
2535/*
2536 * call-seq:
2537 * pos = new_position -> new_position
2538 *
2539 * Seeks to the given +new_position+ (in bytes);
2540 * see {Position}[rdoc-ref:IO@Position]:
2541 *
2542 * f = File.open('t.txt')
2543 * f.tell # => 0
2544 * f.pos = 20 # => 20
2545 * f.tell # => 20
2546 * f.close
2547 *
2548 * Related: IO#seek, IO#tell.
2549 *
2550 */
2551
2552static VALUE
2553rb_io_set_pos(VALUE io, VALUE offset)
2554{
2555 rb_io_t *fptr;
2556 rb_off_t pos;
2557
2558 pos = NUM2OFFT(offset);
2559 GetOpenFile(io, fptr);
2560 pos = io_seek(fptr, pos, SEEK_SET);
2561 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2562
2563 return OFFT2NUM(pos);
2564}
2565
2566static void clear_readconv(rb_io_t *fptr);
2567
2568/*
2569 * call-seq:
2570 * rewind -> 0
2571 *
2572 * Repositions the stream to its beginning,
2573 * setting both the position and the line number to zero;
2574 * see {Position}[rdoc-ref:IO@Position]
2575 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2576 *
2577 * f = File.open('t.txt')
2578 * f.tell # => 0
2579 * f.lineno # => 0
2580 * f.gets # => "First line\n"
2581 * f.tell # => 12
2582 * f.lineno # => 1
2583 * f.rewind # => 0
2584 * f.tell # => 0
2585 * f.lineno # => 0
2586 * f.close
2587 *
2588 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2589 *
2590 */
2591
2592static VALUE
2593rb_io_rewind(VALUE io)
2594{
2595 rb_io_t *fptr;
2596
2597 GetOpenFile(io, fptr);
2598 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2599 if (io == ARGF.current_file) {
2600 ARGF.lineno -= fptr->lineno;
2601 }
2602 fptr->lineno = 0;
2603 if (fptr->readconv) {
2604 clear_readconv(fptr);
2605 }
2606
2607 return INT2FIX(0);
2608}
2609
2610static int
2611fptr_wait_readable(rb_io_t *fptr)
2612{
2613 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2614
2615 if (result)
2616 rb_io_check_closed(fptr);
2617
2618 return result;
2619}
2620
2621static int
2622io_fillbuf(rb_io_t *fptr)
2623{
2624 ssize_t r;
2625
2626 if (fptr->rbuf.ptr == NULL) {
2627 fptr->rbuf.off = 0;
2628 fptr->rbuf.len = 0;
2629 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2630 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2631#ifdef _WIN32
2632 fptr->rbuf.capa--;
2633#endif
2634 }
2635 if (fptr->rbuf.len == 0) {
2636 retry:
2637 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2638
2639 if (r < 0) {
2640 if (fptr_wait_readable(fptr))
2641 goto retry;
2642
2643 int e = errno;
2644 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2645 if (!NIL_P(fptr->pathv)) {
2646 rb_str_append(path, fptr->pathv);
2647 }
2648
2649 rb_syserr_fail_path(e, path);
2650 }
2651 if (r > 0) rb_io_check_closed(fptr);
2652 fptr->rbuf.off = 0;
2653 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2654 if (r == 0)
2655 return -1; /* EOF */
2656 }
2657 return 0;
2658}
2659
2660/*
2661 * call-seq:
2662 * eof -> true or false
2663 *
2664 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2665 * see {Position}[rdoc-ref:IO@Position]:
2666 *
2667 * f = File.open('t.txt')
2668 * f.eof # => false
2669 * f.seek(0, :END) # => 0
2670 * f.eof # => true
2671 * f.close
2672 *
2673 * Raises an exception unless the stream is opened for reading;
2674 * see {Mode}[rdoc-ref:File@Access+Modes].
2675 *
2676 * If +self+ is a stream such as pipe or socket, this method
2677 * blocks until the other end sends some data or closes it:
2678 *
2679 * r, w = IO.pipe
2680 * Thread.new { sleep 1; w.close }
2681 * r.eof? # => true # After 1-second wait.
2682 *
2683 * r, w = IO.pipe
2684 * Thread.new { sleep 1; w.puts "a" }
2685 * r.eof? # => false # After 1-second wait.
2686 *
2687 * r, w = IO.pipe
2688 * r.eof? # blocks forever
2689 *
2690 * Note that this method reads data to the input byte buffer. So
2691 * IO#sysread may not behave as you intend with IO#eof?, unless you
2692 * call IO#rewind first (which is not available for some streams).
2693 */
2694
2695VALUE
2697{
2698 rb_io_t *fptr;
2699
2700 GetOpenFile(io, fptr);
2702
2703 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2704 if (READ_DATA_PENDING(fptr)) return Qfalse;
2705 READ_CHECK(fptr);
2706#if RUBY_CRLF_ENVIRONMENT
2707 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2708 return RBOOL(eof(fptr->fd));
2709 }
2710#endif
2711 return RBOOL(io_fillbuf(fptr) < 0);
2712}
2713
2714/*
2715 * call-seq:
2716 * sync -> true or false
2717 *
2718 * Returns the current sync mode of the stream.
2719 * When sync mode is true, all output is immediately flushed to the underlying
2720 * operating system and is not buffered by Ruby internally. See also #fsync.
2721 *
2722 * f = File.open('t.tmp', 'w')
2723 * f.sync # => false
2724 * f.sync = true
2725 * f.sync # => true
2726 * f.close
2727 *
2728 */
2729
2730static VALUE
2731rb_io_sync(VALUE io)
2732{
2733 rb_io_t *fptr;
2734
2735 io = GetWriteIO(io);
2736 GetOpenFile(io, fptr);
2737 return RBOOL(fptr->mode & FMODE_SYNC);
2738}
2739
2740#ifdef HAVE_FSYNC
2741
2742/*
2743 * call-seq:
2744 * sync = boolean -> boolean
2745 *
2746 * Sets the _sync_ _mode_ for the stream to the given value;
2747 * returns the given value.
2748 *
2749 * Values for the sync mode:
2750 *
2751 * - +true+: All output is immediately flushed to the
2752 * underlying operating system and is not buffered internally.
2753 * - +false+: Output may be buffered internally.
2754 *
2755 * Example;
2756 *
2757 * f = File.open('t.tmp', 'w')
2758 * f.sync # => false
2759 * f.sync = true
2760 * f.sync # => true
2761 * f.close
2762 *
2763 * Related: IO#fsync.
2764 *
2765 */
2766
2767static VALUE
2768rb_io_set_sync(VALUE io, VALUE sync)
2769{
2770 rb_io_t *fptr;
2771
2772 io = GetWriteIO(io);
2773 GetOpenFile(io, fptr);
2774 if (RTEST(sync)) {
2775 fptr->mode |= FMODE_SYNC;
2776 }
2777 else {
2778 fptr->mode &= ~FMODE_SYNC;
2779 }
2780 return sync;
2781}
2782
2783/*
2784 * call-seq:
2785 * fsync -> 0
2786 *
2787 * Immediately writes to disk all data buffered in the stream,
2788 * via the operating system's <tt>fsync(2)</tt>.
2789
2790 * Note this difference:
2791 *
2792 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2793 * but does not guarantee that the operating system actually writes the data to disk.
2794 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2795 * and that data is written to disk.
2796 *
2797 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2798 *
2799 */
2800
2801static VALUE
2802rb_io_fsync(VALUE io)
2803{
2804 rb_io_t *fptr;
2805
2806 io = GetWriteIO(io);
2807 GetOpenFile(io, fptr);
2808
2809 if (io_fflush(fptr) < 0)
2810 rb_sys_fail_on_write(fptr);
2811
2812 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2813 rb_sys_fail_path(fptr->pathv);
2814
2815 return INT2FIX(0);
2816}
2817#else
2818# define rb_io_fsync rb_f_notimplement
2819# define rb_io_sync rb_f_notimplement
2820static VALUE
2821rb_io_set_sync(VALUE io, VALUE sync)
2822{
2825}
2826#endif
2827
2828#ifdef HAVE_FDATASYNC
2829static VALUE
2830nogvl_fdatasync(void *ptr)
2831{
2832 rb_io_t *fptr = ptr;
2833
2834#ifdef _WIN32
2835 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2836 return 0;
2837#endif
2838 return (VALUE)fdatasync(fptr->fd);
2839}
2840
2841/*
2842 * call-seq:
2843 * fdatasync -> 0
2844 *
2845 * Immediately writes to disk all data buffered in the stream,
2846 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2847 * otherwise via <tt>fsync(2)</tt>, if supported;
2848 * otherwise raises an exception.
2849 *
2850 */
2851
2852static VALUE
2853rb_io_fdatasync(VALUE io)
2854{
2855 rb_io_t *fptr;
2856
2857 io = GetWriteIO(io);
2858 GetOpenFile(io, fptr);
2859
2860 if (io_fflush(fptr) < 0)
2861 rb_sys_fail_on_write(fptr);
2862
2863 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2864 return INT2FIX(0);
2865
2866 /* fall back */
2867 return rb_io_fsync(io);
2868}
2869#else
2870#define rb_io_fdatasync rb_io_fsync
2871#endif
2872
2873/*
2874 * call-seq:
2875 * fileno -> integer
2876 *
2877 * Returns the integer file descriptor for the stream:
2878 *
2879 * $stdin.fileno # => 0
2880 * $stdout.fileno # => 1
2881 * $stderr.fileno # => 2
2882 * File.open('t.txt').fileno # => 10
2883 * f.close
2884 *
2885 */
2886
2887static VALUE
2888rb_io_fileno(VALUE io)
2889{
2890 rb_io_t *fptr = RFILE(io)->fptr;
2891 int fd;
2892
2893 rb_io_check_closed(fptr);
2894 fd = fptr->fd;
2895 return INT2FIX(fd);
2896}
2897
2898int
2900{
2901 if (RB_TYPE_P(io, T_FILE)) {
2902 rb_io_t *fptr = RFILE(io)->fptr;
2903 rb_io_check_closed(fptr);
2904 return fptr->fd;
2905 }
2906 else {
2907 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2908 if (!UNDEF_P(fileno)) {
2909 return RB_NUM2INT(fileno);
2910 }
2911 }
2912
2913 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2914
2916}
2917
2918int
2919rb_io_mode(VALUE io)
2920{
2921 rb_io_t *fptr;
2922 GetOpenFile(io, fptr);
2923 return fptr->mode;
2924}
2925
2926/*
2927 * call-seq:
2928 * pid -> integer or nil
2929 *
2930 * Returns the process ID of a child process associated with the stream,
2931 * which will have been set by IO#popen, or +nil+ if the stream was not
2932 * created by IO#popen:
2933 *
2934 * pipe = IO.popen("-")
2935 * if pipe
2936 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2937 * else
2938 * $stderr.puts "In child, pid is #{$$}"
2939 * end
2940 *
2941 * Output:
2942 *
2943 * In child, pid is 26209
2944 * In parent, child pid is 26209
2945 *
2946 */
2947
2948static VALUE
2949rb_io_pid(VALUE io)
2950{
2951 rb_io_t *fptr;
2952
2953 GetOpenFile(io, fptr);
2954 if (!fptr->pid)
2955 return Qnil;
2956 return PIDT2NUM(fptr->pid);
2957}
2958
2959/*
2960 * call-seq:
2961 * path -> string or nil
2962 *
2963 * Returns the path associated with the IO, or +nil+ if there is no path
2964 * associated with the IO. It is not guaranteed that the path exists on
2965 * the filesystem.
2966 *
2967 * $stdin.path # => "<STDIN>"
2968 *
2969 * File.open("testfile") {|f| f.path} # => "testfile"
2970 */
2971
2972VALUE
2974{
2975 rb_io_t *fptr = RFILE(io)->fptr;
2976
2977 if (!fptr)
2978 return Qnil;
2979
2980 return rb_obj_dup(fptr->pathv);
2981}
2982
2983/*
2984 * call-seq:
2985 * inspect -> string
2986 *
2987 * Returns a string representation of +self+:
2988 *
2989 * f = File.open('t.txt')
2990 * f.inspect # => "#<File:t.txt>"
2991 * f.close
2992 *
2993 */
2994
2995static VALUE
2996rb_io_inspect(VALUE obj)
2997{
2998 rb_io_t *fptr;
2999 VALUE result;
3000 static const char closed[] = " (closed)";
3001
3002 fptr = RFILE(obj)->fptr;
3003 if (!fptr) return rb_any_to_s(obj);
3004 result = rb_str_new_cstr("#<");
3005 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3006 rb_str_cat2(result, ":");
3007 if (NIL_P(fptr->pathv)) {
3008 if (fptr->fd < 0) {
3009 rb_str_cat(result, closed+1, strlen(closed)-1);
3010 }
3011 else {
3012 rb_str_catf(result, "fd %d", fptr->fd);
3013 }
3014 }
3015 else {
3016 rb_str_append(result, fptr->pathv);
3017 if (fptr->fd < 0) {
3018 rb_str_cat(result, closed, strlen(closed));
3019 }
3020 }
3021 return rb_str_cat2(result, ">");
3022}
3023
3024/*
3025 * call-seq:
3026 * to_io -> self
3027 *
3028 * Returns +self+.
3029 *
3030 */
3031
3032static VALUE
3033rb_io_to_io(VALUE io)
3034{
3035 return io;
3036}
3037
3038/* reading functions */
3039static long
3040read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3041{
3042 int n;
3043
3044 n = READ_DATA_PENDING_COUNT(fptr);
3045 if (n <= 0) return 0;
3046 if (n > len) n = (int)len;
3047 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3048 fptr->rbuf.off += n;
3049 fptr->rbuf.len -= n;
3050 return n;
3051}
3052
3053static long
3054io_bufread(char *ptr, long len, rb_io_t *fptr)
3055{
3056 long offset = 0;
3057 long n = len;
3058 long c;
3059
3060 if (READ_DATA_PENDING(fptr) == 0) {
3061 while (n > 0) {
3062 again:
3063 rb_io_check_closed(fptr);
3064 c = rb_io_read_memory(fptr, ptr+offset, n);
3065 if (c == 0) break;
3066 if (c < 0) {
3067 if (fptr_wait_readable(fptr))
3068 goto again;
3069 return -1;
3070 }
3071 offset += c;
3072 if ((n -= c) <= 0) break;
3073 }
3074 return len - n;
3075 }
3076
3077 while (n > 0) {
3078 c = read_buffered_data(ptr+offset, n, fptr);
3079 if (c > 0) {
3080 offset += c;
3081 if ((n -= c) <= 0) break;
3082 }
3083 rb_io_check_closed(fptr);
3084 if (io_fillbuf(fptr) < 0) {
3085 break;
3086 }
3087 }
3088 return len - n;
3089}
3090
3091static int io_setstrbuf(VALUE *str, long len);
3092
3094 char *str_ptr;
3095 long len;
3096 rb_io_t *fptr;
3097};
3098
3099static VALUE
3100bufread_call(VALUE arg)
3101{
3102 struct bufread_arg *p = (struct bufread_arg *)arg;
3103 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3104 return Qundef;
3105}
3106
3107static long
3108io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3109{
3110 long len;
3111 struct bufread_arg arg;
3112
3113 io_setstrbuf(&str, offset + size);
3114 arg.str_ptr = RSTRING_PTR(str) + offset;
3115 arg.len = size;
3116 arg.fptr = fptr;
3117 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3118 len = arg.len;
3119 if (len < 0) rb_sys_fail_path(fptr->pathv);
3120 return len;
3121}
3122
3123static long
3124remain_size(rb_io_t *fptr)
3125{
3126 struct stat st;
3127 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3128 rb_off_t pos;
3129
3130 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3131#if defined(__HAIKU__)
3132 && (st.st_dev > 3)
3133#endif
3134 )
3135 {
3136 if (io_fflush(fptr) < 0)
3137 rb_sys_fail_on_write(fptr);
3138 pos = lseek(fptr->fd, 0, SEEK_CUR);
3139 if (st.st_size >= pos && pos >= 0) {
3140 siz += st.st_size - pos;
3141 if (siz > LONG_MAX) {
3142 rb_raise(rb_eIOError, "file too big for single read");
3143 }
3144 }
3145 }
3146 else {
3147 siz += BUFSIZ;
3148 }
3149 return (long)siz;
3150}
3151
3152static VALUE
3153io_enc_str(VALUE str, rb_io_t *fptr)
3154{
3155 rb_enc_associate(str, io_read_encoding(fptr));
3156 return str;
3157}
3158
3159static rb_encoding *io_read_encoding(rb_io_t *fptr);
3160
3161static void
3162make_readconv(rb_io_t *fptr, int size)
3163{
3164 if (!fptr->readconv) {
3165 int ecflags;
3166 VALUE ecopts;
3167 const char *sname, *dname;
3168 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3169 ecopts = fptr->encs.ecopts;
3170 if (fptr->encs.enc2) {
3171 sname = rb_enc_name(fptr->encs.enc2);
3172 dname = rb_enc_name(io_read_encoding(fptr));
3173 }
3174 else {
3175 sname = dname = "";
3176 }
3177 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3178 if (!fptr->readconv)
3179 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3180 fptr->cbuf.off = 0;
3181 fptr->cbuf.len = 0;
3182 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3183 fptr->cbuf.capa = size;
3184 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3185 }
3186}
3187
3188#define MORE_CHAR_SUSPENDED Qtrue
3189#define MORE_CHAR_FINISHED Qnil
3190static VALUE
3191fill_cbuf(rb_io_t *fptr, int ec_flags)
3192{
3193 const unsigned char *ss, *sp, *se;
3194 unsigned char *ds, *dp, *de;
3196 int putbackable;
3197 int cbuf_len0;
3198 VALUE exc;
3199
3200 ec_flags |= ECONV_PARTIAL_INPUT;
3201
3202 if (fptr->cbuf.len == fptr->cbuf.capa)
3203 return MORE_CHAR_SUSPENDED; /* cbuf full */
3204 if (fptr->cbuf.len == 0)
3205 fptr->cbuf.off = 0;
3206 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3207 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3208 fptr->cbuf.off = 0;
3209 }
3210
3211 cbuf_len0 = fptr->cbuf.len;
3212
3213 while (1) {
3214 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3215 se = sp + fptr->rbuf.len;
3216 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3217 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3218 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3219 fptr->rbuf.off += (int)(sp - ss);
3220 fptr->rbuf.len -= (int)(sp - ss);
3221 fptr->cbuf.len += (int)(dp - ds);
3222
3223 putbackable = rb_econv_putbackable(fptr->readconv);
3224 if (putbackable) {
3225 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3226 fptr->rbuf.off -= putbackable;
3227 fptr->rbuf.len += putbackable;
3228 }
3229
3230 exc = rb_econv_make_exception(fptr->readconv);
3231 if (!NIL_P(exc))
3232 return exc;
3233
3234 if (cbuf_len0 != fptr->cbuf.len)
3235 return MORE_CHAR_SUSPENDED;
3236
3237 if (res == econv_finished) {
3238 return MORE_CHAR_FINISHED;
3239 }
3240
3241 if (res == econv_source_buffer_empty) {
3242 if (fptr->rbuf.len == 0) {
3243 READ_CHECK(fptr);
3244 if (io_fillbuf(fptr) < 0) {
3245 if (!fptr->readconv) {
3246 return MORE_CHAR_FINISHED;
3247 }
3248 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3249 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3250 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3251 fptr->cbuf.len += (int)(dp - ds);
3253 break;
3254 }
3255 }
3256 }
3257 }
3258 if (cbuf_len0 != fptr->cbuf.len)
3259 return MORE_CHAR_SUSPENDED;
3260
3261 return MORE_CHAR_FINISHED;
3262}
3263
3264static VALUE
3265more_char(rb_io_t *fptr)
3266{
3267 VALUE v;
3268 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3269 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3270 rb_exc_raise(v);
3271 return v;
3272}
3273
3274static VALUE
3275io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3276{
3277 VALUE str = Qnil;
3278 if (strp) {
3279 str = *strp;
3280 if (NIL_P(str)) {
3281 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3282 }
3283 else {
3284 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3285 }
3286 rb_enc_associate(str, fptr->encs.enc);
3287 }
3288 fptr->cbuf.off += len;
3289 fptr->cbuf.len -= len;
3290 /* xxx: set coderange */
3291 if (fptr->cbuf.len == 0)
3292 fptr->cbuf.off = 0;
3293 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3294 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3295 fptr->cbuf.off = 0;
3296 }
3297 return str;
3298}
3299
3300static int
3301io_setstrbuf(VALUE *str, long len)
3302{
3303#ifdef _WIN32
3304 if (len > 0)
3305 len = (len + 1) & ~1L; /* round up for wide char */
3306#endif
3307 if (NIL_P(*str)) {
3308 *str = rb_str_new(0, len);
3309 return TRUE;
3310 }
3311 else {
3312 VALUE s = StringValue(*str);
3313 rb_str_modify(s);
3314
3315 long clen = RSTRING_LEN(s);
3316 if (clen >= len) {
3317 return FALSE;
3318 }
3319 len -= clen;
3320 }
3321 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3323 }
3324 return FALSE;
3325}
3326
3327#define MAX_REALLOC_GAP 4096
3328static void
3329io_shrink_read_string(VALUE str, long n)
3330{
3331 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3332 rb_str_resize(str, n);
3333 }
3334}
3335
3336static void
3337io_set_read_length(VALUE str, long n, int shrinkable)
3338{
3339 if (RSTRING_LEN(str) != n) {
3340 rb_str_modify(str);
3341 rb_str_set_len(str, n);
3342 if (shrinkable) io_shrink_read_string(str, n);
3343 }
3344}
3345
3346static VALUE
3347read_all(rb_io_t *fptr, long siz, VALUE str)
3348{
3349 long bytes;
3350 long n;
3351 long pos;
3352 rb_encoding *enc;
3353 int cr;
3354 int shrinkable;
3355
3356 if (NEED_READCONV(fptr)) {
3357 int first = !NIL_P(str);
3358 SET_BINARY_MODE(fptr);
3359 shrinkable = io_setstrbuf(&str,0);
3360 make_readconv(fptr, 0);
3361 while (1) {
3362 VALUE v;
3363 if (fptr->cbuf.len) {
3364 if (first) rb_str_set_len(str, first = 0);
3365 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3366 }
3367 v = fill_cbuf(fptr, 0);
3368 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3369 if (fptr->cbuf.len) {
3370 if (first) rb_str_set_len(str, first = 0);
3371 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3372 }
3373 rb_exc_raise(v);
3374 }
3375 if (v == MORE_CHAR_FINISHED) {
3376 clear_readconv(fptr);
3377 if (first) rb_str_set_len(str, first = 0);
3378 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3379 return io_enc_str(str, fptr);
3380 }
3381 }
3382 }
3383
3384 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3385 bytes = 0;
3386 pos = 0;
3387
3388 enc = io_read_encoding(fptr);
3389 cr = 0;
3390
3391 if (siz == 0) siz = BUFSIZ;
3392 shrinkable = io_setstrbuf(&str, siz);
3393 for (;;) {
3394 READ_CHECK(fptr);
3395 n = io_fread(str, bytes, siz - bytes, fptr);
3396 if (n == 0 && bytes == 0) {
3397 rb_str_set_len(str, 0);
3398 break;
3399 }
3400 bytes += n;
3401 rb_str_set_len(str, bytes);
3402 if (cr != ENC_CODERANGE_BROKEN)
3403 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3404 if (bytes < siz) break;
3405 siz += BUFSIZ;
3406
3407 size_t capa = rb_str_capacity(str);
3408 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3409 if (capa < BUFSIZ) {
3410 capa = BUFSIZ;
3411 }
3412 else if (capa > IO_MAX_BUFFER_GROWTH) {
3413 capa = IO_MAX_BUFFER_GROWTH;
3414 }
3416 }
3417 }
3418 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3419 str = io_enc_str(str, fptr);
3420 ENC_CODERANGE_SET(str, cr);
3421 return str;
3422}
3423
3424void
3426{
3427 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3428 rb_sys_fail_path(fptr->pathv);
3429 }
3430}
3431
3432static VALUE
3433io_read_memory_call(VALUE arg)
3434{
3435 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3436
3437 VALUE scheduler = rb_fiber_scheduler_current();
3438 if (scheduler != Qnil) {
3439 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3440
3441 if (!UNDEF_P(result)) {
3442 // This is actually returned as a pseudo-VALUE and later cast to a long:
3444 }
3445 }
3446
3447 if (iis->nonblock) {
3448 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3449 }
3450 else {
3451 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3452 }
3453}
3454
3455static long
3456io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3457{
3458 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3459}
3460
3461#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3462
3463static VALUE
3464io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3465{
3466 rb_io_t *fptr;
3467 VALUE length, str;
3468 long n, len;
3469 struct io_internal_read_struct iis;
3470 int shrinkable;
3471
3472 rb_scan_args(argc, argv, "11", &length, &str);
3473
3474 if ((len = NUM2LONG(length)) < 0) {
3475 rb_raise(rb_eArgError, "negative length %ld given", len);
3476 }
3477
3478 shrinkable = io_setstrbuf(&str, len);
3479
3480 GetOpenFile(io, fptr);
3482
3483 if (len == 0) {
3484 io_set_read_length(str, 0, shrinkable);
3485 return str;
3486 }
3487
3488 if (!nonblock)
3489 READ_CHECK(fptr);
3490 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3491 if (n <= 0) {
3492 again:
3493 if (nonblock) {
3494 rb_io_set_nonblock(fptr);
3495 }
3496 io_setstrbuf(&str, len);
3497 iis.th = rb_thread_current();
3498 iis.fptr = fptr;
3499 iis.nonblock = nonblock;
3500 iis.fd = fptr->fd;
3501 iis.buf = RSTRING_PTR(str);
3502 iis.capa = len;
3503 iis.timeout = NULL;
3504 n = io_read_memory_locktmp(str, &iis);
3505 if (n < 0) {
3506 int e = errno;
3507 if (!nonblock && fptr_wait_readable(fptr))
3508 goto again;
3509 if (nonblock && (io_again_p(e))) {
3510 if (no_exception)
3511 return sym_wait_readable;
3512 else
3513 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3514 e, "read would block");
3515 }
3516 rb_syserr_fail_path(e, fptr->pathv);
3517 }
3518 }
3519 io_set_read_length(str, n, shrinkable);
3520
3521 if (n == 0)
3522 return Qnil;
3523 else
3524 return str;
3525}
3526
3527/*
3528 * call-seq:
3529 * readpartial(maxlen) -> string
3530 * readpartial(maxlen, out_string) -> out_string
3531 *
3532 * Reads up to +maxlen+ bytes from the stream;
3533 * returns a string (either a new string or the given +out_string+).
3534 * Its encoding is:
3535 *
3536 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3537 * - ASCII-8BIT, otherwise.
3538 *
3539 * - Contains +maxlen+ bytes from the stream, if available.
3540 * - Otherwise contains all available bytes, if any available.
3541 * - Otherwise is an empty string.
3542 *
3543 * With the single non-negative integer argument +maxlen+ given,
3544 * returns a new string:
3545 *
3546 * f = File.new('t.txt')
3547 * f.readpartial(20) # => "First line\nSecond l"
3548 * f.readpartial(20) # => "ine\n\nFourth line\n"
3549 * f.readpartial(20) # => "Fifth line\n"
3550 * f.readpartial(20) # Raises EOFError.
3551 * f.close
3552 *
3553 * With both argument +maxlen+ and string argument +out_string+ given,
3554 * returns modified +out_string+:
3555 *
3556 * f = File.new('t.txt')
3557 * s = 'foo'
3558 * f.readpartial(20, s) # => "First line\nSecond l"
3559 * s = 'bar'
3560 * f.readpartial(0, s) # => ""
3561 * f.close
3562 *
3563 * This method is useful for a stream such as a pipe, a socket, or a tty.
3564 * It blocks only when no data is immediately available.
3565 * This means that it blocks only when _all_ of the following are true:
3566 *
3567 * - The byte buffer in the stream is empty.
3568 * - The content of the stream is empty.
3569 * - The stream is not at EOF.
3570 *
3571 * When blocked, the method waits for either more data or EOF on the stream:
3572 *
3573 * - If more data is read, the method returns the data.
3574 * - If EOF is reached, the method raises EOFError.
3575 *
3576 * When not blocked, the method responds immediately:
3577 *
3578 * - Returns data from the buffer if there is any.
3579 * - Otherwise returns data from the stream if there is any.
3580 * - Otherwise raises EOFError if the stream has reached EOF.
3581 *
3582 * Note that this method is similar to sysread. The differences are:
3583 *
3584 * - If the byte buffer is not empty, read from the byte buffer
3585 * instead of "sysread for buffered IO (IOError)".
3586 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3587 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3588 * readpartial retries the system call.
3589 *
3590 * The latter means that readpartial is non-blocking-flag insensitive.
3591 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3592 * if the fd is blocking mode.
3593 *
3594 * Examples:
3595 *
3596 * # # Returned Buffer Content Pipe Content
3597 * r, w = IO.pipe #
3598 * w << 'abc' # "" "abc".
3599 * r.readpartial(4096) # => "abc" "" ""
3600 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3601 *
3602 * # # Returned Buffer Content Pipe Content
3603 * r, w = IO.pipe #
3604 * w << 'abc' # "" "abc"
3605 * w.close # "" "abc" EOF
3606 * r.readpartial(4096) # => "abc" "" EOF
3607 * r.readpartial(4096) # raises EOFError
3608 *
3609 * # # Returned Buffer Content Pipe Content
3610 * r, w = IO.pipe #
3611 * w << "abc\ndef\n" # "" "abc\ndef\n"
3612 * r.gets # => "abc\n" "def\n" ""
3613 * w << "ghi\n" # "def\n" "ghi\n"
3614 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3615 * r.readpartial(4096) # => "ghi\n" "" ""
3616 *
3617 */
3618
3619static VALUE
3620io_readpartial(int argc, VALUE *argv, VALUE io)
3621{
3622 VALUE ret;
3623
3624 ret = io_getpartial(argc, argv, io, Qnil, 0);
3625 if (NIL_P(ret))
3626 rb_eof_error();
3627 return ret;
3628}
3629
3630static VALUE
3631io_nonblock_eof(int no_exception)
3632{
3633 if (!no_exception) {
3634 rb_eof_error();
3635 }
3636 return Qnil;
3637}
3638
3639/* :nodoc: */
3640static VALUE
3641io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3642{
3643 rb_io_t *fptr;
3644 long n, len;
3645 struct io_internal_read_struct iis;
3646 int shrinkable;
3647
3648 if ((len = NUM2LONG(length)) < 0) {
3649 rb_raise(rb_eArgError, "negative length %ld given", len);
3650 }
3651
3652 shrinkable = io_setstrbuf(&str, len);
3653 rb_bool_expected(ex, "exception", TRUE);
3654
3655 GetOpenFile(io, fptr);
3657
3658 if (len == 0) {
3659 io_set_read_length(str, 0, shrinkable);
3660 return str;
3661 }
3662
3663 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3664 if (n <= 0) {
3665 rb_fd_set_nonblock(fptr->fd);
3666 shrinkable |= io_setstrbuf(&str, len);
3667 iis.fptr = fptr;
3668 iis.nonblock = 1;
3669 iis.fd = fptr->fd;
3670 iis.buf = RSTRING_PTR(str);
3671 iis.capa = len;
3672 iis.timeout = NULL;
3673 n = io_read_memory_locktmp(str, &iis);
3674 if (n < 0) {
3675 int e = errno;
3676 if (io_again_p(e)) {
3677 if (!ex) return sym_wait_readable;
3678 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3679 e, "read would block");
3680 }
3681 rb_syserr_fail_path(e, fptr->pathv);
3682 }
3683 }
3684 io_set_read_length(str, n, shrinkable);
3685
3686 if (n == 0) {
3687 if (!ex) return Qnil;
3688 rb_eof_error();
3689 }
3690
3691 return str;
3692}
3693
3694/* :nodoc: */
3695static VALUE
3696io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3697{
3698 rb_io_t *fptr;
3699 long n;
3700
3701 if (!RB_TYPE_P(str, T_STRING))
3702 str = rb_obj_as_string(str);
3703 rb_bool_expected(ex, "exception", TRUE);
3704
3705 io = GetWriteIO(io);
3706 GetOpenFile(io, fptr);
3708
3709 if (io_fflush(fptr) < 0)
3710 rb_sys_fail_on_write(fptr);
3711
3712 rb_fd_set_nonblock(fptr->fd);
3713 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3714 RB_GC_GUARD(str);
3715
3716 if (n < 0) {
3717 int e = errno;
3718 if (io_again_p(e)) {
3719 if (!ex) {
3720 return sym_wait_writable;
3721 }
3722 else {
3723 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3724 }
3725 }
3726 rb_syserr_fail_path(e, fptr->pathv);
3727 }
3728
3729 return LONG2FIX(n);
3730}
3731
3732/*
3733 * call-seq:
3734 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3735 *
3736 * Reads bytes from the stream; the stream must be opened for reading
3737 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3738 *
3739 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3740 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3741 *
3742 * Returns a string (either a new string or the given +out_string+)
3743 * containing the bytes read.
3744 * The encoding of the string depends on both +maxLen+ and +out_string+:
3745 *
3746 * - +maxlen+ is +nil+: uses internal encoding of +self+
3747 * (regardless of whether +out_string+ was given).
3748 * - +maxlen+ not +nil+:
3749 *
3750 * - +out_string+ given: encoding of +out_string+ not modified.
3751 * - +out_string+ not given: ASCII-8BIT is used.
3752 *
3753 * <b>Without Argument +out_string+</b>
3754 *
3755 * When argument +out_string+ is omitted,
3756 * the returned value is a new string:
3757 *
3758 * f = File.new('t.txt')
3759 * f.read
3760 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3761 * f.rewind
3762 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3763 * f.read(30) # => "rth line\r\nFifth line\r\n"
3764 * f.read(30) # => nil
3765 * f.close
3766 *
3767 * If +maxlen+ is zero, returns an empty string.
3768 *
3769 * <b> With Argument +out_string+</b>
3770 *
3771 * When argument +out_string+ is given,
3772 * the returned value is +out_string+, whose content is replaced:
3773 *
3774 * f = File.new('t.txt')
3775 * s = 'foo' # => "foo"
3776 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3777 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3778 * f.rewind
3779 * s = 'bar'
3780 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3781 * s # => "First line\r\nSecond line\r\n\r\nFou"
3782 * s = 'baz'
3783 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3784 * s # => "rth line\r\nFifth line\r\n"
3785 * s = 'bat'
3786 * f.read(30, s) # => nil
3787 * s # => ""
3788 * f.close
3789 *
3790 * Note that this method behaves like the fread() function in C.
3791 * This means it retries to invoke read(2) system calls to read data
3792 * with the specified maxlen (or until EOF).
3793 *
3794 * This behavior is preserved even if the stream is in non-blocking mode.
3795 * (This method is non-blocking-flag insensitive as other methods.)
3796 *
3797 * If you need the behavior like a single read(2) system call,
3798 * consider #readpartial, #read_nonblock, and #sysread.
3799 *
3800 * Related: IO#write.
3801 */
3802
3803static VALUE
3804io_read(int argc, VALUE *argv, VALUE io)
3805{
3806 rb_io_t *fptr;
3807 long n, len;
3808 VALUE length, str;
3809 int shrinkable;
3810#if RUBY_CRLF_ENVIRONMENT
3811 int previous_mode;
3812#endif
3813
3814 rb_scan_args(argc, argv, "02", &length, &str);
3815
3816 if (NIL_P(length)) {
3817 GetOpenFile(io, fptr);
3819 return read_all(fptr, remain_size(fptr), str);
3820 }
3821 len = NUM2LONG(length);
3822 if (len < 0) {
3823 rb_raise(rb_eArgError, "negative length %ld given", len);
3824 }
3825
3826 shrinkable = io_setstrbuf(&str,len);
3827
3828 GetOpenFile(io, fptr);
3830 if (len == 0) {
3831 io_set_read_length(str, 0, shrinkable);
3832 return str;
3833 }
3834
3835 READ_CHECK(fptr);
3836#if RUBY_CRLF_ENVIRONMENT
3837 previous_mode = set_binary_mode_with_seek_cur(fptr);
3838#endif
3839 n = io_fread(str, 0, len, fptr);
3840 io_set_read_length(str, n, shrinkable);
3841#if RUBY_CRLF_ENVIRONMENT
3842 if (previous_mode == O_TEXT) {
3843 setmode(fptr->fd, O_TEXT);
3844 }
3845#endif
3846 if (n == 0) return Qnil;
3847
3848 return str;
3849}
3850
3851static void
3852rscheck(const char *rsptr, long rslen, VALUE rs)
3853{
3854 if (!rs) return;
3855 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3856 rb_raise(rb_eRuntimeError, "rs modified");
3857}
3858
3859static const char *
3860search_delim(const char *p, long len, int delim, rb_encoding *enc)
3861{
3862 if (rb_enc_mbminlen(enc) == 1) {
3863 p = memchr(p, delim, len);
3864 if (p) return p + 1;
3865 }
3866 else {
3867 const char *end = p + len;
3868 while (p < end) {
3869 int r = rb_enc_precise_mbclen(p, end, enc);
3870 if (!MBCLEN_CHARFOUND_P(r)) {
3871 p += rb_enc_mbminlen(enc);
3872 continue;
3873 }
3874 int n = MBCLEN_CHARFOUND_LEN(r);
3875 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3876 return p + n;
3877 }
3878 p += n;
3879 }
3880 }
3881 return NULL;
3882}
3883
3884static int
3885appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3886{
3887 VALUE str = *strp;
3888 long limit = *lp;
3889
3890 if (NEED_READCONV(fptr)) {
3891 SET_BINARY_MODE(fptr);
3892 make_readconv(fptr, 0);
3893 do {
3894 const char *p, *e;
3895 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3896 if (searchlen) {
3897 p = READ_CHAR_PENDING_PTR(fptr);
3898 if (0 < limit && limit < searchlen)
3899 searchlen = (int)limit;
3900 e = search_delim(p, searchlen, delim, enc);
3901 if (e) {
3902 int len = (int)(e-p);
3903 if (NIL_P(str))
3904 *strp = str = rb_str_new(p, len);
3905 else
3906 rb_str_buf_cat(str, p, len);
3907 fptr->cbuf.off += len;
3908 fptr->cbuf.len -= len;
3909 limit -= len;
3910 *lp = limit;
3911 return delim;
3912 }
3913
3914 if (NIL_P(str))
3915 *strp = str = rb_str_new(p, searchlen);
3916 else
3917 rb_str_buf_cat(str, p, searchlen);
3918 fptr->cbuf.off += searchlen;
3919 fptr->cbuf.len -= searchlen;
3920 limit -= searchlen;
3921
3922 if (limit == 0) {
3923 *lp = limit;
3924 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3925 }
3926 }
3927 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3928 clear_readconv(fptr);
3929 *lp = limit;
3930 return EOF;
3931 }
3932
3933 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3934 do {
3935 long pending = READ_DATA_PENDING_COUNT(fptr);
3936 if (pending > 0) {
3937 const char *p = READ_DATA_PENDING_PTR(fptr);
3938 const char *e;
3939 long last;
3940
3941 if (limit > 0 && pending > limit) pending = limit;
3942 e = search_delim(p, pending, delim, enc);
3943 if (e) pending = e - p;
3944 if (!NIL_P(str)) {
3945 last = RSTRING_LEN(str);
3946 rb_str_resize(str, last + pending);
3947 }
3948 else {
3949 last = 0;
3950 *strp = str = rb_str_buf_new(pending);
3951 rb_str_set_len(str, pending);
3952 }
3953 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3954 limit -= pending;
3955 *lp = limit;
3956 if (e) return delim;
3957 if (limit == 0)
3958 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3959 }
3960 READ_CHECK(fptr);
3961 } while (io_fillbuf(fptr) >= 0);
3962 *lp = limit;
3963 return EOF;
3964}
3965
3966static inline int
3967swallow(rb_io_t *fptr, int term)
3968{
3969 if (NEED_READCONV(fptr)) {
3970 rb_encoding *enc = io_read_encoding(fptr);
3971 int needconv = rb_enc_mbminlen(enc) != 1;
3972 SET_BINARY_MODE(fptr);
3973 make_readconv(fptr, 0);
3974 do {
3975 size_t cnt;
3976 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3977 const char *p = READ_CHAR_PENDING_PTR(fptr);
3978 int i;
3979 if (!needconv) {
3980 if (*p != term) return TRUE;
3981 i = (int)cnt;
3982 while (--i && *++p == term);
3983 }
3984 else {
3985 const char *e = p + cnt;
3986 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3987 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3988 i = (int)(e - p);
3989 }
3990 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3991 }
3992 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3993 return FALSE;
3994 }
3995
3996 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3997 do {
3998 size_t cnt;
3999 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4000 char buf[1024];
4001 const char *p = READ_DATA_PENDING_PTR(fptr);
4002 int i;
4003 if (cnt > sizeof buf) cnt = sizeof buf;
4004 if (*p != term) return TRUE;
4005 i = (int)cnt;
4006 while (--i && *++p == term);
4007 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4008 rb_sys_fail_path(fptr->pathv);
4009 }
4010 READ_CHECK(fptr);
4011 } while (io_fillbuf(fptr) == 0);
4012 return FALSE;
4013}
4014
4015static VALUE
4016rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4017{
4018 VALUE str = Qnil;
4019 int len = 0;
4020 long pos = 0;
4021 int cr = 0;
4022
4023 do {
4024 int pending = READ_DATA_PENDING_COUNT(fptr);
4025
4026 if (pending > 0) {
4027 const char *p = READ_DATA_PENDING_PTR(fptr);
4028 const char *e;
4029 int chomplen = 0;
4030
4031 e = memchr(p, '\n', pending);
4032 if (e) {
4033 pending = (int)(e - p + 1);
4034 if (chomp) {
4035 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4036 }
4037 }
4038 if (NIL_P(str)) {
4039 str = rb_str_new(p, pending - chomplen);
4040 fptr->rbuf.off += pending;
4041 fptr->rbuf.len -= pending;
4042 }
4043 else {
4044 rb_str_resize(str, len + pending - chomplen);
4045 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4046 fptr->rbuf.off += chomplen;
4047 fptr->rbuf.len -= chomplen;
4048 if (pending == 1 && chomplen == 1 && len > 0) {
4049 if (RSTRING_PTR(str)[len-1] == '\r') {
4050 rb_str_resize(str, --len);
4051 break;
4052 }
4053 }
4054 }
4055 len += pending - chomplen;
4056 if (cr != ENC_CODERANGE_BROKEN)
4057 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4058 if (e) break;
4059 }
4060 READ_CHECK(fptr);
4061 } while (io_fillbuf(fptr) >= 0);
4062 if (NIL_P(str)) return Qnil;
4063
4064 str = io_enc_str(str, fptr);
4065 ENC_CODERANGE_SET(str, cr);
4066 fptr->lineno++;
4067
4068 return str;
4069}
4070
4072 VALUE io;
4073 VALUE rs;
4074 long limit;
4075 unsigned int chomp: 1;
4076};
4077
4078static void
4079extract_getline_opts(VALUE opts, struct getline_arg *args)
4080{
4081 int chomp = FALSE;
4082 if (!NIL_P(opts)) {
4083 static ID kwds[1];
4084 VALUE vchomp;
4085 if (!kwds[0]) {
4086 kwds[0] = rb_intern_const("chomp");
4087 }
4088 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4089 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4090 }
4091 args->chomp = chomp;
4092}
4093
4094static void
4095extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4096{
4097 VALUE rs = rb_rs, lim = Qnil;
4098
4099 if (argc == 1) {
4100 VALUE tmp = Qnil;
4101
4102 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4103 rs = tmp;
4104 }
4105 else {
4106 lim = argv[0];
4107 }
4108 }
4109 else if (2 <= argc) {
4110 rs = argv[0], lim = argv[1];
4111 if (!NIL_P(rs))
4112 StringValue(rs);
4113 }
4114 args->rs = rs;
4115 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4116}
4117
4118static void
4119check_getline_args(VALUE *rsp, long *limit, VALUE io)
4120{
4121 rb_io_t *fptr;
4122 VALUE rs = *rsp;
4123
4124 if (!NIL_P(rs)) {
4125 rb_encoding *enc_rs, *enc_io;
4126
4127 GetOpenFile(io, fptr);
4128 enc_rs = rb_enc_get(rs);
4129 enc_io = io_read_encoding(fptr);
4130 if (enc_io != enc_rs &&
4131 (!is_ascii_string(rs) ||
4132 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4133 if (rs == rb_default_rs) {
4134 rs = rb_enc_str_new(0, 0, enc_io);
4135 rb_str_buf_cat_ascii(rs, "\n");
4136 *rsp = rs;
4137 }
4138 else {
4139 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4140 rb_enc_name(enc_io),
4141 rb_enc_name(enc_rs));
4142 }
4143 }
4144 }
4145}
4146
4147static void
4148prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4149{
4150 VALUE opts;
4151 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4152 extract_getline_args(argc, argv, args);
4153 extract_getline_opts(opts, args);
4154 check_getline_args(&args->rs, &args->limit, io);
4155}
4156
4157static VALUE
4158rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4159{
4160 VALUE str = Qnil;
4161 int nolimit = 0;
4162 rb_encoding *enc;
4163
4165 if (NIL_P(rs) && limit < 0) {
4166 str = read_all(fptr, 0, Qnil);
4167 if (RSTRING_LEN(str) == 0) return Qnil;
4168 }
4169 else if (limit == 0) {
4170 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4171 }
4172 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4173 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4174 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4175 return rb_io_getline_fast(fptr, enc, chomp);
4176 }
4177 else {
4178 int c, newline = -1;
4179 const char *rsptr = 0;
4180 long rslen = 0;
4181 int rspara = 0;
4182 int extra_limit = 16;
4183 int chomp_cr = chomp;
4184
4185 SET_BINARY_MODE(fptr);
4186 enc = io_read_encoding(fptr);
4187
4188 if (!NIL_P(rs)) {
4189 rslen = RSTRING_LEN(rs);
4190 if (rslen == 0) {
4191 rsptr = "\n\n";
4192 rslen = 2;
4193 rspara = 1;
4194 swallow(fptr, '\n');
4195 rs = 0;
4196 if (!rb_enc_asciicompat(enc)) {
4197 rs = rb_usascii_str_new(rsptr, rslen);
4198 rs = rb_str_conv_enc(rs, 0, enc);
4199 OBJ_FREEZE(rs);
4200 rsptr = RSTRING_PTR(rs);
4201 rslen = RSTRING_LEN(rs);
4202 }
4203 newline = '\n';
4204 }
4205 else if (rb_enc_mbminlen(enc) == 1) {
4206 rsptr = RSTRING_PTR(rs);
4207 newline = (unsigned char)rsptr[rslen - 1];
4208 }
4209 else {
4210 rs = rb_str_conv_enc(rs, 0, enc);
4211 rsptr = RSTRING_PTR(rs);
4212 const char *e = rsptr + rslen;
4213 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4214 int n;
4215 newline = rb_enc_codepoint_len(last, e, &n, enc);
4216 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4217 }
4218 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4219 }
4220
4221 /* MS - Optimization */
4222 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4223 const char *s, *p, *pp, *e;
4224
4225 if (c == newline) {
4226 if (RSTRING_LEN(str) < rslen) continue;
4227 s = RSTRING_PTR(str);
4228 e = RSTRING_END(str);
4229 p = e - rslen;
4230 if (!at_char_boundary(s, p, e, enc)) continue;
4231 if (!rspara) rscheck(rsptr, rslen, rs);
4232 if (memcmp(p, rsptr, rslen) == 0) {
4233 if (chomp) {
4234 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4235 rb_str_set_len(str, p - s);
4236 }
4237 break;
4238 }
4239 }
4240 if (limit == 0) {
4241 s = RSTRING_PTR(str);
4242 p = RSTRING_END(str);
4243 pp = rb_enc_prev_char(s, p, p, enc);
4244 if (extra_limit && pp &&
4245 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4246 /* relax the limit while incomplete character.
4247 * extra_limit limits the relax length */
4248 limit = 1;
4249 extra_limit--;
4250 }
4251 else {
4252 nolimit = 1;
4253 break;
4254 }
4255 }
4256 }
4257
4258 if (rspara && c != EOF)
4259 swallow(fptr, '\n');
4260 if (!NIL_P(str))
4261 str = io_enc_str(str, fptr);
4262 }
4263
4264 if (!NIL_P(str) && !nolimit) {
4265 fptr->lineno++;
4266 }
4267
4268 return str;
4269}
4270
4271static VALUE
4272rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4273{
4274 rb_io_t *fptr;
4275 int old_lineno, new_lineno;
4276 VALUE str;
4277
4278 GetOpenFile(io, fptr);
4279 old_lineno = fptr->lineno;
4280 str = rb_io_getline_0(rs, limit, chomp, fptr);
4281 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4282 if (io == ARGF.current_file) {
4283 ARGF.lineno += new_lineno - old_lineno;
4284 ARGF.last_lineno = ARGF.lineno;
4285 }
4286 else {
4287 ARGF.last_lineno = new_lineno;
4288 }
4289 }
4290
4291 return str;
4292}
4293
4294static VALUE
4295rb_io_getline(int argc, VALUE *argv, VALUE io)
4296{
4297 struct getline_arg args;
4298
4299 prepare_getline_args(argc, argv, &args, io);
4300 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4301}
4302
4303VALUE
4305{
4306 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4307}
4308
4309VALUE
4310rb_io_gets_internal(VALUE io)
4311{
4312 rb_io_t *fptr;
4313 GetOpenFile(io, fptr);
4314 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4315}
4316
4317/*
4318 * call-seq:
4319 * gets(sep = $/, chomp: false) -> string or nil
4320 * gets(limit, chomp: false) -> string or nil
4321 * gets(sep, limit, chomp: false) -> string or nil
4322 *
4323 * Reads and returns a line from the stream;
4324 * assigns the return value to <tt>$_</tt>.
4325 * See {Line IO}[rdoc-ref:IO@Line+IO].
4326 *
4327 * With no arguments given, returns the next line
4328 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4329 *
4330 * f = File.open('t.txt')
4331 * f.gets # => "First line\n"
4332 * $_ # => "First line\n"
4333 * f.gets # => "\n"
4334 * f.gets # => "Fourth line\n"
4335 * f.gets # => "Fifth line\n"
4336 * f.gets # => nil
4337 * f.close
4338 *
4339 * With only string argument +sep+ given,
4340 * returns the next line as determined by line separator +sep+,
4341 * or +nil+ if none;
4342 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4343 *
4344 * f = File.new('t.txt')
4345 * f.gets('l') # => "First l"
4346 * f.gets('li') # => "ine\nSecond li"
4347 * f.gets('lin') # => "ne\n\nFourth lin"
4348 * f.gets # => "e\n"
4349 * f.close
4350 *
4351 * The two special values for +sep+ are honored:
4352 *
4353 * f = File.new('t.txt')
4354 * # Get all.
4355 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4356 * f.rewind
4357 * # Get paragraph (up to two line separators).
4358 * f.gets('') # => "First line\nSecond line\n\n"
4359 * f.close
4360 *
4361 * With only integer argument +limit+ given,
4362 * limits the number of bytes in the line;
4363 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4364 *
4365 * # No more than one line.
4366 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4367 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4368 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4369 *
4370 * With arguments +sep+ and +limit+ given,
4371 * combines the two behaviors
4372 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4373 *
4374 * Optional keyword argument +chomp+ specifies whether line separators
4375 * are to be omitted:
4376 *
4377 * f = File.open('t.txt')
4378 * # Chomp the lines.
4379 * f.gets(chomp: true) # => "First line"
4380 * f.gets(chomp: true) # => "Second line"
4381 * f.gets(chomp: true) # => ""
4382 * f.gets(chomp: true) # => "Fourth line"
4383 * f.gets(chomp: true) # => "Fifth line"
4384 * f.gets(chomp: true) # => nil
4385 * f.close
4386 *
4387 */
4388
4389static VALUE
4390rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4391{
4392 VALUE str;
4393
4394 str = rb_io_getline(argc, argv, io);
4395 rb_lastline_set(str);
4396
4397 return str;
4398}
4399
4400/*
4401 * call-seq:
4402 * lineno -> integer
4403 *
4404 * Returns the current line number for the stream;
4405 * see {Line Number}[rdoc-ref:IO@Line+Number].
4406 *
4407 */
4408
4409static VALUE
4410rb_io_lineno(VALUE io)
4411{
4412 rb_io_t *fptr;
4413
4414 GetOpenFile(io, fptr);
4416 return INT2NUM(fptr->lineno);
4417}
4418
4419/*
4420 * call-seq:
4421 * lineno = integer -> integer
4422 *
4423 * Sets and returns the line number for the stream;
4424 * see {Line Number}[rdoc-ref:IO@Line+Number].
4425 *
4426 */
4427
4428static VALUE
4429rb_io_set_lineno(VALUE io, VALUE lineno)
4430{
4431 rb_io_t *fptr;
4432
4433 GetOpenFile(io, fptr);
4435 fptr->lineno = NUM2INT(lineno);
4436 return lineno;
4437}
4438
4439/* :nodoc: */
4440static VALUE
4441io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4442{
4443 long limit = -1;
4444 if (NIL_P(lim)) {
4445 VALUE tmp = Qnil;
4446 // If sep is specified, but it's not a string and not nil, then assume
4447 // it's the limit (it should be an integer)
4448 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4449 // If the user has specified a non-nil / non-string value
4450 // for the separator, we assume it's the limit and set the
4451 // separator to default: rb_rs.
4452 lim = sep;
4453 limit = NUM2LONG(lim);
4454 sep = rb_rs;
4455 }
4456 else {
4457 sep = tmp;
4458 }
4459 }
4460 else {
4461 if (!NIL_P(sep)) StringValue(sep);
4462 limit = NUM2LONG(lim);
4463 }
4464
4465 check_getline_args(&sep, &limit, io);
4466
4467 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4468 rb_lastline_set_up(line, 1);
4469
4470 if (NIL_P(line)) {
4471 rb_eof_error();
4472 }
4473 return line;
4474}
4475
4476static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4477
4478/*
4479 * call-seq:
4480 * readlines(sep = $/, chomp: false) -> array
4481 * readlines(limit, chomp: false) -> array
4482 * readlines(sep, limit, chomp: false) -> array
4483 *
4484 * Reads and returns all remaining line from the stream;
4485 * does not modify <tt>$_</tt>.
4486 * See {Line IO}[rdoc-ref:IO@Line+IO].
4487 *
4488 * With no arguments given, returns lines
4489 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4490 *
4491 * f = File.new('t.txt')
4492 * f.readlines
4493 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4494 * f.readlines # => []
4495 * f.close
4496 *
4497 * With only string argument +sep+ given,
4498 * returns lines as determined by line separator +sep+,
4499 * or +nil+ if none;
4500 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4501 *
4502 * f = File.new('t.txt')
4503 * f.readlines('li')
4504 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4505 * f.close
4506 *
4507 * The two special values for +sep+ are honored:
4508 *
4509 * f = File.new('t.txt')
4510 * # Get all into one string.
4511 * f.readlines(nil)
4512 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4513 * # Get paragraphs (up to two line separators).
4514 * f.rewind
4515 * f.readlines('')
4516 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4517 * f.close
4518 *
4519 * With only integer argument +limit+ given,
4520 * limits the number of bytes in each line;
4521 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4522 *
4523 * f = File.new('t.txt')
4524 * f.readlines(8)
4525 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4526 * f.close
4527 *
4528 * With arguments +sep+ and +limit+ given,
4529 * combines the two behaviors
4530 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4531 *
4532 * Optional keyword argument +chomp+ specifies whether line separators
4533 * are to be omitted:
4534 *
4535 * f = File.new('t.txt')
4536 * f.readlines(chomp: true)
4537 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4538 * f.close
4539 *
4540 */
4541
4542static VALUE
4543rb_io_readlines(int argc, VALUE *argv, VALUE io)
4544{
4545 struct getline_arg args;
4546
4547 prepare_getline_args(argc, argv, &args, io);
4548 return io_readlines(&args, io);
4549}
4550
4551static VALUE
4552io_readlines(const struct getline_arg *arg, VALUE io)
4553{
4554 VALUE line, ary;
4555
4556 if (arg->limit == 0)
4557 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4558 ary = rb_ary_new();
4559 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4560 rb_ary_push(ary, line);
4561 }
4562 return ary;
4563}
4564
4565/*
4566 * call-seq:
4567 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4568 * each_line(limit, chomp: false) {|line| ... } -> self
4569 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4570 * each_line -> enumerator
4571 *
4572 * Calls the block with each remaining line read from the stream;
4573 * returns +self+.
4574 * Does nothing if already at end-of-stream;
4575 * See {Line IO}[rdoc-ref:IO@Line+IO].
4576 *
4577 * With no arguments given, reads lines
4578 * as determined by line separator <tt>$/</tt>:
4579 *
4580 * f = File.new('t.txt')
4581 * f.each_line {|line| p line }
4582 * f.each_line {|line| fail 'Cannot happen' }
4583 * f.close
4584 *
4585 * Output:
4586 *
4587 * "First line\n"
4588 * "Second line\n"
4589 * "\n"
4590 * "Fourth line\n"
4591 * "Fifth line\n"
4592 *
4593 * With only string argument +sep+ given,
4594 * reads lines as determined by line separator +sep+;
4595 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4596 *
4597 * f = File.new('t.txt')
4598 * f.each_line('li') {|line| p line }
4599 * f.close
4600 *
4601 * Output:
4602 *
4603 * "First li"
4604 * "ne\nSecond li"
4605 * "ne\n\nFourth li"
4606 * "ne\nFifth li"
4607 * "ne\n"
4608 *
4609 * The two special values for +sep+ are honored:
4610 *
4611 * f = File.new('t.txt')
4612 * # Get all into one string.
4613 * f.each_line(nil) {|line| p line }
4614 * f.close
4615 *
4616 * Output:
4617 *
4618 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4619 *
4620 * f.rewind
4621 * # Get paragraphs (up to two line separators).
4622 * f.each_line('') {|line| p line }
4623 *
4624 * Output:
4625 *
4626 * "First line\nSecond line\n\n"
4627 * "Fourth line\nFifth line\n"
4628 *
4629 * With only integer argument +limit+ given,
4630 * limits the number of bytes in each line;
4631 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4632 *
4633 * f = File.new('t.txt')
4634 * f.each_line(8) {|line| p line }
4635 * f.close
4636 *
4637 * Output:
4638 *
4639 * "First li"
4640 * "ne\n"
4641 * "Second l"
4642 * "ine\n"
4643 * "\n"
4644 * "Fourth l"
4645 * "ine\n"
4646 * "Fifth li"
4647 * "ne\n"
4648 *
4649 * With arguments +sep+ and +limit+ given,
4650 * combines the two behaviors
4651 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4652 *
4653 * Optional keyword argument +chomp+ specifies whether line separators
4654 * are to be omitted:
4655 *
4656 * f = File.new('t.txt')
4657 * f.each_line(chomp: true) {|line| p line }
4658 * f.close
4659 *
4660 * Output:
4661 *
4662 * "First line"
4663 * "Second line"
4664 * ""
4665 * "Fourth line"
4666 * "Fifth line"
4667 *
4668 * Returns an Enumerator if no block is given.
4669 */
4670
4671static VALUE
4672rb_io_each_line(int argc, VALUE *argv, VALUE io)
4673{
4674 VALUE str;
4675 struct getline_arg args;
4676
4677 RETURN_ENUMERATOR(io, argc, argv);
4678 prepare_getline_args(argc, argv, &args, io);
4679 if (args.limit == 0)
4680 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4681 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4682 rb_yield(str);
4683 }
4684 return io;
4685}
4686
4687/*
4688 * call-seq:
4689 * each_byte {|byte| ... } -> self
4690 * each_byte -> enumerator
4691 *
4692 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4693 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4694 *
4695 * f = File.new('t.rus')
4696 * a = []
4697 * f.each_byte {|b| a << b }
4698 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4699 * f.close
4700 *
4701 * Returns an Enumerator if no block is given.
4702 *
4703 * Related: IO#each_char, IO#each_codepoint.
4704 *
4705 */
4706
4707static VALUE
4708rb_io_each_byte(VALUE io)
4709{
4710 rb_io_t *fptr;
4711
4712 RETURN_ENUMERATOR(io, 0, 0);
4713 GetOpenFile(io, fptr);
4714
4715 do {
4716 while (fptr->rbuf.len > 0) {
4717 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4718 fptr->rbuf.len--;
4719 rb_yield(INT2FIX(*p & 0xff));
4721 errno = 0;
4722 }
4723 READ_CHECK(fptr);
4724 } while (io_fillbuf(fptr) >= 0);
4725 return io;
4726}
4727
4728static VALUE
4729io_getc(rb_io_t *fptr, rb_encoding *enc)
4730{
4731 int r, n, cr = 0;
4732 VALUE str;
4733
4734 if (NEED_READCONV(fptr)) {
4735 rb_encoding *read_enc = io_read_encoding(fptr);
4736
4737 str = Qnil;
4738 SET_BINARY_MODE(fptr);
4739 make_readconv(fptr, 0);
4740
4741 while (1) {
4742 if (fptr->cbuf.len) {
4743 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4744 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4745 read_enc);
4746 if (!MBCLEN_NEEDMORE_P(r))
4747 break;
4748 if (fptr->cbuf.len == fptr->cbuf.capa) {
4749 rb_raise(rb_eIOError, "too long character");
4750 }
4751 }
4752
4753 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4754 if (fptr->cbuf.len == 0) {
4755 clear_readconv(fptr);
4756 return Qnil;
4757 }
4758 /* return an unit of an incomplete character just before EOF */
4759 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4760 fptr->cbuf.off += 1;
4761 fptr->cbuf.len -= 1;
4762 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4764 return str;
4765 }
4766 }
4767 if (MBCLEN_INVALID_P(r)) {
4768 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4769 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4770 read_enc);
4771 io_shift_cbuf(fptr, r, &str);
4773 }
4774 else {
4775 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4777 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4778 ISASCII(RSTRING_PTR(str)[0])) {
4779 cr = ENC_CODERANGE_7BIT;
4780 }
4781 }
4782 str = io_enc_str(str, fptr);
4783 ENC_CODERANGE_SET(str, cr);
4784 return str;
4785 }
4786
4787 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4788 if (io_fillbuf(fptr) < 0) {
4789 return Qnil;
4790 }
4791 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4792 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4793 fptr->rbuf.off += 1;
4794 fptr->rbuf.len -= 1;
4795 cr = ENC_CODERANGE_7BIT;
4796 }
4797 else {
4798 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4799 if (MBCLEN_CHARFOUND_P(r) &&
4800 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4801 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4802 fptr->rbuf.off += n;
4803 fptr->rbuf.len -= n;
4805 }
4806 else if (MBCLEN_NEEDMORE_P(r)) {
4807 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4808 fptr->rbuf.len = 0;
4809 getc_needmore:
4810 if (io_fillbuf(fptr) != -1) {
4811 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4812 fptr->rbuf.off++;
4813 fptr->rbuf.len--;
4814 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4815 if (MBCLEN_NEEDMORE_P(r)) {
4816 goto getc_needmore;
4817 }
4818 else if (MBCLEN_CHARFOUND_P(r)) {
4820 }
4821 }
4822 }
4823 else {
4824 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4825 fptr->rbuf.off++;
4826 fptr->rbuf.len--;
4827 }
4828 }
4829 if (!cr) cr = ENC_CODERANGE_BROKEN;
4830 str = io_enc_str(str, fptr);
4831 ENC_CODERANGE_SET(str, cr);
4832 return str;
4833}
4834
4835/*
4836 * call-seq:
4837 * each_char {|c| ... } -> self
4838 * each_char -> enumerator
4839 *
4840 * Calls the given block with each character in the stream; returns +self+.
4841 * See {Character IO}[rdoc-ref:IO@Character+IO].
4842 *
4843 * f = File.new('t.rus')
4844 * a = []
4845 * f.each_char {|c| a << c.ord }
4846 * a # => [1090, 1077, 1089, 1090]
4847 * f.close
4848 *
4849 * Returns an Enumerator if no block is given.
4850 *
4851 * Related: IO#each_byte, IO#each_codepoint.
4852 *
4853 */
4854
4855static VALUE
4856rb_io_each_char(VALUE io)
4857{
4858 rb_io_t *fptr;
4859 rb_encoding *enc;
4860 VALUE c;
4861
4862 RETURN_ENUMERATOR(io, 0, 0);
4863 GetOpenFile(io, fptr);
4865
4866 enc = io_input_encoding(fptr);
4867 READ_CHECK(fptr);
4868 while (!NIL_P(c = io_getc(fptr, enc))) {
4869 rb_yield(c);
4870 }
4871 return io;
4872}
4873
4874/*
4875 * call-seq:
4876 * each_codepoint {|c| ... } -> self
4877 * each_codepoint -> enumerator
4878 *
4879 * Calls the given block with each codepoint in the stream; returns +self+:
4880 *
4881 * f = File.new('t.rus')
4882 * a = []
4883 * f.each_codepoint {|c| a << c }
4884 * a # => [1090, 1077, 1089, 1090]
4885 * f.close
4886 *
4887 * Returns an Enumerator if no block is given.
4888 *
4889 * Related: IO#each_byte, IO#each_char.
4890 *
4891 */
4892
4893static VALUE
4894rb_io_each_codepoint(VALUE io)
4895{
4896 rb_io_t *fptr;
4897 rb_encoding *enc;
4898 unsigned int c;
4899 int r, n;
4900
4901 RETURN_ENUMERATOR(io, 0, 0);
4902 GetOpenFile(io, fptr);
4904
4905 READ_CHECK(fptr);
4906 if (NEED_READCONV(fptr)) {
4907 SET_BINARY_MODE(fptr);
4908 r = 1; /* no invalid char yet */
4909 for (;;) {
4910 make_readconv(fptr, 0);
4911 for (;;) {
4912 if (fptr->cbuf.len) {
4913 if (fptr->encs.enc)
4914 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4915 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4916 fptr->encs.enc);
4917 else
4918 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4919 if (!MBCLEN_NEEDMORE_P(r))
4920 break;
4921 if (fptr->cbuf.len == fptr->cbuf.capa) {
4922 rb_raise(rb_eIOError, "too long character");
4923 }
4924 }
4925 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4926 clear_readconv(fptr);
4927 if (!MBCLEN_CHARFOUND_P(r)) {
4928 enc = fptr->encs.enc;
4929 goto invalid;
4930 }
4931 return io;
4932 }
4933 }
4934 if (MBCLEN_INVALID_P(r)) {
4935 enc = fptr->encs.enc;
4936 goto invalid;
4937 }
4938 n = MBCLEN_CHARFOUND_LEN(r);
4939 if (fptr->encs.enc) {
4940 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4941 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4942 fptr->encs.enc);
4943 }
4944 else {
4945 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4946 }
4947 fptr->cbuf.off += n;
4948 fptr->cbuf.len -= n;
4949 rb_yield(UINT2NUM(c));
4951 }
4952 }
4953 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4954 enc = io_input_encoding(fptr);
4955 while (io_fillbuf(fptr) >= 0) {
4956 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4957 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4958 if (MBCLEN_CHARFOUND_P(r) &&
4959 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4960 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4961 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4962 fptr->rbuf.off += n;
4963 fptr->rbuf.len -= n;
4964 rb_yield(UINT2NUM(c));
4965 }
4966 else if (MBCLEN_INVALID_P(r)) {
4967 goto invalid;
4968 }
4969 else if (MBCLEN_NEEDMORE_P(r)) {
4970 char cbuf[8], *p = cbuf;
4971 int more = MBCLEN_NEEDMORE_LEN(r);
4972 if (more > numberof(cbuf)) goto invalid;
4973 more += n = fptr->rbuf.len;
4974 if (more > numberof(cbuf)) goto invalid;
4975 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4976 (p += n, (more -= n) > 0)) {
4977 if (io_fillbuf(fptr) < 0) goto invalid;
4978 if ((n = fptr->rbuf.len) > more) n = more;
4979 }
4980 r = rb_enc_precise_mbclen(cbuf, p, enc);
4981 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4982 c = rb_enc_codepoint(cbuf, p, enc);
4983 rb_yield(UINT2NUM(c));
4984 }
4985 else {
4986 continue;
4987 }
4989 }
4990 return io;
4991
4992 invalid:
4993 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4995}
4996
4997/*
4998 * call-seq:
4999 * getc -> character or nil
5000 *
5001 * Reads and returns the next 1-character string from the stream;
5002 * returns +nil+ if already at end-of-stream.
5003 * See {Character IO}[rdoc-ref:IO@Character+IO].
5004 *
5005 * f = File.open('t.txt')
5006 * f.getc # => "F"
5007 * f.close
5008 * f = File.open('t.rus')
5009 * f.getc.ord # => 1090
5010 * f.close
5011 *
5012 * Related: IO#readchar (may raise EOFError).
5013 *
5014 */
5015
5016static VALUE
5017rb_io_getc(VALUE io)
5018{
5019 rb_io_t *fptr;
5020 rb_encoding *enc;
5021
5022 GetOpenFile(io, fptr);
5024
5025 enc = io_input_encoding(fptr);
5026 READ_CHECK(fptr);
5027 return io_getc(fptr, enc);
5028}
5029
5030/*
5031 * call-seq:
5032 * readchar -> string
5033 *
5034 * Reads and returns the next 1-character string from the stream;
5035 * raises EOFError if already at end-of-stream.
5036 * See {Character IO}[rdoc-ref:IO@Character+IO].
5037 *
5038 * f = File.open('t.txt')
5039 * f.readchar # => "F"
5040 * f.close
5041 * f = File.open('t.rus')
5042 * f.readchar.ord # => 1090
5043 * f.close
5044 *
5045 * Related: IO#getc (will not raise EOFError).
5046 *
5047 */
5048
5049static VALUE
5050rb_io_readchar(VALUE io)
5051{
5052 VALUE c = rb_io_getc(io);
5053
5054 if (NIL_P(c)) {
5055 rb_eof_error();
5056 }
5057 return c;
5058}
5059
5060/*
5061 * call-seq:
5062 * getbyte -> integer or nil
5063 *
5064 * Reads and returns the next byte (in range 0..255) from the stream;
5065 * returns +nil+ if already at end-of-stream.
5066 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5067 *
5068 * f = File.open('t.txt')
5069 * f.getbyte # => 70
5070 * f.close
5071 * f = File.open('t.rus')
5072 * f.getbyte # => 209
5073 * f.close
5074 *
5075 * Related: IO#readbyte (may raise EOFError).
5076 */
5077
5078VALUE
5080{
5081 rb_io_t *fptr;
5082 int c;
5083
5084 GetOpenFile(io, fptr);
5086 READ_CHECK(fptr);
5087 VALUE r_stdout = rb_ractor_stdout();
5088 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5089 rb_io_t *ofp;
5090 GetOpenFile(r_stdout, ofp);
5091 if (ofp->mode & FMODE_TTY) {
5092 rb_io_flush(r_stdout);
5093 }
5094 }
5095 if (io_fillbuf(fptr) < 0) {
5096 return Qnil;
5097 }
5098 fptr->rbuf.off++;
5099 fptr->rbuf.len--;
5100 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5101 return INT2FIX(c & 0xff);
5102}
5103
5104/*
5105 * call-seq:
5106 * readbyte -> integer
5107 *
5108 * Reads and returns the next byte (in range 0..255) from the stream;
5109 * raises EOFError if already at end-of-stream.
5110 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5111 *
5112 * f = File.open('t.txt')
5113 * f.readbyte # => 70
5114 * f.close
5115 * f = File.open('t.rus')
5116 * f.readbyte # => 209
5117 * f.close
5118 *
5119 * Related: IO#getbyte (will not raise EOFError).
5120 *
5121 */
5122
5123static VALUE
5124rb_io_readbyte(VALUE io)
5125{
5126 VALUE c = rb_io_getbyte(io);
5127
5128 if (NIL_P(c)) {
5129 rb_eof_error();
5130 }
5131 return c;
5132}
5133
5134/*
5135 * call-seq:
5136 * ungetbyte(integer) -> nil
5137 * ungetbyte(string) -> nil
5138 *
5139 * Pushes back ("unshifts") the given data onto the stream's buffer,
5140 * placing the data so that it is next to be read; returns +nil+.
5141 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5142 *
5143 * Note that:
5144 *
5145 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5146 * - Calling #rewind on the stream discards the pushed-back data.
5147 *
5148 * When argument +integer+ is given, uses only its low-order byte:
5149 *
5150 * File.write('t.tmp', '012')
5151 * f = File.open('t.tmp')
5152 * f.ungetbyte(0x41) # => nil
5153 * f.read # => "A012"
5154 * f.rewind
5155 * f.ungetbyte(0x4243) # => nil
5156 * f.read # => "C012"
5157 * f.close
5158 *
5159 * When argument +string+ is given, uses all bytes:
5160 *
5161 * File.write('t.tmp', '012')
5162 * f = File.open('t.tmp')
5163 * f.ungetbyte('A') # => nil
5164 * f.read # => "A012"
5165 * f.rewind
5166 * f.ungetbyte('BCDE') # => nil
5167 * f.read # => "BCDE012"
5168 * f.close
5169 *
5170 */
5171
5172VALUE
5174{
5175 rb_io_t *fptr;
5176
5177 GetOpenFile(io, fptr);
5179 switch (TYPE(b)) {
5180 case T_NIL:
5181 return Qnil;
5182 case T_FIXNUM:
5183 case T_BIGNUM: ;
5184 VALUE v = rb_int_modulo(b, INT2FIX(256));
5185 unsigned char c = NUM2INT(v) & 0xFF;
5186 b = rb_str_new((const char *)&c, 1);
5187 break;
5188 default:
5189 StringValue(b);
5190 }
5191 io_ungetbyte(b, fptr);
5192 return Qnil;
5193}
5194
5195/*
5196 * call-seq:
5197 * ungetc(integer) -> nil
5198 * ungetc(string) -> nil
5199 *
5200 * Pushes back ("unshifts") the given data onto the stream's buffer,
5201 * placing the data so that it is next to be read; returns +nil+.
5202 * See {Character IO}[rdoc-ref:IO@Character+IO].
5203 *
5204 * Note that:
5205 *
5206 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5207 * - Calling #rewind on the stream discards the pushed-back data.
5208 *
5209 * When argument +integer+ is given, interprets the integer as a character:
5210 *
5211 * File.write('t.tmp', '012')
5212 * f = File.open('t.tmp')
5213 * f.ungetc(0x41) # => nil
5214 * f.read # => "A012"
5215 * f.rewind
5216 * f.ungetc(0x0442) # => nil
5217 * f.getc.ord # => 1090
5218 * f.close
5219 *
5220 * When argument +string+ is given, uses all characters:
5221 *
5222 * File.write('t.tmp', '012')
5223 * f = File.open('t.tmp')
5224 * f.ungetc('A') # => nil
5225 * f.read # => "A012"
5226 * f.rewind
5227 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5228 * f.getc.ord # => 1090
5229 * f.getc.ord # => 1077
5230 * f.getc.ord # => 1089
5231 * f.getc.ord # => 1090
5232 * f.close
5233 *
5234 */
5235
5236VALUE
5238{
5239 rb_io_t *fptr;
5240 long len;
5241
5242 GetOpenFile(io, fptr);
5244 if (FIXNUM_P(c)) {
5245 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5246 }
5247 else if (RB_BIGNUM_TYPE_P(c)) {
5248 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5249 }
5250 else {
5251 StringValue(c);
5252 }
5253 if (NEED_READCONV(fptr)) {
5254 SET_BINARY_MODE(fptr);
5255 len = RSTRING_LEN(c);
5256#if SIZEOF_LONG > SIZEOF_INT
5257 if (len > INT_MAX)
5258 rb_raise(rb_eIOError, "ungetc failed");
5259#endif
5260 make_readconv(fptr, (int)len);
5261 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5262 rb_raise(rb_eIOError, "ungetc failed");
5263 if (fptr->cbuf.off < len) {
5264 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5265 fptr->cbuf.ptr+fptr->cbuf.off,
5266 char, fptr->cbuf.len);
5267 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5268 }
5269 fptr->cbuf.off -= (int)len;
5270 fptr->cbuf.len += (int)len;
5271 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5272 }
5273 else {
5274 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5275 io_ungetbyte(c, fptr);
5276 }
5277 return Qnil;
5278}
5279
5280/*
5281 * call-seq:
5282 * isatty -> true or false
5283 *
5284 * Returns +true+ if the stream is associated with a terminal device (tty),
5285 * +false+ otherwise:
5286 *
5287 * f = File.new('t.txt').isatty #=> false
5288 * f.close
5289 * f = File.new('/dev/tty').isatty #=> true
5290 * f.close
5291 *
5292 */
5293
5294static VALUE
5295rb_io_isatty(VALUE io)
5296{
5297 rb_io_t *fptr;
5298
5299 GetOpenFile(io, fptr);
5300 return RBOOL(isatty(fptr->fd) != 0);
5301}
5302
5303#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5304/*
5305 * call-seq:
5306 * close_on_exec? -> true or false
5307 *
5308 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5309 *
5310 * f = File.open('t.txt')
5311 * f.close_on_exec? # => true
5312 * f.close_on_exec = false
5313 * f.close_on_exec? # => false
5314 * f.close
5315 *
5316 */
5317
5318static VALUE
5319rb_io_close_on_exec_p(VALUE io)
5320{
5321 rb_io_t *fptr;
5322 VALUE write_io;
5323 int fd, ret;
5324
5325 write_io = GetWriteIO(io);
5326 if (io != write_io) {
5327 GetOpenFile(write_io, fptr);
5328 if (fptr && 0 <= (fd = fptr->fd)) {
5329 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5330 if (!(ret & FD_CLOEXEC)) return Qfalse;
5331 }
5332 }
5333
5334 GetOpenFile(io, fptr);
5335 if (fptr && 0 <= (fd = fptr->fd)) {
5336 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5337 if (!(ret & FD_CLOEXEC)) return Qfalse;
5338 }
5339 return Qtrue;
5340}
5341#else
5342#define rb_io_close_on_exec_p rb_f_notimplement
5343#endif
5344
5345#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5346/*
5347 * call-seq:
5348 * self.close_on_exec = bool -> true or false
5349 *
5350 * Sets a close-on-exec flag.
5351 *
5352 * f = File.open(File::NULL)
5353 * f.close_on_exec = true
5354 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5355 * f.closed? #=> false
5356 *
5357 * Ruby sets close-on-exec flags of all file descriptors by default
5358 * since Ruby 2.0.0.
5359 * So you don't need to set by yourself.
5360 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5361 * if another thread use fork() and exec() (via system() method for example).
5362 * If you really needs file descriptor inheritance to child process,
5363 * use spawn()'s argument such as fd=>fd.
5364 */
5365
5366static VALUE
5367rb_io_set_close_on_exec(VALUE io, VALUE arg)
5368{
5369 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5370 rb_io_t *fptr;
5371 VALUE write_io;
5372 int fd, ret;
5373
5374 write_io = GetWriteIO(io);
5375 if (io != write_io) {
5376 GetOpenFile(write_io, fptr);
5377 if (fptr && 0 <= (fd = fptr->fd)) {
5378 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5379 if ((ret & FD_CLOEXEC) != flag) {
5380 ret = (ret & ~FD_CLOEXEC) | flag;
5381 ret = fcntl(fd, F_SETFD, ret);
5382 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5383 }
5384 }
5385
5386 }
5387
5388 GetOpenFile(io, fptr);
5389 if (fptr && 0 <= (fd = fptr->fd)) {
5390 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5391 if ((ret & FD_CLOEXEC) != flag) {
5392 ret = (ret & ~FD_CLOEXEC) | flag;
5393 ret = fcntl(fd, F_SETFD, ret);
5394 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5395 }
5396 }
5397 return Qnil;
5398}
5399#else
5400#define rb_io_set_close_on_exec rb_f_notimplement
5401#endif
5402
5403#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5404#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5405
5406static VALUE
5407finish_writeconv(rb_io_t *fptr, int noalloc)
5408{
5409 unsigned char *ds, *dp, *de;
5411
5412 if (!fptr->wbuf.ptr) {
5413 unsigned char buf[1024];
5414
5416 while (res == econv_destination_buffer_full) {
5417 ds = dp = buf;
5418 de = buf + sizeof(buf);
5419 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5420 while (dp-ds) {
5421 size_t remaining = dp-ds;
5422 long result = rb_io_write_memory(fptr, ds, remaining);
5423
5424 if (result > 0) {
5425 ds += result;
5426 if ((size_t)result == remaining) break;
5427 }
5428 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5429 if (fptr->fd < 0)
5430 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5431 }
5432 else {
5433 return noalloc ? Qtrue : INT2NUM(errno);
5434 }
5435 }
5436 if (res == econv_invalid_byte_sequence ||
5437 res == econv_incomplete_input ||
5439 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5440 }
5441 }
5442
5443 return Qnil;
5444 }
5445
5447 while (res == econv_destination_buffer_full) {
5448 if (fptr->wbuf.len == fptr->wbuf.capa) {
5449 if (io_fflush(fptr) < 0) {
5450 return noalloc ? Qtrue : INT2NUM(errno);
5451 }
5452 }
5453
5454 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5455 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5456 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5457 fptr->wbuf.len += (int)(dp - ds);
5458 if (res == econv_invalid_byte_sequence ||
5459 res == econv_incomplete_input ||
5461 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5462 }
5463 }
5464 return Qnil;
5465}
5466
5468 rb_io_t *fptr;
5469 int noalloc;
5470};
5471
5472static VALUE
5473finish_writeconv_sync(VALUE arg)
5474{
5475 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5476 return finish_writeconv(p->fptr, p->noalloc);
5477}
5478
5479static void*
5480nogvl_close(void *ptr)
5481{
5482 int *fd = ptr;
5483
5484 return (void*)(intptr_t)close(*fd);
5485}
5486
5487static int
5488maygvl_close(int fd, int keepgvl)
5489{
5490 if (keepgvl)
5491 return close(fd);
5492
5493 /*
5494 * close() may block for certain file types (NFS, SO_LINGER sockets,
5495 * inotify), so let other threads run.
5496 */
5497 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5498}
5499
5500static void*
5501nogvl_fclose(void *ptr)
5502{
5503 FILE *file = ptr;
5504
5505 return (void*)(intptr_t)fclose(file);
5506}
5507
5508static int
5509maygvl_fclose(FILE *file, int keepgvl)
5510{
5511 if (keepgvl)
5512 return fclose(file);
5513
5514 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5515}
5516
5517static void free_io_buffer(rb_io_buffer_t *buf);
5518
5519static void
5520fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5521{
5522 VALUE error = Qnil;
5523 int fd = fptr->fd;
5524 FILE *stdio_file = fptr->stdio_file;
5525 int mode = fptr->mode;
5526
5527 if (fptr->writeconv) {
5528 if (!NIL_P(fptr->write_lock) && !noraise) {
5529 struct finish_writeconv_arg arg;
5530 arg.fptr = fptr;
5531 arg.noalloc = noraise;
5532 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5533 }
5534 else {
5535 error = finish_writeconv(fptr, noraise);
5536 }
5537 }
5538 if (fptr->wbuf.len) {
5539 if (noraise) {
5540 io_flush_buffer_sync(fptr);
5541 }
5542 else {
5543 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5544 error = INT2NUM(errno);
5545 }
5546 }
5547 }
5548
5549 int done = 0;
5550
5551 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5552 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5553 done = 1;
5554 }
5555
5556 fptr->fd = -1;
5557 fptr->stdio_file = 0;
5559
5560 // wait for blocking operations to ensure they do not hit EBADF:
5561 rb_thread_io_close_wait(fptr);
5562
5563 // Disable for now.
5564 // if (!done && fd >= 0) {
5565 // VALUE scheduler = rb_fiber_scheduler_current();
5566 // if (scheduler != Qnil) {
5567 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5568 // if (!UNDEF_P(result)) done = 1;
5569 // }
5570 // }
5571
5572 if (!done && stdio_file) {
5573 // stdio_file is deallocated anyway even if fclose failed.
5574 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5575 if (!noraise) {
5576 error = INT2NUM(errno);
5577 }
5578 }
5579
5580 done = 1;
5581 }
5582
5583 if (!done && fd >= 0) {
5584 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5585 // We assumes it is closed.
5586
5587 keepgvl |= !(mode & FMODE_WRITABLE);
5588 keepgvl |= noraise;
5589 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5590 if (!noraise) {
5591 error = INT2NUM(errno);
5592 }
5593 }
5594
5595 done = 1;
5596 }
5597
5598 if (!NIL_P(error) && !noraise) {
5599 if (RB_INTEGER_TYPE_P(error))
5600 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5601 else
5602 rb_exc_raise(error);
5603 }
5604}
5605
5606static void
5607fptr_finalize(rb_io_t *fptr, int noraise)
5608{
5609 fptr_finalize_flush(fptr, noraise, FALSE);
5610 free_io_buffer(&fptr->rbuf);
5611 free_io_buffer(&fptr->wbuf);
5612 clear_codeconv(fptr);
5613}
5614
5615static void
5616rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5617{
5618 if (fptr->finalize) {
5619 (*fptr->finalize)(fptr, noraise);
5620 }
5621 else {
5622 fptr_finalize(fptr, noraise);
5623 }
5624}
5625
5626static void
5627free_io_buffer(rb_io_buffer_t *buf)
5628{
5629 if (buf->ptr) {
5630 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5631 buf->ptr = NULL;
5632 }
5633}
5634
5635static void
5636clear_readconv(rb_io_t *fptr)
5637{
5638 if (fptr->readconv) {
5639 rb_econv_close(fptr->readconv);
5640 fptr->readconv = NULL;
5641 }
5642 free_io_buffer(&fptr->cbuf);
5643}
5644
5645static void
5646clear_writeconv(rb_io_t *fptr)
5647{
5648 if (fptr->writeconv) {
5650 fptr->writeconv = NULL;
5651 }
5652 fptr->writeconv_initialized = 0;
5653}
5654
5655static void
5656clear_codeconv(rb_io_t *fptr)
5657{
5658 clear_readconv(fptr);
5659 clear_writeconv(fptr);
5660}
5661
5662static void
5663rb_io_fptr_cleanup_all(rb_io_t *fptr)
5664{
5665 fptr->pathv = Qnil;
5666 if (0 <= fptr->fd)
5667 rb_io_fptr_cleanup(fptr, TRUE);
5668 fptr->write_lock = Qnil;
5669 free_io_buffer(&fptr->rbuf);
5670 free_io_buffer(&fptr->wbuf);
5671 clear_codeconv(fptr);
5672}
5673
5674int
5676{
5677 if (!io) return 0;
5678 rb_io_fptr_cleanup_all(io);
5679 free(io);
5680
5681 return 1;
5682}
5683
5684size_t
5685rb_io_memsize(const rb_io_t *io)
5686{
5687 size_t size = sizeof(rb_io_t);
5688 size += io->rbuf.capa;
5689 size += io->wbuf.capa;
5690 size += io->cbuf.capa;
5691 if (io->readconv) size += rb_econv_memsize(io->readconv);
5692 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5693
5694 struct rb_io_blocking_operation *blocking_operation = 0;
5695 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5696 size += sizeof(struct rb_io_blocking_operation);
5697 }
5698
5699 return size;
5700}
5701
5702#ifdef _WIN32
5703/* keep GVL while closing to prevent crash on Windows */
5704# define KEEPGVL TRUE
5705#else
5706# define KEEPGVL FALSE
5707#endif
5708
5709static rb_io_t *
5710io_close_fptr(VALUE io)
5711{
5712 rb_io_t *fptr;
5713 VALUE write_io;
5714 rb_io_t *write_fptr;
5715
5716 write_io = GetWriteIO(io);
5717 if (io != write_io) {
5718 write_fptr = RFILE(write_io)->fptr;
5719 if (write_fptr && 0 <= write_fptr->fd) {
5720 rb_io_fptr_cleanup(write_fptr, TRUE);
5721 }
5722 }
5723
5724 fptr = RFILE(io)->fptr;
5725 if (!fptr) return 0;
5726 if (fptr->fd < 0) return 0;
5727
5728 if (rb_thread_io_close_interrupt(fptr)) {
5729 /* calls close(fptr->fd): */
5730 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5731 }
5732 rb_io_fptr_cleanup(fptr, FALSE);
5733 return fptr;
5734}
5735
5736static void
5737fptr_waitpid(rb_io_t *fptr, int nohang)
5738{
5739 int status;
5740 if (fptr->pid) {
5741 rb_last_status_clear();
5742 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5743 fptr->pid = 0;
5744 }
5745}
5746
5747VALUE
5749{
5750 rb_io_t *fptr = io_close_fptr(io);
5751 if (fptr) fptr_waitpid(fptr, 0);
5752 return Qnil;
5753}
5754
5755/*
5756 * call-seq:
5757 * close -> nil
5758 *
5759 * Closes the stream for both reading and writing
5760 * if open for either or both; returns +nil+.
5761 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5762 *
5763 * If the stream is open for writing, flushes any buffered writes
5764 * to the operating system before closing.
5765 *
5766 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5767 * (child exit status).
5768 *
5769 * It is not an error to close an IO object that has already been closed.
5770 * It just returns nil.
5771 *
5772 * Example:
5773 *
5774 * IO.popen('ruby', 'r+') do |pipe|
5775 * puts pipe.closed?
5776 * pipe.close
5777 * puts $?
5778 * puts pipe.closed?
5779 * end
5780 *
5781 * Output:
5782 *
5783 * false
5784 * pid 13760 exit 0
5785 * true
5786 *
5787 * Related: IO#close_read, IO#close_write, IO#closed?.
5788 */
5789
5790static VALUE
5791rb_io_close_m(VALUE io)
5792{
5793 rb_io_t *fptr = rb_io_get_fptr(io);
5794 if (fptr->fd < 0) {
5795 return Qnil;
5796 }
5797 rb_io_close(io);
5798 return Qnil;
5799}
5800
5801static VALUE
5802io_call_close(VALUE io)
5803{
5804 rb_check_funcall(io, rb_intern("close"), 0, 0);
5805 return io;
5806}
5807
5808static VALUE
5809ignore_closed_stream(VALUE io, VALUE exc)
5810{
5811 enum {mesg_len = sizeof(closed_stream)-1};
5812 VALUE mesg = rb_attr_get(exc, idMesg);
5813 if (!RB_TYPE_P(mesg, T_STRING) ||
5814 RSTRING_LEN(mesg) != mesg_len ||
5815 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5816 rb_exc_raise(exc);
5817 }
5818 return io;
5819}
5820
5821static VALUE
5822io_close(VALUE io)
5823{
5824 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5825 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5826 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5827 rb_eIOError, (VALUE)0);
5828 return io;
5829}
5830
5831/*
5832 * call-seq:
5833 * closed? -> true or false
5834 *
5835 * Returns +true+ if the stream is closed for both reading and writing,
5836 * +false+ otherwise.
5837 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5838 *
5839 * IO.popen('ruby', 'r+') do |pipe|
5840 * puts pipe.closed?
5841 * pipe.close_read
5842 * puts pipe.closed?
5843 * pipe.close_write
5844 * puts pipe.closed?
5845 * end
5846 *
5847 * Output:
5848 *
5849 * false
5850 * false
5851 * true
5852 *
5853 * Related: IO#close_read, IO#close_write, IO#close.
5854 */
5855VALUE
5857{
5858 rb_io_t *fptr;
5859 VALUE write_io;
5860 rb_io_t *write_fptr;
5861
5862 write_io = GetWriteIO(io);
5863 if (io != write_io) {
5864 write_fptr = RFILE(write_io)->fptr;
5865 if (write_fptr && 0 <= write_fptr->fd) {
5866 return Qfalse;
5867 }
5868 }
5869
5870 fptr = rb_io_get_fptr(io);
5871 return RBOOL(0 > fptr->fd);
5872}
5873
5874/*
5875 * call-seq:
5876 * close_read -> nil
5877 *
5878 * Closes the stream for reading if open for reading;
5879 * returns +nil+.
5880 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5881 *
5882 * If the stream was opened by IO.popen and is also closed for writing,
5883 * sets global variable <tt>$?</tt> (child exit status).
5884 *
5885 * Example:
5886 *
5887 * IO.popen('ruby', 'r+') do |pipe|
5888 * puts pipe.closed?
5889 * pipe.close_write
5890 * puts pipe.closed?
5891 * pipe.close_read
5892 * puts $?
5893 * puts pipe.closed?
5894 * end
5895 *
5896 * Output:
5897 *
5898 * false
5899 * false
5900 * pid 14748 exit 0
5901 * true
5902 *
5903 * Related: IO#close, IO#close_write, IO#closed?.
5904 */
5905
5906static VALUE
5907rb_io_close_read(VALUE io)
5908{
5909 rb_io_t *fptr;
5910 VALUE write_io;
5911
5912 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5913 if (fptr->fd < 0) return Qnil;
5914 if (is_socket(fptr->fd, fptr->pathv)) {
5915#ifndef SHUT_RD
5916# define SHUT_RD 0
5917#endif
5918 if (shutdown(fptr->fd, SHUT_RD) < 0)
5919 rb_sys_fail_path(fptr->pathv);
5920 fptr->mode &= ~FMODE_READABLE;
5921 if (!(fptr->mode & FMODE_WRITABLE))
5922 return rb_io_close(io);
5923 return Qnil;
5924 }
5925
5926 write_io = GetWriteIO(io);
5927 if (io != write_io) {
5928 rb_io_t *wfptr;
5929 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5930 wfptr->pid = fptr->pid;
5931 fptr->pid = 0;
5932 RFILE(io)->fptr = wfptr;
5933 /* bind to write_io temporarily to get rid of memory/fd leak */
5934 fptr->tied_io_for_writing = 0;
5935 RFILE(write_io)->fptr = fptr;
5936 rb_io_fptr_cleanup(fptr, FALSE);
5937 /* should not finalize fptr because another thread may be reading it */
5938 return Qnil;
5939 }
5940
5941 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5942 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5943 }
5944 return rb_io_close(io);
5945}
5946
5947/*
5948 * call-seq:
5949 * close_write -> nil
5950 *
5951 * Closes the stream for writing if open for writing;
5952 * returns +nil+.
5953 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5954 *
5955 * Flushes any buffered writes to the operating system before closing.
5956 *
5957 * If the stream was opened by IO.popen and is also closed for reading,
5958 * sets global variable <tt>$?</tt> (child exit status).
5959 *
5960 * IO.popen('ruby', 'r+') do |pipe|
5961 * puts pipe.closed?
5962 * pipe.close_read
5963 * puts pipe.closed?
5964 * pipe.close_write
5965 * puts $?
5966 * puts pipe.closed?
5967 * end
5968 *
5969 * Output:
5970 *
5971 * false
5972 * false
5973 * pid 15044 exit 0
5974 * true
5975 *
5976 * Related: IO#close, IO#close_read, IO#closed?.
5977 */
5978
5979static VALUE
5980rb_io_close_write(VALUE io)
5981{
5982 rb_io_t *fptr;
5983 VALUE write_io;
5984
5985 write_io = GetWriteIO(io);
5986 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5987 if (fptr->fd < 0) return Qnil;
5988 if (is_socket(fptr->fd, fptr->pathv)) {
5989#ifndef SHUT_WR
5990# define SHUT_WR 1
5991#endif
5992 if (shutdown(fptr->fd, SHUT_WR) < 0)
5993 rb_sys_fail_path(fptr->pathv);
5994 fptr->mode &= ~FMODE_WRITABLE;
5995 if (!(fptr->mode & FMODE_READABLE))
5996 return rb_io_close(write_io);
5997 return Qnil;
5998 }
5999
6000 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6001 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6002 }
6003
6004 if (io != write_io) {
6005 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6006 fptr->tied_io_for_writing = 0;
6007 }
6008 rb_io_close(write_io);
6009 return Qnil;
6010}
6011
6012/*
6013 * call-seq:
6014 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6015 *
6016 * Behaves like IO#seek, except that it:
6017 *
6018 * - Uses low-level system functions.
6019 * - Returns the new position.
6020 *
6021 */
6022
6023static VALUE
6024rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6025{
6026 VALUE offset, ptrname;
6027 int whence = SEEK_SET;
6028 rb_io_t *fptr;
6029 rb_off_t pos;
6030
6031 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6032 whence = interpret_seek_whence(ptrname);
6033 }
6034 pos = NUM2OFFT(offset);
6035 GetOpenFile(io, fptr);
6036 if ((fptr->mode & FMODE_READABLE) &&
6037 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6038 rb_raise(rb_eIOError, "sysseek for buffered IO");
6039 }
6040 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6041 rb_warn("sysseek for buffered IO");
6042 }
6043 errno = 0;
6044 pos = lseek(fptr->fd, pos, whence);
6045 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6046
6047 return OFFT2NUM(pos);
6048}
6049
6050/*
6051 * call-seq:
6052 * syswrite(object) -> integer
6053 *
6054 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6055 * returns the number bytes written.
6056 * If +object+ is not a string is converted via method to_s:
6057 *
6058 * f = File.new('t.tmp', 'w')
6059 * f.syswrite('foo') # => 3
6060 * f.syswrite(30) # => 2
6061 * f.syswrite(:foo) # => 3
6062 * f.close
6063 *
6064 * This methods should not be used with other stream-writer methods.
6065 *
6066 */
6067
6068static VALUE
6069rb_io_syswrite(VALUE io, VALUE str)
6070{
6071 VALUE tmp;
6072 rb_io_t *fptr;
6073 long n, len;
6074 const char *ptr;
6075
6076 if (!RB_TYPE_P(str, T_STRING))
6077 str = rb_obj_as_string(str);
6078
6079 io = GetWriteIO(io);
6080 GetOpenFile(io, fptr);
6082
6083 if (fptr->wbuf.len) {
6084 rb_warn("syswrite for buffered IO");
6085 }
6086
6087 tmp = rb_str_tmp_frozen_acquire(str);
6088 RSTRING_GETMEM(tmp, ptr, len);
6089 n = rb_io_write_memory(fptr, ptr, len);
6090 if (n < 0) rb_sys_fail_path(fptr->pathv);
6091 rb_str_tmp_frozen_release(str, tmp);
6092
6093 return LONG2FIX(n);
6094}
6095
6096/*
6097 * call-seq:
6098 * sysread(maxlen) -> string
6099 * sysread(maxlen, out_string) -> string
6100 *
6101 * Behaves like IO#readpartial, except that it uses low-level system functions.
6102 *
6103 * This method should not be used with other stream-reader methods.
6104 *
6105 */
6106
6107static VALUE
6108rb_io_sysread(int argc, VALUE *argv, VALUE io)
6109{
6110 VALUE len, str;
6111 rb_io_t *fptr;
6112 long n, ilen;
6113 struct io_internal_read_struct iis;
6114 int shrinkable;
6115
6116 rb_scan_args(argc, argv, "11", &len, &str);
6117 ilen = NUM2LONG(len);
6118
6119 shrinkable = io_setstrbuf(&str, ilen);
6120 if (ilen == 0) return str;
6121
6122 GetOpenFile(io, fptr);
6124
6125 if (READ_DATA_BUFFERED(fptr)) {
6126 rb_raise(rb_eIOError, "sysread for buffered IO");
6127 }
6128
6129 rb_io_check_closed(fptr);
6130
6131 io_setstrbuf(&str, ilen);
6132 iis.th = rb_thread_current();
6133 iis.fptr = fptr;
6134 iis.nonblock = 0;
6135 iis.fd = fptr->fd;
6136 iis.buf = RSTRING_PTR(str);
6137 iis.capa = ilen;
6138 iis.timeout = NULL;
6139 n = io_read_memory_locktmp(str, &iis);
6140
6141 if (n < 0) {
6142 rb_sys_fail_path(fptr->pathv);
6143 }
6144
6145 io_set_read_length(str, n, shrinkable);
6146
6147 if (n == 0 && ilen > 0) {
6148 rb_eof_error();
6149 }
6150
6151 return str;
6152}
6153
6155 struct rb_io *io;
6156 int fd;
6157 void *buf;
6158 size_t count;
6159 rb_off_t offset;
6160};
6161
6162static VALUE
6163internal_pread_func(void *_arg)
6164{
6165 struct prdwr_internal_arg *arg = _arg;
6166
6167 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6168}
6169
6170static VALUE
6171pread_internal_call(VALUE _arg)
6172{
6173 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6174
6175 VALUE scheduler = rb_fiber_scheduler_current();
6176 if (scheduler != Qnil) {
6177 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6178
6179 if (!UNDEF_P(result)) {
6181 }
6182 }
6183
6184 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6185}
6186
6187/*
6188 * call-seq:
6189 * pread(maxlen, offset) -> string
6190 * pread(maxlen, offset, out_string) -> string
6191 *
6192 * Behaves like IO#readpartial, except that it:
6193 *
6194 * - Reads at the given +offset+ (in bytes).
6195 * - Disregards, and does not modify, the stream's position
6196 * (see {Position}[rdoc-ref:IO@Position]).
6197 * - Bypasses any user space buffering in the stream.
6198 *
6199 * Because this method does not disturb the stream's state
6200 * (its position, in particular), +pread+ allows multiple threads and processes
6201 * to use the same \IO object for reading at various offsets.
6202 *
6203 * f = File.open('t.txt')
6204 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6205 * f.pos # => 52
6206 * # Read 12 bytes at offset 0.
6207 * f.pread(12, 0) # => "First line\n"
6208 * # Read 9 bytes at offset 8.
6209 * f.pread(9, 8) # => "ne\nSecon"
6210 * f.close
6211 *
6212 * Not available on some platforms.
6213 *
6214 */
6215static VALUE
6216rb_io_pread(int argc, VALUE *argv, VALUE io)
6217{
6218 VALUE len, offset, str;
6219 rb_io_t *fptr;
6220 ssize_t n;
6221 struct prdwr_internal_arg arg;
6222 int shrinkable;
6223
6224 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6225 arg.count = NUM2SIZET(len);
6226 arg.offset = NUM2OFFT(offset);
6227
6228 shrinkable = io_setstrbuf(&str, (long)arg.count);
6229 if (arg.count == 0) return str;
6230 arg.buf = RSTRING_PTR(str);
6231
6232 GetOpenFile(io, fptr);
6234
6235 arg.io = fptr;
6236 arg.fd = fptr->fd;
6237 rb_io_check_closed(fptr);
6238
6239 rb_str_locktmp(str);
6240 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6241
6242 if (n < 0) {
6243 rb_sys_fail_path(fptr->pathv);
6244 }
6245 io_set_read_length(str, n, shrinkable);
6246 if (n == 0 && arg.count > 0) {
6247 rb_eof_error();
6248 }
6249
6250 return str;
6251}
6252
6253static VALUE
6254internal_pwrite_func(void *_arg)
6255{
6256 struct prdwr_internal_arg *arg = _arg;
6257
6258 VALUE scheduler = rb_fiber_scheduler_current();
6259 if (scheduler != Qnil) {
6260 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6261
6262 if (!UNDEF_P(result)) {
6264 }
6265 }
6266
6267
6268 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6269}
6270
6271/*
6272 * call-seq:
6273 * pwrite(object, offset) -> integer
6274 *
6275 * Behaves like IO#write, except that it:
6276 *
6277 * - Writes at the given +offset+ (in bytes).
6278 * - Disregards, and does not modify, the stream's position
6279 * (see {Position}[rdoc-ref:IO@Position]).
6280 * - Bypasses any user space buffering in the stream.
6281 *
6282 * Because this method does not disturb the stream's state
6283 * (its position, in particular), +pwrite+ allows multiple threads and processes
6284 * to use the same \IO object for writing at various offsets.
6285 *
6286 * f = File.open('t.tmp', 'w+')
6287 * # Write 6 bytes at offset 3.
6288 * f.pwrite('ABCDEF', 3) # => 6
6289 * f.rewind
6290 * f.read # => "\u0000\u0000\u0000ABCDEF"
6291 * f.close
6292 *
6293 * Not available on some platforms.
6294 *
6295 */
6296static VALUE
6297rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6298{
6299 rb_io_t *fptr;
6300 ssize_t n;
6301 struct prdwr_internal_arg arg;
6302 VALUE tmp;
6303
6304 if (!RB_TYPE_P(str, T_STRING))
6305 str = rb_obj_as_string(str);
6306
6307 arg.offset = NUM2OFFT(offset);
6308
6309 io = GetWriteIO(io);
6310 GetOpenFile(io, fptr);
6312
6313 arg.io = fptr;
6314 arg.fd = fptr->fd;
6315
6316 tmp = rb_str_tmp_frozen_acquire(str);
6317 arg.buf = RSTRING_PTR(tmp);
6318 arg.count = (size_t)RSTRING_LEN(tmp);
6319
6320 n = (ssize_t)rb_io_blocking_region_wait(fptr, internal_pwrite_func, &arg, RUBY_IO_WRITABLE);
6321 if (n < 0) rb_sys_fail_path(fptr->pathv);
6322 rb_str_tmp_frozen_release(str, tmp);
6323
6324 return SSIZET2NUM(n);
6325}
6326
6327VALUE
6329{
6330 rb_io_t *fptr;
6331
6332 GetOpenFile(io, fptr);
6333 if (fptr->readconv)
6335 if (fptr->writeconv)
6337 fptr->mode |= FMODE_BINMODE;
6338 fptr->mode &= ~FMODE_TEXTMODE;
6339 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6340#ifdef O_BINARY
6341 if (!fptr->readconv) {
6342 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6343 }
6344 else {
6345 setmode(fptr->fd, O_BINARY);
6346 }
6347#endif
6348 return io;
6349}
6350
6351static void
6352io_ascii8bit_binmode(rb_io_t *fptr)
6353{
6354 if (fptr->readconv) {
6355 rb_econv_close(fptr->readconv);
6356 fptr->readconv = NULL;
6357 }
6358 if (fptr->writeconv) {
6360 fptr->writeconv = NULL;
6361 }
6362 fptr->mode |= FMODE_BINMODE;
6363 fptr->mode &= ~FMODE_TEXTMODE;
6364 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6365
6366 fptr->encs.enc = rb_ascii8bit_encoding();
6367 fptr->encs.enc2 = NULL;
6368 fptr->encs.ecflags = 0;
6369 fptr->encs.ecopts = Qnil;
6370 clear_codeconv(fptr);
6371}
6372
6373VALUE
6375{
6376 rb_io_t *fptr;
6377
6378 GetOpenFile(io, fptr);
6379 io_ascii8bit_binmode(fptr);
6380
6381 return io;
6382}
6383
6384/*
6385 * call-seq:
6386 * binmode -> self
6387 *
6388 * Sets the stream's data mode as binary
6389 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6390 *
6391 * A stream's data mode may not be changed from binary to text.
6392 *
6393 */
6394
6395static VALUE
6396rb_io_binmode_m(VALUE io)
6397{
6398 VALUE write_io;
6399
6401
6402 write_io = GetWriteIO(io);
6403 if (write_io != io)
6404 rb_io_ascii8bit_binmode(write_io);
6405 return io;
6406}
6407
6408/*
6409 * call-seq:
6410 * binmode? -> true or false
6411 *
6412 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6413 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6414 *
6415 */
6416static VALUE
6417rb_io_binmode_p(VALUE io)
6418{
6419 rb_io_t *fptr;
6420 GetOpenFile(io, fptr);
6421 return RBOOL(fptr->mode & FMODE_BINMODE);
6422}
6423
6424static const char*
6425rb_io_fmode_modestr(enum rb_io_mode fmode)
6426{
6427 if (fmode & FMODE_APPEND) {
6428 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6429 return MODE_BTMODE("a+", "ab+", "at+");
6430 }
6431 return MODE_BTMODE("a", "ab", "at");
6432 }
6433 switch (fmode & FMODE_READWRITE) {
6434 default:
6435 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6436 case FMODE_READABLE:
6437 return MODE_BTMODE("r", "rb", "rt");
6438 case FMODE_WRITABLE:
6439 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6440 case FMODE_READWRITE:
6441 if (fmode & FMODE_CREATE) {
6442 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6443 }
6444 return MODE_BTMODE("r+", "rb+", "rt+");
6445 }
6446}
6447
6448static const char bom_prefix[] = "bom|";
6449static const char utf_prefix[] = "utf-";
6450enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6451enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6452
6453static int
6454io_encname_bom_p(const char *name, long len)
6455{
6456 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6457}
6458
6459enum rb_io_mode
6460rb_io_modestr_fmode(const char *modestr)
6461{
6462 enum rb_io_mode fmode = 0;
6463 const char *m = modestr, *p = NULL;
6464
6465 switch (*m++) {
6466 case 'r':
6467 fmode |= FMODE_READABLE;
6468 break;
6469 case 'w':
6471 break;
6472 case 'a':
6474 break;
6475 default:
6476 goto error;
6477 }
6478
6479 while (*m) {
6480 switch (*m++) {
6481 case 'b':
6482 fmode |= FMODE_BINMODE;
6483 break;
6484 case 't':
6485 fmode |= FMODE_TEXTMODE;
6486 break;
6487 case '+':
6488 fmode |= FMODE_READWRITE;
6489 break;
6490 case 'x':
6491 if (modestr[0] != 'w')
6492 goto error;
6493 fmode |= FMODE_EXCL;
6494 break;
6495 default:
6496 goto error;
6497 case ':':
6498 p = strchr(m, ':');
6499 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6500 fmode |= FMODE_SETENC_BY_BOM;
6501 goto finished;
6502 }
6503 }
6504
6505 finished:
6506 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6507 goto error;
6508
6509 return fmode;
6510
6511 error:
6512 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6514}
6515
6516int
6517rb_io_oflags_fmode(int oflags)
6518{
6519 enum rb_io_mode fmode = 0;
6520
6521 switch (oflags & O_ACCMODE) {
6522 case O_RDONLY:
6523 fmode = FMODE_READABLE;
6524 break;
6525 case O_WRONLY:
6526 fmode = FMODE_WRITABLE;
6527 break;
6528 case O_RDWR:
6529 fmode = FMODE_READWRITE;
6530 break;
6531 }
6532
6533 if (oflags & O_APPEND) {
6534 fmode |= FMODE_APPEND;
6535 }
6536 if (oflags & O_TRUNC) {
6537 fmode |= FMODE_TRUNC;
6538 }
6539 if (oflags & O_CREAT) {
6540 fmode |= FMODE_CREATE;
6541 }
6542 if (oflags & O_EXCL) {
6543 fmode |= FMODE_EXCL;
6544 }
6545#ifdef O_BINARY
6546 if (oflags & O_BINARY) {
6547 fmode |= FMODE_BINMODE;
6548 }
6549#endif
6550
6551 return fmode;
6552}
6553
6554static int
6555rb_io_fmode_oflags(enum rb_io_mode fmode)
6556{
6557 int oflags = 0;
6558
6559 switch (fmode & FMODE_READWRITE) {
6560 case FMODE_READABLE:
6561 oflags |= O_RDONLY;
6562 break;
6563 case FMODE_WRITABLE:
6564 oflags |= O_WRONLY;
6565 break;
6566 case FMODE_READWRITE:
6567 oflags |= O_RDWR;
6568 break;
6569 }
6570
6571 if (fmode & FMODE_APPEND) {
6572 oflags |= O_APPEND;
6573 }
6574 if (fmode & FMODE_TRUNC) {
6575 oflags |= O_TRUNC;
6576 }
6577 if (fmode & FMODE_CREATE) {
6578 oflags |= O_CREAT;
6579 }
6580 if (fmode & FMODE_EXCL) {
6581 oflags |= O_EXCL;
6582 }
6583#ifdef O_BINARY
6584 if (fmode & FMODE_BINMODE) {
6585 oflags |= O_BINARY;
6586 }
6587#endif
6588
6589 return oflags;
6590}
6591
6592int
6593rb_io_modestr_oflags(const char *modestr)
6594{
6595 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6596}
6597
6598static const char*
6599rb_io_oflags_modestr(int oflags)
6600{
6601#ifdef O_BINARY
6602# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6603#else
6604# define MODE_BINARY(a,b) (a)
6605#endif
6606 int accmode;
6607 if (oflags & O_EXCL) {
6608 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6609 }
6610 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6611 if (oflags & O_APPEND) {
6612 if (accmode == O_WRONLY) {
6613 return MODE_BINARY("a", "ab");
6614 }
6615 if (accmode == O_RDWR) {
6616 return MODE_BINARY("a+", "ab+");
6617 }
6618 }
6619 switch (accmode) {
6620 default:
6621 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6622 case O_RDONLY:
6623 return MODE_BINARY("r", "rb");
6624 case O_WRONLY:
6625 return MODE_BINARY("w", "wb");
6626 case O_RDWR:
6627 if (oflags & O_TRUNC) {
6628 return MODE_BINARY("w+", "wb+");
6629 }
6630 return MODE_BINARY("r+", "rb+");
6631 }
6632}
6633
6634/*
6635 * Convert external/internal encodings to enc/enc2
6636 * NULL => use default encoding
6637 * Qnil => no encoding specified (internal only)
6638 */
6639static void
6640rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6641{
6642 int default_ext = 0;
6643
6644 if (ext == NULL) {
6645 ext = rb_default_external_encoding();
6646 default_ext = 1;
6647 }
6648 if (rb_is_ascii8bit_enc(ext)) {
6649 /* If external is ASCII-8BIT, no transcoding */
6650 intern = NULL;
6651 }
6652 else if (intern == NULL) {
6653 intern = rb_default_internal_encoding();
6654 }
6655 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6656 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6657 /* No internal encoding => use external + no transcoding */
6658 *enc = (default_ext && intern != ext) ? NULL : ext;
6659 *enc2 = NULL;
6660 }
6661 else {
6662 *enc = intern;
6663 *enc2 = ext;
6664 }
6665}
6666
6667static void
6668unsupported_encoding(const char *name, rb_encoding *enc)
6669{
6670 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6671}
6672
6673static void
6674parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6675 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6676{
6677 const char *p;
6678 char encname[ENCODING_MAXNAMELEN+1];
6679 int idx, idx2;
6680 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6681 rb_encoding *ext_enc, *int_enc;
6682 long len;
6683
6684 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6685
6686 p = strrchr(estr, ':');
6687 len = p ? (p++ - estr) : (long)strlen(estr);
6688 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6689 estr += bom_prefix_len;
6690 len -= bom_prefix_len;
6691 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6692 fmode |= FMODE_SETENC_BY_BOM;
6693 }
6694 else {
6695 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6696 fmode &= ~FMODE_SETENC_BY_BOM;
6697 }
6698 }
6699 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6700 idx = -1;
6701 }
6702 else {
6703 if (p) {
6704 memcpy(encname, estr, len);
6705 encname[len] = '\0';
6706 estr = encname;
6707 }
6708 idx = rb_enc_find_index(estr);
6709 }
6710 if (fmode_p) *fmode_p = fmode;
6711
6712 if (idx >= 0)
6713 ext_enc = rb_enc_from_index(idx);
6714 else {
6715 if (idx != -2)
6716 unsupported_encoding(estr, estr_enc);
6717 ext_enc = NULL;
6718 }
6719
6720 int_enc = NULL;
6721 if (p) {
6722 if (*p == '-' && *(p+1) == '\0') {
6723 /* Special case - "-" => no transcoding */
6724 int_enc = (rb_encoding *)Qnil;
6725 }
6726 else {
6727 idx2 = rb_enc_find_index(p);
6728 if (idx2 < 0)
6729 unsupported_encoding(p, estr_enc);
6730 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6731 int_enc = (rb_encoding *)Qnil;
6732 }
6733 else
6734 int_enc = rb_enc_from_index(idx2);
6735 }
6736 }
6737
6738 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6739}
6740
6741int
6742rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6743{
6744 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6745 int extracted = 0;
6746 rb_encoding *extencoding = NULL;
6747 rb_encoding *intencoding = NULL;
6748
6749 if (!NIL_P(opt)) {
6750 VALUE v;
6751 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6752 if (v != Qnil) encoding = v;
6753 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6754 if (v != Qnil) extenc = v;
6755 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6756 if (!UNDEF_P(v)) intenc = v;
6757 }
6758 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6759 if (!NIL_P(ruby_verbose)) {
6760 int idx = rb_to_encoding_index(encoding);
6761 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6762 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6763 encoding, UNDEF_P(extenc) ? "internal" : "external");
6764 }
6765 encoding = Qnil;
6766 }
6767 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6768 extencoding = rb_to_encoding(extenc);
6769 }
6770 if (!UNDEF_P(intenc)) {
6771 if (NIL_P(intenc)) {
6772 /* internal_encoding: nil => no transcoding */
6773 intencoding = (rb_encoding *)Qnil;
6774 }
6775 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6776 char *p = StringValueCStr(tmp);
6777
6778 if (*p == '-' && *(p+1) == '\0') {
6779 /* Special case - "-" => no transcoding */
6780 intencoding = (rb_encoding *)Qnil;
6781 }
6782 else {
6783 intencoding = rb_to_encoding(intenc);
6784 }
6785 }
6786 else {
6787 intencoding = rb_to_encoding(intenc);
6788 }
6789 if (extencoding == intencoding) {
6790 intencoding = (rb_encoding *)Qnil;
6791 }
6792 }
6793 if (!NIL_P(encoding)) {
6794 extracted = 1;
6795 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6796 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6797 enc_p, enc2_p, fmode_p);
6798 }
6799 else {
6800 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6801 }
6802 }
6803 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6804 extracted = 1;
6805 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6806 }
6807 return extracted;
6808}
6809
6810static void
6811validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6812{
6813 enum rb_io_mode fmode = *fmode_p;
6814
6815 if ((fmode & FMODE_READABLE) &&
6816 !enc2 &&
6817 !(fmode & FMODE_BINMODE) &&
6818 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6819 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6820
6821 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6822 rb_raise(rb_eArgError, "newline decorator with binary mode");
6823 }
6824 if (!(fmode & FMODE_BINMODE) &&
6825 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6826 fmode |= FMODE_TEXTMODE;
6827 *fmode_p = fmode;
6828 }
6829#if !DEFAULT_TEXTMODE
6830 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6831 fmode &= ~FMODE_TEXTMODE;
6832 *fmode_p = fmode;
6833 }
6834#endif
6835}
6836
6837static void
6838extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
6839{
6840 if (!NIL_P(opthash)) {
6841 VALUE v;
6842 v = rb_hash_aref(opthash, sym_textmode);
6843 if (!NIL_P(v)) {
6844 if (*fmode & FMODE_TEXTMODE)
6845 rb_raise(rb_eArgError, "textmode specified twice");
6846 if (*fmode & FMODE_BINMODE)
6847 rb_raise(rb_eArgError, "both textmode and binmode specified");
6848 if (RTEST(v))
6849 *fmode |= FMODE_TEXTMODE;
6850 }
6851 v = rb_hash_aref(opthash, sym_binmode);
6852 if (!NIL_P(v)) {
6853 if (*fmode & FMODE_BINMODE)
6854 rb_raise(rb_eArgError, "binmode specified twice");
6855 if (*fmode & FMODE_TEXTMODE)
6856 rb_raise(rb_eArgError, "both textmode and binmode specified");
6857 if (RTEST(v))
6858 *fmode |= FMODE_BINMODE;
6859 }
6860
6861 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6862 rb_raise(rb_eArgError, "both textmode and binmode specified");
6863 }
6864}
6865
6866void
6867rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6868 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
6869{
6870 VALUE vmode;
6871 int oflags;
6872 enum rb_io_mode fmode;
6873 rb_encoding *enc, *enc2;
6874 int ecflags;
6875 VALUE ecopts;
6876 int has_enc = 0, has_vmode = 0;
6877 VALUE intmode;
6878
6879 vmode = *vmode_p;
6880
6881 /* Set to defaults */
6882 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6883
6884 vmode_handle:
6885 if (NIL_P(vmode)) {
6886 fmode = FMODE_READABLE;
6887 oflags = O_RDONLY;
6888 }
6889 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6890 vmode = intmode;
6891 oflags = NUM2INT(intmode);
6892 fmode = rb_io_oflags_fmode(oflags);
6893 }
6894 else {
6895 const char *p;
6896
6897 StringValue(vmode);
6898 p = StringValueCStr(vmode);
6899 fmode = rb_io_modestr_fmode(p);
6900 oflags = rb_io_fmode_oflags(fmode);
6901 p = strchr(p, ':');
6902 if (p) {
6903 has_enc = 1;
6904 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6905 }
6906 else {
6907 rb_encoding *e;
6908
6909 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6910 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6911 }
6912 }
6913
6914 if (NIL_P(opthash)) {
6915 ecflags = (fmode & FMODE_READABLE) ?
6918#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6919 ecflags |= (fmode & FMODE_WRITABLE) ?
6920 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6921 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6922#endif
6923 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6924 ecopts = Qnil;
6925 if (fmode & FMODE_BINMODE) {
6926#ifdef O_BINARY
6927 oflags |= O_BINARY;
6928#endif
6929 if (!has_enc)
6930 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6931 }
6932#if DEFAULT_TEXTMODE
6933 else if (NIL_P(vmode)) {
6934 fmode |= DEFAULT_TEXTMODE;
6935 }
6936#endif
6937 }
6938 else {
6939 VALUE v;
6940 if (!has_vmode) {
6941 v = rb_hash_aref(opthash, sym_mode);
6942 if (!NIL_P(v)) {
6943 if (!NIL_P(vmode)) {
6944 rb_raise(rb_eArgError, "mode specified twice");
6945 }
6946 has_vmode = 1;
6947 vmode = v;
6948 goto vmode_handle;
6949 }
6950 }
6951 v = rb_hash_aref(opthash, sym_flags);
6952 if (!NIL_P(v)) {
6953 v = rb_to_int(v);
6954 oflags |= NUM2INT(v);
6955 vmode = INT2NUM(oflags);
6956 fmode = rb_io_oflags_fmode(oflags);
6957 }
6958 extract_binmode(opthash, &fmode);
6959 if (fmode & FMODE_BINMODE) {
6960#ifdef O_BINARY
6961 oflags |= O_BINARY;
6962#endif
6963 if (!has_enc)
6964 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6965 }
6966#if DEFAULT_TEXTMODE
6967 else if (NIL_P(vmode)) {
6968 fmode |= DEFAULT_TEXTMODE;
6969 }
6970#endif
6971 v = rb_hash_aref(opthash, sym_perm);
6972 if (!NIL_P(v)) {
6973 if (vperm_p) {
6974 if (!NIL_P(*vperm_p)) {
6975 rb_raise(rb_eArgError, "perm specified twice");
6976 }
6977 *vperm_p = v;
6978 }
6979 else {
6980 /* perm no use, just ignore */
6981 }
6982 }
6983 ecflags = (fmode & FMODE_READABLE) ?
6986#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6987 ecflags |= (fmode & FMODE_WRITABLE) ?
6988 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6989 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6990#endif
6991
6992 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6993 if (has_enc) {
6994 rb_raise(rb_eArgError, "encoding specified twice");
6995 }
6996 }
6997 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6998 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
6999 }
7000
7001 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7002
7003 *vmode_p = vmode;
7004
7005 *oflags_p = oflags;
7006 *fmode_p = fmode;
7007 convconfig_p->enc = enc;
7008 convconfig_p->enc2 = enc2;
7009 convconfig_p->ecflags = ecflags;
7010 convconfig_p->ecopts = ecopts;
7011}
7012
7014 VALUE fname;
7015 int oflags;
7016 mode_t perm;
7017};
7018
7019static void *
7020sysopen_func(void *ptr)
7021{
7022 const struct sysopen_struct *data = ptr;
7023 const char *fname = RSTRING_PTR(data->fname);
7024 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7025}
7026
7027static inline int
7028rb_sysopen_internal(struct sysopen_struct *data)
7029{
7030 int fd;
7031 do {
7032 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7033 } while (fd < 0 && errno == EINTR);
7034 if (0 <= fd)
7035 rb_update_max_fd(fd);
7036 return fd;
7037}
7038
7039static int
7040rb_sysopen(VALUE fname, int oflags, mode_t perm)
7041{
7042 int fd = -1;
7043 struct sysopen_struct data;
7044
7045 data.fname = rb_str_encode_ospath(fname);
7046 StringValueCStr(data.fname);
7047 data.oflags = oflags;
7048 data.perm = perm;
7049
7050 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7051 rb_syserr_fail_path(first_errno, fname);
7052 }
7053 return fd;
7054}
7055
7056static inline FILE *
7057fdopen_internal(int fd, const char *modestr)
7058{
7059 FILE *file;
7060
7061#if defined(__sun)
7062 errno = 0;
7063#endif
7064 file = fdopen(fd, modestr);
7065 if (!file) {
7066#ifdef _WIN32
7067 if (errno == 0) errno = EINVAL;
7068#elif defined(__sun)
7069 if (errno == 0) errno = EMFILE;
7070#endif
7071 }
7072 return file;
7073}
7074
7075FILE *
7076rb_fdopen(int fd, const char *modestr)
7077{
7078 FILE *file = 0;
7079
7080 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7081 rb_syserr_fail(first_errno, 0);
7082 }
7083
7084 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7085#ifdef USE_SETVBUF
7086 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7087 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7088#endif
7089 return file;
7090}
7091
7092static int
7093io_check_tty(rb_io_t *fptr)
7094{
7095 int t = isatty(fptr->fd);
7096 if (t)
7097 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7098 return t;
7099}
7100
7101static VALUE rb_io_internal_encoding(VALUE);
7102static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7103
7104static int
7105io_strip_bom(VALUE io)
7106{
7107 VALUE b1, b2, b3, b4;
7108 rb_io_t *fptr;
7109
7110 GetOpenFile(io, fptr);
7111 if (!(fptr->mode & FMODE_READABLE)) return 0;
7112 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7113 switch (b1) {
7114 case INT2FIX(0xEF):
7115 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7116 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7117 if (b3 == INT2FIX(0xBF)) {
7118 return rb_utf8_encindex();
7119 }
7120 rb_io_ungetbyte(io, b3);
7121 }
7122 rb_io_ungetbyte(io, b2);
7123 break;
7124
7125 case INT2FIX(0xFE):
7126 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7127 if (b2 == INT2FIX(0xFF)) {
7128 return ENCINDEX_UTF_16BE;
7129 }
7130 rb_io_ungetbyte(io, b2);
7131 break;
7132
7133 case INT2FIX(0xFF):
7134 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7135 if (b2 == INT2FIX(0xFE)) {
7136 b3 = rb_io_getbyte(io);
7137 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7138 if (b4 == INT2FIX(0)) {
7139 return ENCINDEX_UTF_32LE;
7140 }
7141 rb_io_ungetbyte(io, b4);
7142 }
7143 rb_io_ungetbyte(io, b3);
7144 return ENCINDEX_UTF_16LE;
7145 }
7146 rb_io_ungetbyte(io, b2);
7147 break;
7148
7149 case INT2FIX(0):
7150 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7151 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7152 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7153 if (b4 == INT2FIX(0xFF)) {
7154 return ENCINDEX_UTF_32BE;
7155 }
7156 rb_io_ungetbyte(io, b4);
7157 }
7158 rb_io_ungetbyte(io, b3);
7159 }
7160 rb_io_ungetbyte(io, b2);
7161 break;
7162 }
7163 rb_io_ungetbyte(io, b1);
7164 return 0;
7165}
7166
7167static rb_encoding *
7168io_set_encoding_by_bom(VALUE io)
7169{
7170 int idx = io_strip_bom(io);
7171 rb_io_t *fptr;
7172 rb_encoding *extenc = NULL;
7173
7174 GetOpenFile(io, fptr);
7175 if (idx) {
7176 extenc = rb_enc_from_index(idx);
7177 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7178 rb_io_internal_encoding(io), Qnil);
7179 }
7180 else {
7181 fptr->encs.enc2 = NULL;
7182 }
7183 return extenc;
7184}
7185
7186static VALUE
7187rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7188 const struct rb_io_encoding *convconfig, mode_t perm)
7189{
7190 VALUE pathv;
7191 rb_io_t *fptr;
7192 struct rb_io_encoding cc;
7193 if (!convconfig) {
7194 /* Set to default encodings */
7195 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7196 cc.ecflags = 0;
7197 cc.ecopts = Qnil;
7198 convconfig = &cc;
7199 }
7200 validate_enc_binmode(&fmode, convconfig->ecflags,
7201 convconfig->enc, convconfig->enc2);
7202
7203 MakeOpenFile(io, fptr);
7204 fptr->mode = fmode;
7205 fptr->encs = *convconfig;
7206 pathv = rb_str_new_frozen(filename);
7207#ifdef O_TMPFILE
7208 if (!(oflags & O_TMPFILE)) {
7209 fptr->pathv = pathv;
7210 }
7211#else
7212 fptr->pathv = pathv;
7213#endif
7214 fptr->fd = rb_sysopen(pathv, oflags, perm);
7215 io_check_tty(fptr);
7216 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7217
7218 return io;
7219}
7220
7221static VALUE
7222rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7223{
7224 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7225 const char *p = strchr(modestr, ':');
7226 struct rb_io_encoding convconfig;
7227
7228 if (p) {
7229 parse_mode_enc(p+1, rb_usascii_encoding(),
7230 &convconfig.enc, &convconfig.enc2, &fmode);
7231 }
7232 else {
7233 rb_encoding *e;
7234 /* Set to default encodings */
7235
7236 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7237 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7238 }
7239
7240 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7243#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7244 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7245 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7246 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7247#endif
7248 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7249 convconfig.ecopts = Qnil;
7250
7251 return rb_file_open_generic(io, filename,
7252 rb_io_fmode_oflags(fmode),
7253 fmode,
7254 &convconfig,
7255 0666);
7256}
7257
7258VALUE
7259rb_file_open_str(VALUE fname, const char *modestr)
7260{
7261 FilePathValue(fname);
7262 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7263}
7264
7265VALUE
7266rb_file_open(const char *fname, const char *modestr)
7267{
7268 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7269}
7270
7271#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7272static struct pipe_list {
7273 rb_io_t *fptr;
7274 struct pipe_list *next;
7275} *pipe_list;
7276
7277static void
7278pipe_add_fptr(rb_io_t *fptr)
7279{
7280 struct pipe_list *list;
7281
7282 list = ALLOC(struct pipe_list);
7283 list->fptr = fptr;
7284 list->next = pipe_list;
7285 pipe_list = list;
7286}
7287
7288static void
7289pipe_del_fptr(rb_io_t *fptr)
7290{
7291 struct pipe_list **prev = &pipe_list;
7292 struct pipe_list *tmp;
7293
7294 while ((tmp = *prev) != 0) {
7295 if (tmp->fptr == fptr) {
7296 *prev = tmp->next;
7297 free(tmp);
7298 return;
7299 }
7300 prev = &tmp->next;
7301 }
7302}
7303
7304#if defined (_WIN32) || defined(__CYGWIN__)
7305static void
7306pipe_atexit(void)
7307{
7308 struct pipe_list *list = pipe_list;
7309 struct pipe_list *tmp;
7310
7311 while (list) {
7312 tmp = list->next;
7313 rb_io_fptr_finalize(list->fptr);
7314 list = tmp;
7315 }
7316}
7317#endif
7318
7319static void
7320pipe_finalize(rb_io_t *fptr, int noraise)
7321{
7322#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7323 int status = 0;
7324 if (fptr->stdio_file) {
7325 status = pclose(fptr->stdio_file);
7326 }
7327 fptr->fd = -1;
7328 fptr->stdio_file = 0;
7329 rb_last_status_set(status, fptr->pid);
7330#else
7331 fptr_finalize(fptr, noraise);
7332#endif
7333 pipe_del_fptr(fptr);
7334}
7335#endif
7336
7337static void
7338fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7339{
7340#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7341 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7342
7343 if (old_finalize == orig->finalize) return;
7344#endif
7345
7346 fptr->finalize = orig->finalize;
7347
7348#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7349 if (old_finalize != pipe_finalize) {
7350 struct pipe_list *list;
7351 for (list = pipe_list; list; list = list->next) {
7352 if (list->fptr == fptr) break;
7353 }
7354 if (!list) pipe_add_fptr(fptr);
7355 }
7356 else {
7357 pipe_del_fptr(fptr);
7358 }
7359#endif
7360}
7361
7362void
7364{
7366 fptr->mode |= FMODE_SYNC;
7367}
7368
7369void
7370rb_io_unbuffered(rb_io_t *fptr)
7371{
7372 rb_io_synchronized(fptr);
7373}
7374
7375int
7376rb_pipe(int *pipes)
7377{
7378 int ret;
7379 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7380 if (ret == 0) {
7381 rb_update_max_fd(pipes[0]);
7382 rb_update_max_fd(pipes[1]);
7383 }
7384 return ret;
7385}
7386
7387#ifdef _WIN32
7388#define HAVE_SPAWNV 1
7389#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7390#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7391#endif
7392
7393#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7394struct popen_arg {
7395 VALUE execarg_obj;
7396 struct rb_execarg *eargp;
7397 int modef;
7398 int pair[2];
7399 int write_pair[2];
7400};
7401#endif
7402
7403#ifdef HAVE_WORKING_FORK
7404# ifndef __EMSCRIPTEN__
7405static void
7406popen_redirect(struct popen_arg *p)
7407{
7408 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7409 close(p->write_pair[1]);
7410 if (p->write_pair[0] != 0) {
7411 dup2(p->write_pair[0], 0);
7412 close(p->write_pair[0]);
7413 }
7414 close(p->pair[0]);
7415 if (p->pair[1] != 1) {
7416 dup2(p->pair[1], 1);
7417 close(p->pair[1]);
7418 }
7419 }
7420 else if (p->modef & FMODE_READABLE) {
7421 close(p->pair[0]);
7422 if (p->pair[1] != 1) {
7423 dup2(p->pair[1], 1);
7424 close(p->pair[1]);
7425 }
7426 }
7427 else {
7428 close(p->pair[1]);
7429 if (p->pair[0] != 0) {
7430 dup2(p->pair[0], 0);
7431 close(p->pair[0]);
7432 }
7433 }
7434}
7435# endif
7436
7437#if defined(__linux__)
7438/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7439 * Since /proc may not be available, linux_get_maxfd is just a hint.
7440 * This function, linux_get_maxfd, must be async-signal-safe.
7441 * I.e. opendir() is not usable.
7442 *
7443 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7444 * However they are easy to re-implement in async-signal-safe manner.
7445 * (Also note that there is missing/memcmp.c.)
7446 */
7447static int
7448linux_get_maxfd(void)
7449{
7450 int fd;
7451 char buf[4096], *p, *np, *e;
7452 ssize_t ss;
7453 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7454 if (fd < 0) return fd;
7455 ss = read(fd, buf, sizeof(buf));
7456 if (ss < 0) goto err;
7457 p = buf;
7458 e = buf + ss;
7459 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7460 (np = memchr(p, '\n', e-p)) != NULL) {
7461 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7462 int fdsize;
7463 p += sizeof("FDSize:")-1;
7464 *np = '\0';
7465 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7466 close(fd);
7467 return fdsize;
7468 }
7469 p = np+1;
7470 }
7471 /* fall through */
7472
7473 err:
7474 close(fd);
7475 return (int)ss;
7476}
7477#endif
7478
7479/* This function should be async-signal-safe. */
7480void
7481rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7482{
7483#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7484 int fd, ret;
7485 int max = (int)max_file_descriptor;
7486# ifdef F_MAXFD
7487 /* F_MAXFD is available since NetBSD 2.0. */
7488 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7489 if (ret != -1)
7490 maxhint = max = ret;
7491# elif defined(__linux__)
7492 ret = linux_get_maxfd();
7493 if (maxhint < ret)
7494 maxhint = ret;
7495 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7496# endif
7497 if (max < maxhint)
7498 max = maxhint;
7499 for (fd = lowfd; fd <= max; fd++) {
7500 if (!NIL_P(noclose_fds) &&
7501 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7502 continue;
7503 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7504 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7505 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7506 }
7507# define CONTIGUOUS_CLOSED_FDS 20
7508 if (ret != -1) {
7509 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7510 max = fd + CONTIGUOUS_CLOSED_FDS;
7511 }
7512 }
7513#endif
7514}
7515
7516# ifndef __EMSCRIPTEN__
7517static int
7518popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7519{
7520 struct popen_arg *p = (struct popen_arg*)pp;
7521
7522 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7523}
7524# endif
7525#endif
7526
7527#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7528static VALUE
7529rb_execarg_fixup_v(VALUE execarg_obj)
7530{
7531 rb_execarg_parent_start(execarg_obj);
7532 return Qnil;
7533}
7534#else
7535char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7536#endif
7537
7538#ifndef __EMSCRIPTEN__
7539static VALUE
7540pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7541 const struct rb_io_encoding *convconfig)
7542{
7543 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7544 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7545 rb_pid_t pid = 0;
7546 rb_io_t *fptr;
7547 VALUE port;
7548 rb_io_t *write_fptr;
7549 VALUE write_port;
7550#if defined(HAVE_WORKING_FORK)
7551 int status;
7552 char errmsg[80] = { '\0' };
7553#endif
7554#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7555 int state;
7556 struct popen_arg arg;
7557#endif
7558 int e = 0;
7559#if defined(HAVE_SPAWNV)
7560# if defined(HAVE_SPAWNVE)
7561# define DO_SPAWN(cmd, args, envp) ((args) ? \
7562 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7563 spawne(P_NOWAIT, (cmd), (envp)))
7564# else
7565# define DO_SPAWN(cmd, args, envp) ((args) ? \
7566 spawnv(P_NOWAIT, (cmd), (args)) : \
7567 spawn(P_NOWAIT, (cmd)))
7568# endif
7569# if !defined(HAVE_WORKING_FORK)
7570 char **args = NULL;
7571# if defined(HAVE_SPAWNVE)
7572 char **envp = NULL;
7573# endif
7574# endif
7575#endif
7576#if !defined(HAVE_WORKING_FORK)
7577 struct rb_execarg sarg, *sargp = &sarg;
7578#endif
7579 FILE *fp = 0;
7580 int fd = -1;
7581 int write_fd = -1;
7582#if !defined(HAVE_WORKING_FORK)
7583 const char *cmd = 0;
7584
7585 if (prog)
7586 cmd = StringValueCStr(prog);
7587#endif
7588
7589#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7590 arg.execarg_obj = execarg_obj;
7591 arg.eargp = eargp;
7592 arg.modef = fmode;
7593 arg.pair[0] = arg.pair[1] = -1;
7594 arg.write_pair[0] = arg.write_pair[1] = -1;
7595# if !defined(HAVE_WORKING_FORK)
7596 if (eargp && !eargp->use_shell) {
7597 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7598 }
7599# endif
7600 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7602 if (rb_pipe(arg.write_pair) < 0)
7603 rb_sys_fail_str(prog);
7604 if (rb_pipe(arg.pair) < 0) {
7605 e = errno;
7606 close(arg.write_pair[0]);
7607 close(arg.write_pair[1]);
7608 rb_syserr_fail_str(e, prog);
7609 }
7610 if (eargp) {
7611 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7612 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7613 }
7614 break;
7615 case FMODE_READABLE:
7616 if (rb_pipe(arg.pair) < 0)
7617 rb_sys_fail_str(prog);
7618 if (eargp)
7619 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7620 break;
7621 case FMODE_WRITABLE:
7622 if (rb_pipe(arg.pair) < 0)
7623 rb_sys_fail_str(prog);
7624 if (eargp)
7625 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7626 break;
7627 default:
7628 rb_sys_fail_str(prog);
7629 }
7630 if (!NIL_P(execarg_obj)) {
7631 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7632 if (state) {
7633 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7634 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7635 if (0 <= arg.pair[0]) close(arg.pair[0]);
7636 if (0 <= arg.pair[1]) close(arg.pair[1]);
7637 rb_execarg_parent_end(execarg_obj);
7638 rb_jump_tag(state);
7639 }
7640
7641# if defined(HAVE_WORKING_FORK)
7642 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7643# else
7644 rb_execarg_run_options(eargp, sargp, NULL, 0);
7645# if defined(HAVE_SPAWNVE)
7646 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7647# endif
7648 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7649 /* exec failed */
7650 switch (e = errno) {
7651 case EAGAIN:
7652# if EWOULDBLOCK != EAGAIN
7653 case EWOULDBLOCK:
7654# endif
7655 rb_thread_sleep(1);
7656 continue;
7657 }
7658 break;
7659 }
7660 if (eargp)
7661 rb_execarg_run_options(sargp, NULL, NULL, 0);
7662# endif
7663 rb_execarg_parent_end(execarg_obj);
7664 }
7665 else {
7666# if defined(HAVE_WORKING_FORK)
7667 pid = rb_call_proc__fork();
7668 if (pid == 0) { /* child */
7669 popen_redirect(&arg);
7670 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7671 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7672 return Qnil;
7673 }
7674# else
7676# endif
7677 }
7678
7679 /* parent */
7680 if (pid < 0) {
7681# if defined(HAVE_WORKING_FORK)
7682 e = errno;
7683# endif
7684 close(arg.pair[0]);
7685 close(arg.pair[1]);
7687 close(arg.write_pair[0]);
7688 close(arg.write_pair[1]);
7689 }
7690# if defined(HAVE_WORKING_FORK)
7691 if (errmsg[0])
7692 rb_syserr_fail(e, errmsg);
7693# endif
7694 rb_syserr_fail_str(e, prog);
7695 }
7696 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7697 close(arg.pair[1]);
7698 fd = arg.pair[0];
7699 close(arg.write_pair[0]);
7700 write_fd = arg.write_pair[1];
7701 }
7702 else if (fmode & FMODE_READABLE) {
7703 close(arg.pair[1]);
7704 fd = arg.pair[0];
7705 }
7706 else {
7707 close(arg.pair[0]);
7708 fd = arg.pair[1];
7709 }
7710#else
7711 cmd = rb_execarg_commandline(eargp, &prog);
7712 if (!NIL_P(execarg_obj)) {
7713 rb_execarg_parent_start(execarg_obj);
7714 rb_execarg_run_options(eargp, sargp, NULL, 0);
7715 }
7716 fp = popen(cmd, modestr);
7717 e = errno;
7718 if (eargp) {
7719 rb_execarg_parent_end(execarg_obj);
7720 rb_execarg_run_options(sargp, NULL, NULL, 0);
7721 }
7722 if (!fp) rb_syserr_fail_path(e, prog);
7723 fd = fileno(fp);
7724#endif
7725
7726 port = io_alloc(rb_cIO);
7727 MakeOpenFile(port, fptr);
7728 fptr->fd = fd;
7729 fptr->stdio_file = fp;
7730 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7731 if (convconfig) {
7732 fptr->encs = *convconfig;
7733#if RUBY_CRLF_ENVIRONMENT
7736 }
7737#endif
7738 }
7739 else {
7740 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7742 }
7743#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7744 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7745 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7746 }
7747#endif
7748 }
7749 fptr->pid = pid;
7750
7751 if (0 <= write_fd) {
7752 write_port = io_alloc(rb_cIO);
7753 MakeOpenFile(write_port, write_fptr);
7754 write_fptr->fd = write_fd;
7755 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7756 fptr->mode &= ~FMODE_WRITABLE;
7757 fptr->tied_io_for_writing = write_port;
7758 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7759 }
7760
7761#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7762 fptr->finalize = pipe_finalize;
7763 pipe_add_fptr(fptr);
7764#endif
7765 return port;
7766}
7767#else
7768static VALUE
7769pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7770 const struct rb_io_encoding *convconfig)
7771{
7772 rb_raise(rb_eNotImpError, "popen() is not available");
7773}
7774#endif
7775
7776static int
7777is_popen_fork(VALUE prog)
7778{
7779 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7780#if !defined(HAVE_WORKING_FORK)
7781 rb_raise(rb_eNotImpError,
7782 "fork() function is unimplemented on this machine");
7783#else
7784 return TRUE;
7785#endif
7786 }
7787 return FALSE;
7788}
7789
7790static VALUE
7791pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
7792 const struct rb_io_encoding *convconfig)
7793{
7794 int argc = 1;
7795 VALUE *argv = &prog;
7796 VALUE execarg_obj = Qnil;
7797
7798 if (!is_popen_fork(prog))
7799 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7800 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7801}
7802
7803static VALUE
7804pipe_close(VALUE io)
7805{
7806 rb_io_t *fptr = io_close_fptr(io);
7807 if (fptr) {
7808 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7809 }
7810 return Qnil;
7811}
7812
7813static VALUE popen_finish(VALUE port, VALUE klass);
7814
7815/*
7816 * call-seq:
7817 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7818 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7819 *
7820 * Executes the given command +cmd+ as a subprocess
7821 * whose $stdin and $stdout are connected to a new stream +io+.
7822 *
7823 * This method has potential security vulnerabilities if called with untrusted input;
7824 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
7825 *
7826 * If no block is given, returns the new stream,
7827 * which depending on given +mode+ may be open for reading, writing, or both.
7828 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7829 *
7830 * If a block is given, the stream is passed to the block
7831 * (again, open for reading, writing, or both);
7832 * when the block exits, the stream is closed,
7833 * and the block's value is assigned to global variable <tt>$?</tt> and returned.
7834 *
7835 * Optional argument +mode+ may be any valid \IO mode.
7836 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7837 *
7838 * Required argument +cmd+ determines which of the following occurs:
7839 *
7840 * - The process forks.
7841 * - A specified program runs in a shell.
7842 * - A specified program runs with specified arguments.
7843 * - A specified program runs with specified arguments and a specified +argv0+.
7844 *
7845 * Each of these is detailed below.
7846 *
7847 * The optional hash argument +env+ specifies name/value pairs that are to be added
7848 * to the environment variables for the subprocess:
7849 *
7850 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7851 * pipe.puts 'puts ENV["FOO"]'
7852 * pipe.close_write
7853 * pipe.gets
7854 * end => "bar\n"
7855 *
7856 * Optional keyword arguments +opts+ specify:
7857 *
7858 * - {Open options}[rdoc-ref:IO@Open+Options].
7859 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7860 * - Options for Kernel#spawn.
7861 *
7862 * <b>Forked Process</b>
7863 *
7864 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7865 * IO.popen('-') do |pipe|
7866 * if pipe
7867 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7868 * else
7869 * $stderr.puts "In child, pid is #{$$}\n"
7870 * end
7871 * end
7872 *
7873 * Output:
7874 *
7875 * In parent, child pid is 26253
7876 * In child, pid is 26253
7877 *
7878 * Note that this is not supported on all platforms.
7879 *
7880 * <b>Shell Subprocess</b>
7881 *
7882 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7883 * the program named +cmd+ is run as a shell command:
7884 *
7885 * IO.popen('uname') do |pipe|
7886 * pipe.readlines
7887 * end
7888 *
7889 * Output:
7890 *
7891 * ["Linux\n"]
7892 *
7893 * Another example:
7894 *
7895 * IO.popen('/bin/sh', 'r+') do |pipe|
7896 * pipe.puts('ls')
7897 * pipe.close_write
7898 * $stderr.puts pipe.readlines.size
7899 * end
7900 *
7901 * Output:
7902 *
7903 * 213
7904 *
7905 * <b>Program Subprocess</b>
7906 *
7907 * When argument +cmd+ is an array of strings,
7908 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7909 *
7910 * IO.popen(['du', '..', '.']) do |pipe|
7911 * $stderr.puts pipe.readlines.size
7912 * end
7913 *
7914 * Output:
7915 *
7916 * 1111
7917 *
7918 * <b>Program Subprocess with <tt>argv0</tt></b>
7919 *
7920 * When argument +cmd+ is an array whose first element is a 2-element string array
7921 * and whose remaining elements (if any) are strings:
7922 *
7923 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7924 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7925 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7926 *
7927 * Example (sets <tt>$0</tt> to 'foo'):
7928 *
7929 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7930 *
7931 * <b>Some Special Examples</b>
7932 *
7933 * # Set IO encoding.
7934 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7935 * euc_jp_string = nkf_io.read
7936 * }
7937 *
7938 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7939 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7940 * ls_result_with_error = io.read
7941 * end
7942 *
7943 * # Use mixture of spawn options and IO options.
7944 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7945 * ls_result_with_error = io.read
7946 * end
7947 *
7948 * f = IO.popen("uname")
7949 * p f.readlines
7950 * f.close
7951 * puts "Parent is #{Process.pid}"
7952 * IO.popen("date") {|f| puts f.gets }
7953 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7954 * p $?
7955 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7956 * f.puts "bar"; f.close_write; puts f.gets
7957 * }
7958 *
7959 * Output (from last section):
7960 *
7961 * ["Linux\n"]
7962 * Parent is 21346
7963 * Thu Jan 15 22:41:19 JST 2009
7964 * 21346 is here, f is #<IO:fd 3>
7965 * 21352 is here, f is nil
7966 * #<Process::Status: pid 21352 exit 0>
7967 * <foo>bar;zot;
7968 *
7969 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7970 *
7971 */
7972
7973static VALUE
7974rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7975{
7976 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7977
7978 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7979 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7980 switch (argc) {
7981 case 2:
7982 pmode = argv[1];
7983 case 1:
7984 pname = argv[0];
7985 break;
7986 default:
7987 {
7988 int ex = !NIL_P(opt);
7989 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7990 }
7991 }
7992 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7993}
7994
7995VALUE
7996rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
7997{
7998 const char *modestr;
7999 VALUE tmp, execarg_obj = Qnil;
8000 int oflags;
8001 enum rb_io_mode fmode;
8002 struct rb_io_encoding convconfig;
8003
8004 tmp = rb_check_array_type(pname);
8005 if (!NIL_P(tmp)) {
8006 long len = RARRAY_LEN(tmp);
8007#if SIZEOF_LONG > SIZEOF_INT
8008 if (len > INT_MAX) {
8009 rb_raise(rb_eArgError, "too many arguments");
8010 }
8011#endif
8012 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8013 RB_GC_GUARD(tmp);
8014 }
8015 else {
8016 StringValue(pname);
8017 execarg_obj = Qnil;
8018 if (!is_popen_fork(pname))
8019 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8020 }
8021 if (!NIL_P(execarg_obj)) {
8022 if (!NIL_P(opt))
8023 opt = rb_execarg_extract_options(execarg_obj, opt);
8024 if (!NIL_P(env))
8025 rb_execarg_setenv(execarg_obj, env);
8026 }
8027 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8028 modestr = rb_io_oflags_modestr(oflags);
8029
8030 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8031}
8032
8033static VALUE
8034popen_finish(VALUE port, VALUE klass)
8035{
8036 if (NIL_P(port)) {
8037 /* child */
8038 if (rb_block_given_p()) {
8039 rb_protect(rb_yield, Qnil, NULL);
8040 rb_io_flush(rb_ractor_stdout());
8041 rb_io_flush(rb_ractor_stderr());
8042 _exit(0);
8043 }
8044 return Qnil;
8045 }
8046 RBASIC_SET_CLASS(port, klass);
8047 if (rb_block_given_p()) {
8048 return rb_ensure(rb_yield, port, pipe_close, port);
8049 }
8050 return port;
8051}
8052
8053#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8054struct popen_writer_arg {
8055 char *const *argv;
8056 struct popen_arg popen;
8057};
8058
8059static int
8060exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8061{
8062 struct popen_writer_arg *pw = arg;
8063 pw->popen.modef = FMODE_WRITABLE;
8064 popen_redirect(&pw->popen);
8065 execv(pw->argv[0], pw->argv);
8066 strlcpy(errmsg, strerror(errno), buflen);
8067 return -1;
8068}
8069#endif
8070
8071FILE *
8072ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8073{
8074#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8075# ifdef HAVE_WORKING_FORK
8076 struct popen_writer_arg pw;
8077 int *const write_pair = pw.popen.pair;
8078# else
8079 int write_pair[2];
8080# endif
8081
8082 int result = rb_cloexec_pipe(write_pair);
8083 *pid = -1;
8084 if (result == 0) {
8085# ifdef HAVE_WORKING_FORK
8086 pw.argv = argv;
8087 int status;
8088 char errmsg[80] = {'\0'};
8089 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8090# else
8091 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8092 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8093# endif
8094 close(write_pair[0]);
8095 if (*pid < 0) {
8096 close(write_pair[1]);
8097 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8098 }
8099 else {
8100 return fdopen(write_pair[1], "w");
8101 }
8102 }
8103#endif
8104 return NULL;
8105}
8106
8107static VALUE
8108rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8109{
8110 int oflags;
8111 enum rb_io_mode fmode;
8112 struct rb_io_encoding convconfig;
8113 mode_t perm;
8114
8115 FilePathValue(fname);
8116
8117 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8118 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8119
8120 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8121
8122 return io;
8123}
8124
8125/*
8126 * Document-method: File::open
8127 *
8128 * call-seq:
8129 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8130 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8131 *
8132 * Creates a new File object, via File.new with the given arguments.
8133 *
8134 * With no block given, returns the File object.
8135 *
8136 * With a block given, calls the block with the File object
8137 * and returns the block's value.
8138 *
8139 */
8140
8141/*
8142 * Document-method: IO::open
8143 *
8144 * call-seq:
8145 * IO.open(fd, mode = 'r', **opts) -> io
8146 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8147 *
8148 * Creates a new \IO object, via IO.new with the given arguments.
8149 *
8150 * With no block given, returns the \IO object.
8151 *
8152 * With a block given, calls the block with the \IO object
8153 * and returns the block's value.
8154 *
8155 */
8156
8157static VALUE
8158rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8159{
8161
8162 if (rb_block_given_p()) {
8163 return rb_ensure(rb_yield, io, io_close, io);
8164 }
8165
8166 return io;
8167}
8168
8169/*
8170 * call-seq:
8171 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8172 *
8173 * Opens the file at the given path with the given mode and permissions;
8174 * returns the integer file descriptor.
8175 *
8176 * If the file is to be readable, it must exist;
8177 * if the file is to be writable and does not exist,
8178 * it is created with the given permissions:
8179 *
8180 * File.write('t.tmp', '') # => 0
8181 * IO.sysopen('t.tmp') # => 8
8182 * IO.sysopen('t.tmp', 'w') # => 9
8183 *
8184 *
8185 */
8186
8187static VALUE
8188rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8189{
8190 VALUE fname, vmode, vperm;
8191 VALUE intmode;
8192 int oflags, fd;
8193 mode_t perm;
8194
8195 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8196 FilePathValue(fname);
8197
8198 if (NIL_P(vmode))
8199 oflags = O_RDONLY;
8200 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8201 oflags = NUM2INT(intmode);
8202 else {
8203 StringValue(vmode);
8204 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8205 }
8206 if (NIL_P(vperm)) perm = 0666;
8207 else perm = NUM2MODET(vperm);
8208
8209 RB_GC_GUARD(fname) = rb_str_new4(fname);
8210 fd = rb_sysopen(fname, oflags, perm);
8211 return INT2NUM(fd);
8212}
8213
8214static VALUE
8215check_pipe_command(VALUE filename_or_command)
8216{
8217 char *s = RSTRING_PTR(filename_or_command);
8218 long l = RSTRING_LEN(filename_or_command);
8219 char *e = s + l;
8220 int chlen;
8221
8222 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8223 VALUE cmd = rb_str_new(s+chlen, l-chlen);
8224 return cmd;
8225 }
8226 return Qnil;
8227}
8228
8229/*
8230 * call-seq:
8231 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8232 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8233 *
8234 * Creates an IO object connected to the given file.
8235 *
8236 * This method has potential security vulnerabilities if called with untrusted input;
8237 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
8238 *
8239 * With no block given, file stream is returned:
8240 *
8241 * open('t.txt') # => #<File:t.txt>
8242 *
8243 * With a block given, calls the block with the open file stream,
8244 * then closes the stream:
8245 *
8246 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8247 *
8248 * Output:
8249 *
8250 * #<File:t.txt>
8251 *
8252 * See File.open for details.
8253 *
8254 */
8255
8256static VALUE
8257rb_f_open(int argc, VALUE *argv, VALUE _)
8258{
8259 ID to_open = 0;
8260 int redirect = FALSE;
8261
8262 if (argc >= 1) {
8263 CONST_ID(to_open, "to_open");
8264 if (rb_respond_to(argv[0], to_open)) {
8265 redirect = TRUE;
8266 }
8267 else {
8268 VALUE tmp = argv[0];
8269 FilePathValue(tmp);
8270 if (NIL_P(tmp)) {
8271 redirect = TRUE;
8272 }
8273 else {
8274 VALUE cmd = check_pipe_command(tmp);
8275 if (!NIL_P(cmd)) {
8276 // TODO: when removed in 4.0, update command_injection.rdoc
8277 rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen");
8278 argv[0] = cmd;
8279 return rb_io_s_popen(argc, argv, rb_cIO);
8280 }
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 VALUE cmd;
8300 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8301 // TODO: when removed in 4.0, update command_injection.rdoc
8302 rb_warn_deprecated_to_remove_at(4.0, "IO process creation with a leading '|'", "IO.popen");
8303 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8304 }
8305 else {
8306 return rb_file_open_generic(io_alloc(klass), filename,
8307 oflags, fmode, convconfig, perm);
8308 }
8309}
8310
8311static VALUE
8312rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8313{
8314 int oflags;
8315 enum rb_io_mode fmode;
8316 struct rb_io_encoding convconfig;
8317 mode_t perm;
8318
8319 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8320 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8321 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8322}
8323
8324static VALUE
8325io_reopen(VALUE io, VALUE nfile)
8326{
8327 rb_io_t *fptr, *orig;
8328 int fd, fd2;
8329 rb_off_t pos = 0;
8330
8331 nfile = rb_io_get_io(nfile);
8332 GetOpenFile(io, fptr);
8333 GetOpenFile(nfile, orig);
8334
8335 if (fptr == orig) return io;
8336 if (RUBY_IO_EXTERNAL_P(fptr)) {
8337 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8338 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8339 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8340 rb_raise(rb_eArgError,
8341 "%s can't change access mode from \"%s\" to \"%s\"",
8342 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8343 rb_io_fmode_modestr(orig->mode));
8344 }
8345 }
8346 if (fptr->mode & FMODE_WRITABLE) {
8347 if (io_fflush(fptr) < 0)
8348 rb_sys_fail_on_write(fptr);
8349 }
8350 else {
8351 flush_before_seek(fptr, true);
8352 }
8353 if (orig->mode & FMODE_READABLE) {
8354 pos = io_tell(orig);
8355 }
8356 if (orig->mode & FMODE_WRITABLE) {
8357 if (io_fflush(orig) < 0)
8358 rb_sys_fail_on_write(fptr);
8359 }
8360
8361 /* copy rb_io_t structure */
8362 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8363 fptr->encs = orig->encs;
8364 fptr->pid = orig->pid;
8365 fptr->lineno = orig->lineno;
8366 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8367 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8368 fptr_copy_finalizer(fptr, orig);
8369
8370 fd = fptr->fd;
8371 fd2 = orig->fd;
8372 if (fd != fd2) {
8373 // Interrupt all usage of the old file descriptor:
8374 rb_thread_io_close_interrupt(fptr);
8375 rb_thread_io_close_wait(fptr);
8376
8377 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8378 /* need to keep FILE objects of stdin, stdout and stderr */
8379 if (rb_cloexec_dup2(fd2, fd) < 0)
8380 rb_sys_fail_path(orig->pathv);
8381 rb_update_max_fd(fd);
8382 }
8383 else {
8384 fclose(fptr->stdio_file);
8385 fptr->stdio_file = 0;
8386 fptr->fd = -1;
8387 if (rb_cloexec_dup2(fd2, fd) < 0)
8388 rb_sys_fail_path(orig->pathv);
8389 rb_update_max_fd(fd);
8390 fptr->fd = fd;
8391 }
8392
8393 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8394 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8395 rb_sys_fail_path(fptr->pathv);
8396 }
8397 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8398 rb_sys_fail_path(orig->pathv);
8399 }
8400 }
8401 }
8402
8403 if (fptr->mode & FMODE_BINMODE) {
8404 rb_io_binmode(io);
8405 }
8406
8407 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8408 return io;
8409}
8410
8411#ifdef _WIN32
8412int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8413#else
8414static int
8415rb_freopen(VALUE fname, const char *mode, FILE *fp)
8416{
8417 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8418 RB_GC_GUARD(fname);
8419 return errno;
8420 }
8421 return 0;
8422}
8423#endif
8424
8425/*
8426 * call-seq:
8427 * reopen(other_io) -> self
8428 * reopen(path, mode = 'r', **opts) -> self
8429 *
8430 * Reassociates the stream with another stream,
8431 * which may be of a different class.
8432 * This method may be used to redirect an existing stream
8433 * to a new destination.
8434 *
8435 * With argument +other_io+ given, reassociates with that stream:
8436 *
8437 * # Redirect $stdin from a file.
8438 * f = File.open('t.txt')
8439 * $stdin.reopen(f)
8440 * f.close
8441 *
8442 * # Redirect $stdout to a file.
8443 * f = File.open('t.tmp', 'w')
8444 * $stdout.reopen(f)
8445 * f.close
8446 *
8447 * With argument +path+ given, reassociates with a new stream to that file path:
8448 *
8449 * $stdin.reopen('t.txt')
8450 * $stdout.reopen('t.tmp', 'w')
8451 *
8452 * Optional keyword arguments +opts+ specify:
8453 *
8454 * - {Open Options}[rdoc-ref:IO@Open+Options].
8455 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8456 *
8457 */
8458
8459static VALUE
8460rb_io_reopen(int argc, VALUE *argv, VALUE file)
8461{
8462 VALUE fname, nmode, opt;
8463 int oflags;
8464 rb_io_t *fptr;
8465
8466 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8467 VALUE tmp = rb_io_check_io(fname);
8468 if (!NIL_P(tmp)) {
8469 return io_reopen(file, tmp);
8470 }
8471 }
8472
8473 FilePathValue(fname);
8474 rb_io_taint_check(file);
8475 fptr = RFILE(file)->fptr;
8476 if (!fptr) {
8477 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8478 }
8479
8480 if (!NIL_P(nmode) || !NIL_P(opt)) {
8481 enum rb_io_mode fmode;
8482 struct rb_io_encoding convconfig;
8483
8484 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8485 if (RUBY_IO_EXTERNAL_P(fptr) &&
8486 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8487 (fptr->mode & FMODE_READWRITE)) {
8488 rb_raise(rb_eArgError,
8489 "%s can't change access mode from \"%s\" to \"%s\"",
8490 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8491 rb_io_fmode_modestr(fmode));
8492 }
8493 fptr->mode = fmode;
8494 fptr->encs = convconfig;
8495 }
8496 else {
8497 oflags = rb_io_fmode_oflags(fptr->mode);
8498 }
8499
8500 fptr->pathv = fname;
8501 if (fptr->fd < 0) {
8502 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8503 fptr->stdio_file = 0;
8504 return file;
8505 }
8506
8507 if (fptr->mode & FMODE_WRITABLE) {
8508 if (io_fflush(fptr) < 0)
8509 rb_sys_fail_on_write(fptr);
8510 }
8511 fptr->rbuf.off = fptr->rbuf.len = 0;
8512
8513 if (fptr->stdio_file) {
8514 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8515 rb_io_oflags_modestr(oflags),
8516 fptr->stdio_file);
8517 if (e) rb_syserr_fail_path(e, fptr->pathv);
8518 fptr->fd = fileno(fptr->stdio_file);
8519 rb_fd_fix_cloexec(fptr->fd);
8520#ifdef USE_SETVBUF
8521 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8522 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8523#endif
8524 if (fptr->stdio_file == stderr) {
8525 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8526 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8527 }
8528 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8529 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8530 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8531 }
8532 }
8533 else {
8534 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8535 int err = 0;
8536 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8537 err = errno;
8538 (void)close(tmpfd);
8539 if (err) {
8540 rb_syserr_fail_path(err, fptr->pathv);
8541 }
8542 }
8543
8544 return file;
8545}
8546
8547/* :nodoc: */
8548static VALUE
8549rb_io_init_copy(VALUE dest, VALUE io)
8550{
8551 rb_io_t *fptr, *orig;
8552 int fd;
8553 VALUE write_io;
8554 rb_off_t pos;
8555
8556 io = rb_io_get_io(io);
8557 if (!OBJ_INIT_COPY(dest, io)) return dest;
8558 GetOpenFile(io, orig);
8559 MakeOpenFile(dest, fptr);
8560
8561 rb_io_flush(io);
8562
8563 /* copy rb_io_t structure */
8564 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8565 fptr->encs = orig->encs;
8566 fptr->pid = orig->pid;
8567 fptr->lineno = orig->lineno;
8568 fptr->timeout = orig->timeout;
8569
8570 ccan_list_head_init(&fptr->blocking_operations);
8571 fptr->closing_ec = NULL;
8572 fptr->wakeup_mutex = Qnil;
8573 fptr->fork_generation = GET_VM()->fork_gen;
8574
8575 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8576 fptr_copy_finalizer(fptr, orig);
8577
8578 fd = ruby_dup(orig->fd);
8579 fptr->fd = fd;
8580 pos = io_tell(orig);
8581 if (0 <= pos)
8582 io_seek(fptr, pos, SEEK_SET);
8583 if (fptr->mode & FMODE_BINMODE) {
8584 rb_io_binmode(dest);
8585 }
8586
8587 write_io = GetWriteIO(io);
8588 if (io != write_io) {
8589 write_io = rb_obj_dup(write_io);
8590 fptr->tied_io_for_writing = write_io;
8591 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8592 }
8593
8594 return dest;
8595}
8596
8597/*
8598 * call-seq:
8599 * printf(format_string, *objects) -> nil
8600 *
8601 * Formats and writes +objects+ to the stream.
8602 *
8603 * For details on +format_string+, see
8604 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8605 *
8606 */
8607
8608VALUE
8609rb_io_printf(int argc, const VALUE *argv, VALUE out)
8610{
8611 rb_io_write(out, rb_f_sprintf(argc, argv));
8612 return Qnil;
8613}
8614
8615/*
8616 * call-seq:
8617 * printf(format_string, *objects) -> nil
8618 * printf(io, format_string, *objects) -> nil
8619 *
8620 * Equivalent to:
8621 *
8622 * io.write(sprintf(format_string, *objects))
8623 *
8624 * For details on +format_string+, see
8625 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8626 *
8627 * With the single argument +format_string+, formats +objects+ into the string,
8628 * then writes the formatted string to $stdout:
8629 *
8630 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8631 *
8632 * Output (on $stdout):
8633 *
8634 * 0024 24 24.00#
8635 *
8636 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8637 * then writes the formatted string to +io+:
8638 *
8639 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8640 *
8641 * Output (on $stderr):
8642 *
8643 * 0024 24 24.00# => nil
8644 *
8645 * With no arguments, does nothing.
8646 *
8647 */
8648
8649static VALUE
8650rb_f_printf(int argc, VALUE *argv, VALUE _)
8651{
8652 VALUE out;
8653
8654 if (argc == 0) return Qnil;
8655 if (RB_TYPE_P(argv[0], T_STRING)) {
8656 out = rb_ractor_stdout();
8657 }
8658 else {
8659 out = argv[0];
8660 argv++;
8661 argc--;
8662 }
8663 rb_io_write(out, rb_f_sprintf(argc, argv));
8664
8665 return Qnil;
8666}
8667
8668static void
8669deprecated_str_setter(VALUE val, ID id, VALUE *var)
8670{
8671 rb_str_setter(val, id, &val);
8672 if (!NIL_P(val)) {
8673 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8674 }
8675 *var = val;
8676}
8677
8678static void
8679deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8680{
8681 if (!NIL_P(val)) {
8682 if (!RB_TYPE_P(val, T_STRING)) {
8683 rb_raise(rb_eTypeError, "value of %"PRIsVALUE" must be String", rb_id2str(id));
8684 }
8685 if (rb_str_equal(val, rb_default_rs)) {
8686 val = rb_default_rs;
8687 }
8688 else {
8689 val = rb_str_frozen_bare_string(val);
8690 }
8692 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8693 }
8694 *var = val;
8695}
8696
8697/*
8698 * call-seq:
8699 * print(*objects) -> nil
8700 *
8701 * Writes the given objects to the stream; returns +nil+.
8702 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8703 * (<tt>$\</tt>), if it is not +nil+.
8704 * See {Line IO}[rdoc-ref:IO@Line+IO].
8705 *
8706 * With argument +objects+ given, for each object:
8707 *
8708 * - Converts via its method +to_s+ if not a string.
8709 * - Writes to the stream.
8710 * - If not the last object, writes the output field separator
8711 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8712 *
8713 * With default separators:
8714 *
8715 * f = File.open('t.tmp', 'w+')
8716 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8717 * p $OUTPUT_RECORD_SEPARATOR
8718 * p $OUTPUT_FIELD_SEPARATOR
8719 * f.print(*objects)
8720 * f.rewind
8721 * p f.read
8722 * f.close
8723 *
8724 * Output:
8725 *
8726 * nil
8727 * nil
8728 * "00.00/10+0izerozero"
8729 *
8730 * With specified separators:
8731 *
8732 * $\ = "\n"
8733 * $, = ','
8734 * f.rewind
8735 * f.print(*objects)
8736 * f.rewind
8737 * p f.read
8738 *
8739 * Output:
8740 *
8741 * "0,0.0,0/1,0+0i,zero,zero\n"
8742 *
8743 * With no argument given, writes the content of <tt>$_</tt>
8744 * (which is usually the most recent user input):
8745 *
8746 * f = File.open('t.tmp', 'w+')
8747 * gets # Sets $_ to the most recent user input.
8748 * f.print
8749 * f.close
8750 *
8751 */
8752
8753VALUE
8754rb_io_print(int argc, const VALUE *argv, VALUE out)
8755{
8756 int i;
8757 VALUE line;
8758
8759 /* if no argument given, print `$_' */
8760 if (argc == 0) {
8761 argc = 1;
8762 line = rb_lastline_get();
8763 argv = &line;
8764 }
8765 if (argc > 1 && !NIL_P(rb_output_fs)) {
8766 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8767 }
8768 for (i=0; i<argc; i++) {
8769 if (!NIL_P(rb_output_fs) && i>0) {
8770 rb_io_write(out, rb_output_fs);
8771 }
8772 rb_io_write(out, argv[i]);
8773 }
8774 if (argc > 0 && !NIL_P(rb_output_rs)) {
8775 rb_io_write(out, rb_output_rs);
8776 }
8777
8778 return Qnil;
8779}
8780
8781/*
8782 * call-seq:
8783 * print(*objects) -> nil
8784 *
8785 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8786 * this method is the straightforward way to write to <tt>$stdout</tt>.
8787 *
8788 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8789 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8790 * <tt>$\</tt>), if it is not +nil+.
8791 *
8792 * With argument +objects+ given, for each object:
8793 *
8794 * - Converts via its method +to_s+ if not a string.
8795 * - Writes to <tt>stdout</tt>.
8796 * - If not the last object, writes the output field separator
8797 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8798 *
8799 * With default separators:
8800 *
8801 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8802 * $OUTPUT_RECORD_SEPARATOR
8803 * $OUTPUT_FIELD_SEPARATOR
8804 * print(*objects)
8805 *
8806 * Output:
8807 *
8808 * nil
8809 * nil
8810 * 00.00/10+0izerozero
8811 *
8812 * With specified separators:
8813 *
8814 * $OUTPUT_RECORD_SEPARATOR = "\n"
8815 * $OUTPUT_FIELD_SEPARATOR = ','
8816 * print(*objects)
8817 *
8818 * Output:
8819 *
8820 * 0,0.0,0/1,0+0i,zero,zero
8821 *
8822 * With no argument given, writes the content of <tt>$_</tt>
8823 * (which is usually the most recent user input):
8824 *
8825 * gets # Sets $_ to the most recent user input.
8826 * print # Prints $_.
8827 *
8828 */
8829
8830static VALUE
8831rb_f_print(int argc, const VALUE *argv, VALUE _)
8832{
8833 rb_io_print(argc, argv, rb_ractor_stdout());
8834 return Qnil;
8835}
8836
8837/*
8838 * call-seq:
8839 * putc(object) -> object
8840 *
8841 * Writes a character to the stream.
8842 * See {Character IO}[rdoc-ref:IO@Character+IO].
8843 *
8844 * If +object+ is numeric, converts to integer if necessary,
8845 * then writes the character whose code is the
8846 * least significant byte;
8847 * if +object+ is a string, writes the first character:
8848 *
8849 * $stdout.putc "A"
8850 * $stdout.putc 65
8851 *
8852 * Output:
8853 *
8854 * AA
8855 *
8856 */
8857
8858static VALUE
8859rb_io_putc(VALUE io, VALUE ch)
8860{
8861 VALUE str;
8862 if (RB_TYPE_P(ch, T_STRING)) {
8863 str = rb_str_substr(ch, 0, 1);
8864 }
8865 else {
8866 char c = NUM2CHR(ch);
8867 str = rb_str_new(&c, 1);
8868 }
8869 rb_io_write(io, str);
8870 return ch;
8871}
8872
8873#define forward(obj, id, argc, argv) \
8874 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8875#define forward_public(obj, id, argc, argv) \
8876 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8877#define forward_current(id, argc, argv) \
8878 forward_public(ARGF.current_file, id, argc, argv)
8879
8880/*
8881 * call-seq:
8882 * putc(int) -> int
8883 *
8884 * Equivalent to:
8885 *
8886 * $stdout.putc(int)
8887 *
8888 * See IO#putc for important information regarding multi-byte characters.
8889 *
8890 */
8891
8892static VALUE
8893rb_f_putc(VALUE recv, VALUE ch)
8894{
8895 VALUE r_stdout = rb_ractor_stdout();
8896 if (recv == r_stdout) {
8897 return rb_io_putc(recv, ch);
8898 }
8899 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8900}
8901
8902
8903int
8904rb_str_end_with_asciichar(VALUE str, int c)
8905{
8906 long len = RSTRING_LEN(str);
8907 const char *ptr = RSTRING_PTR(str);
8908 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8909 int n;
8910
8911 if (len == 0) return 0;
8912 if ((n = rb_enc_mbminlen(enc)) == 1) {
8913 return ptr[len - 1] == c;
8914 }
8915 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8916}
8917
8918static VALUE
8919io_puts_ary(VALUE ary, VALUE out, int recur)
8920{
8921 VALUE tmp;
8922 long i;
8923
8924 if (recur) {
8925 tmp = rb_str_new2("[...]");
8926 rb_io_puts(1, &tmp, out);
8927 return Qtrue;
8928 }
8929 ary = rb_check_array_type(ary);
8930 if (NIL_P(ary)) return Qfalse;
8931 for (i=0; i<RARRAY_LEN(ary); i++) {
8932 tmp = RARRAY_AREF(ary, i);
8933 rb_io_puts(1, &tmp, out);
8934 }
8935 return Qtrue;
8936}
8937
8938/*
8939 * call-seq:
8940 * puts(*objects) -> nil
8941 *
8942 * Writes the given +objects+ to the stream, which must be open for writing;
8943 * returns +nil+.\
8944 * Writes a newline after each that does not already end with a newline sequence.
8945 * If called without arguments, writes a newline.
8946 * See {Line IO}[rdoc-ref:IO@Line+IO].
8947 *
8948 * Note that each added newline is the character <tt>"\n"<//tt>,
8949 * not the output record separator (<tt>$\</tt>).
8950 *
8951 * Treatment for each object:
8952 *
8953 * - String: writes the string.
8954 * - Neither string nor array: writes <tt>object.to_s</tt>.
8955 * - Array: writes each element of the array; arrays may be nested.
8956 *
8957 * To keep these examples brief, we define this helper method:
8958 *
8959 * def show(*objects)
8960 * # Puts objects to file.
8961 * f = File.new('t.tmp', 'w+')
8962 * f.puts(objects)
8963 * # Return file content.
8964 * f.rewind
8965 * p f.read
8966 * f.close
8967 * end
8968 *
8969 * # Strings without newlines.
8970 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8971 * # Strings, some with newlines.
8972 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8973 *
8974 * # Neither strings nor arrays:
8975 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8976 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8977 *
8978 * # Array of strings.
8979 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8980 * # Nested arrays.
8981 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8982 *
8983 */
8984
8985VALUE
8986rb_io_puts(int argc, const VALUE *argv, VALUE out)
8987{
8988 VALUE line, args[2];
8989
8990 /* if no argument given, print newline. */
8991 if (argc == 0) {
8992 rb_io_write(out, rb_default_rs);
8993 return Qnil;
8994 }
8995 for (int i = 0; i < argc; i++) {
8996 // Convert the argument to a string:
8997 if (RB_TYPE_P(argv[i], T_STRING)) {
8998 line = argv[i];
8999 }
9000 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9001 continue;
9002 }
9003 else {
9004 line = rb_obj_as_string(argv[i]);
9005 }
9006
9007 // Write the line:
9008 int n = 0;
9009 if (RSTRING_LEN(line) == 0) {
9010 args[n++] = rb_default_rs;
9011 }
9012 else {
9013 args[n++] = line;
9014 if (!rb_str_end_with_asciichar(line, '\n')) {
9015 args[n++] = rb_default_rs;
9016 }
9017 }
9018
9019 rb_io_writev(out, n, args);
9020 }
9021
9022 return Qnil;
9023}
9024
9025/*
9026 * call-seq:
9027 * puts(*objects) -> nil
9028 *
9029 * Equivalent to
9030 *
9031 * $stdout.puts(objects)
9032 */
9033
9034static VALUE
9035rb_f_puts(int argc, VALUE *argv, VALUE recv)
9036{
9037 VALUE r_stdout = rb_ractor_stdout();
9038 if (recv == r_stdout) {
9039 return rb_io_puts(argc, argv, recv);
9040 }
9041 return forward(r_stdout, rb_intern("puts"), argc, argv);
9042}
9043
9044static VALUE
9045rb_p_write(VALUE str)
9046{
9047 VALUE args[2];
9048 args[0] = str;
9049 args[1] = rb_default_rs;
9050 VALUE r_stdout = rb_ractor_stdout();
9051 if (RB_TYPE_P(r_stdout, T_FILE) &&
9052 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9053 io_writev(2, args, r_stdout);
9054 }
9055 else {
9056 rb_io_writev(r_stdout, 2, args);
9057 }
9058 return Qnil;
9059}
9060
9061void
9062rb_p(VALUE obj) /* for debug print within C code */
9063{
9064 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9065}
9066
9067static VALUE
9068rb_p_result(int argc, const VALUE *argv)
9069{
9070 VALUE ret = Qnil;
9071
9072 if (argc == 1) {
9073 ret = argv[0];
9074 }
9075 else if (argc > 1) {
9076 ret = rb_ary_new4(argc, argv);
9077 }
9078 VALUE r_stdout = rb_ractor_stdout();
9079 if (RB_TYPE_P(r_stdout, T_FILE)) {
9080 rb_uninterruptible(rb_io_flush, r_stdout);
9081 }
9082 return ret;
9083}
9084
9085/*
9086 * call-seq:
9087 * p(object) -> obj
9088 * p(*objects) -> array of objects
9089 * p -> nil
9090 *
9091 * For each object +obj+, executes:
9092 *
9093 * $stdout.write(obj.inspect, "\n")
9094 *
9095 * With one object given, returns the object;
9096 * with multiple objects given, returns an array containing the objects;
9097 * with no object given, returns +nil+.
9098 *
9099 * Examples:
9100 *
9101 * r = Range.new(0, 4)
9102 * p r # => 0..4
9103 * p [r, r, r] # => [0..4, 0..4, 0..4]
9104 * p # => nil
9105 *
9106 * Output:
9107 *
9108 * 0..4
9109 * [0..4, 0..4, 0..4]
9110 *
9111 * Kernel#p is designed for debugging purposes.
9112 * Ruby implementations may define Kernel#p to be uninterruptible
9113 * in whole or in part.
9114 * On CRuby, Kernel#p's writing of data is uninterruptible.
9115 */
9116
9117static VALUE
9118rb_f_p(int argc, VALUE *argv, VALUE self)
9119{
9120 int i;
9121 for (i=0; i<argc; i++) {
9122 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9123 rb_uninterruptible(rb_p_write, inspected);
9124 }
9125 return rb_p_result(argc, argv);
9126}
9127
9128/*
9129 * call-seq:
9130 * display(port = $>) -> nil
9131 *
9132 * Writes +self+ on the given port:
9133 *
9134 * 1.display
9135 * "cat".display
9136 * [ 4, 5, 6 ].display
9137 * puts
9138 *
9139 * Output:
9140 *
9141 * 1cat[4, 5, 6]
9142 *
9143 */
9144
9145static VALUE
9146rb_obj_display(int argc, VALUE *argv, VALUE self)
9147{
9148 VALUE out;
9149
9150 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9151 rb_io_write(out, self);
9152
9153 return Qnil;
9154}
9155
9156static int
9157rb_stderr_to_original_p(VALUE err)
9158{
9159 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9160}
9161
9162void
9163rb_write_error2(const char *mesg, long len)
9164{
9165 VALUE out = rb_ractor_stderr();
9166 if (rb_stderr_to_original_p(out)) {
9167#ifdef _WIN32
9168 if (isatty(fileno(stderr))) {
9169 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9170 }
9171#endif
9172 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9173 /* failed to write to stderr, what can we do? */
9174 return;
9175 }
9176 }
9177 else {
9178 rb_io_write(out, rb_str_new(mesg, len));
9179 }
9180}
9181
9182void
9183rb_write_error(const char *mesg)
9184{
9185 rb_write_error2(mesg, strlen(mesg));
9186}
9187
9188void
9189rb_write_error_str(VALUE mesg)
9190{
9191 VALUE out = rb_ractor_stderr();
9192 /* a stopgap measure for the time being */
9193 if (rb_stderr_to_original_p(out)) {
9194 size_t len = (size_t)RSTRING_LEN(mesg);
9195#ifdef _WIN32
9196 if (isatty(fileno(stderr))) {
9197 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9198 }
9199#endif
9200 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9201 RB_GC_GUARD(mesg);
9202 return;
9203 }
9204 }
9205 else {
9206 /* may unlock GVL, and */
9207 rb_io_write(out, mesg);
9208 }
9209}
9210
9211int
9212rb_stderr_tty_p(void)
9213{
9214 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9215 return isatty(fileno(stderr));
9216 return 0;
9217}
9218
9219static void
9220must_respond_to(ID mid, VALUE val, ID id)
9221{
9222 if (!rb_respond_to(val, mid)) {
9223 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9224 rb_id2str(id), rb_id2str(mid),
9225 rb_obj_class(val));
9226 }
9227}
9228
9229static void
9230stdin_setter(VALUE val, ID id, VALUE *ptr)
9231{
9233}
9234
9235static VALUE
9236stdin_getter(ID id, VALUE *ptr)
9237{
9238 return rb_ractor_stdin();
9239}
9240
9241static void
9242stdout_setter(VALUE val, ID id, VALUE *ptr)
9243{
9244 must_respond_to(id_write, val, id);
9246}
9247
9248static VALUE
9249stdout_getter(ID id, VALUE *ptr)
9250{
9251 return rb_ractor_stdout();
9252}
9253
9254static void
9255stderr_setter(VALUE val, ID id, VALUE *ptr)
9256{
9257 must_respond_to(id_write, val, id);
9259}
9260
9261static VALUE
9262stderr_getter(ID id, VALUE *ptr)
9263{
9264 return rb_ractor_stderr();
9265}
9266
9267static VALUE
9268allocate_and_open_new_file(VALUE klass)
9269{
9270 VALUE self = io_alloc(klass);
9271 rb_io_make_open_file(self);
9272 return self;
9273}
9274
9275VALUE
9276rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9277{
9278 int state;
9279 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9280 if (state) {
9281 /* if we raised an exception allocating an IO object, but the caller
9282 intended to transfer ownership of this FD to us, close the fd before
9283 raising the exception. Otherwise, we would leak a FD - the caller
9284 expects GC to close the file, but we never got around to assigning
9285 it to a rb_io. */
9286 if (!(mode & FMODE_EXTERNAL)) {
9287 maygvl_close(descriptor, 0);
9288 }
9289 rb_jump_tag(state);
9290 }
9291
9292
9293 rb_io_t *io = RFILE(self)->fptr;
9294 io->self = self;
9295 io->fd = descriptor;
9296 io->mode = mode;
9297
9298 /* At this point, Ruby fully owns the descriptor, and will close it when
9299 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9300 in the rest of this method. */
9301
9302 if (NIL_P(path)) {
9303 io->pathv = Qnil;
9304 }
9305 else {
9306 StringValue(path);
9307 io->pathv = rb_str_new_frozen(path);
9308 }
9309
9310 io->timeout = timeout;
9311
9312 ccan_list_head_init(&io->blocking_operations);
9313 io->closing_ec = NULL;
9314 io->wakeup_mutex = Qnil;
9315 io->fork_generation = GET_VM()->fork_gen;
9316
9317 if (encoding) {
9318 io->encs = *encoding;
9319 }
9320
9321 rb_update_max_fd(descriptor);
9322
9323 return self;
9324}
9325
9326static VALUE
9327prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9328{
9329 VALUE path_value = Qnil;
9330 rb_encoding *e;
9331 struct rb_io_encoding convconfig;
9332
9333 if (path) {
9334 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9335 }
9336
9337 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9338 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9339 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9342#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9343 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9344 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9345 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9346#endif
9347 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9348 convconfig.ecopts = Qnil;
9349
9350 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9351 rb_io_t*io = RFILE(self)->fptr;
9352
9353 if (!io_check_tty(io)) {
9354#ifdef __CYGWIN__
9355 io->mode |= FMODE_BINMODE;
9356 setmode(fd, O_BINARY);
9357#endif
9358 }
9359
9360 return self;
9361}
9362
9363VALUE
9364rb_io_fdopen(int fd, int oflags, const char *path)
9365{
9366 VALUE klass = rb_cIO;
9367
9368 if (path && strcmp(path, "-")) klass = rb_cFile;
9369 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9370}
9371
9372static VALUE
9373prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9374{
9375 rb_io_t *fptr;
9376 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9377
9378 GetOpenFile(io, fptr);
9380#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9381 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9382 if (fmode & FMODE_READABLE) {
9384 }
9385#endif
9386 fptr->stdio_file = f;
9387
9388 return io;
9389}
9390
9391VALUE
9392rb_io_prep_stdin(void)
9393{
9394 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9395}
9396
9397VALUE
9398rb_io_prep_stdout(void)
9399{
9400 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9401}
9402
9403VALUE
9404rb_io_prep_stderr(void)
9405{
9406 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9407}
9408
9409FILE *
9411{
9412 if (!fptr->stdio_file) {
9413 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9414 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9415 }
9416 return fptr->stdio_file;
9417}
9418
9419static inline void
9420rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9421{
9422 buf->ptr = NULL;
9423 buf->off = 0;
9424 buf->len = 0;
9425 buf->capa = 0;
9426}
9427
9428static inline rb_io_t *
9429rb_io_fptr_new(void)
9430{
9431 rb_io_t *fp = ALLOC(rb_io_t);
9432 fp->self = Qnil;
9433 fp->fd = -1;
9434 fp->stdio_file = NULL;
9435 fp->mode = 0;
9436 fp->pid = 0;
9437 fp->lineno = 0;
9438 fp->pathv = Qnil;
9439 fp->finalize = 0;
9440 rb_io_buffer_init(&fp->wbuf);
9441 rb_io_buffer_init(&fp->rbuf);
9442 rb_io_buffer_init(&fp->cbuf);
9443 fp->readconv = NULL;
9444 fp->writeconv = NULL;
9446 fp->writeconv_pre_ecflags = 0;
9448 fp->writeconv_initialized = 0;
9449 fp->tied_io_for_writing = 0;
9450 fp->encs.enc = NULL;
9451 fp->encs.enc2 = NULL;
9452 fp->encs.ecflags = 0;
9453 fp->encs.ecopts = Qnil;
9454 fp->write_lock = Qnil;
9455 fp->timeout = Qnil;
9456 ccan_list_head_init(&fp->blocking_operations);
9457 fp->closing_ec = NULL;
9458 fp->wakeup_mutex = Qnil;
9459 fp->fork_generation = GET_VM()->fork_gen;
9460 return fp;
9461}
9462
9463rb_io_t *
9464rb_io_make_open_file(VALUE obj)
9465{
9466 rb_io_t *fp = 0;
9467
9468 Check_Type(obj, T_FILE);
9469 if (RFILE(obj)->fptr) {
9470 rb_io_close(obj);
9471 rb_io_fptr_finalize(RFILE(obj)->fptr);
9472 RFILE(obj)->fptr = 0;
9473 }
9474 fp = rb_io_fptr_new();
9475 fp->self = obj;
9476 RFILE(obj)->fptr = fp;
9477 return fp;
9478}
9479
9480static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9481
9482/*
9483 * call-seq:
9484 * IO.new(fd, mode = 'r', **opts) -> io
9485 *
9486 * Creates and returns a new \IO object (file stream) from a file descriptor.
9487 *
9488 * \IO.new may be useful for interaction with low-level libraries.
9489 * For higher-level interactions, it may be simpler to create
9490 * the file stream using File.open.
9491 *
9492 * Argument +fd+ must be a valid file descriptor (integer):
9493 *
9494 * path = 't.tmp'
9495 * fd = IO.sysopen(path) # => 3
9496 * IO.new(fd) # => #<IO:fd 3>
9497 *
9498 * The new \IO object does not inherit encoding
9499 * (because the integer file descriptor does not have an encoding):
9500 *
9501 * fd = IO.sysopen('t.rus', 'rb')
9502 * io = IO.new(fd)
9503 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9504 *
9505 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9506 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9507 *
9508 * IO.new(fd, 'w') # => #<IO:fd 3>
9509 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9510 *
9511 * Optional keyword arguments +opts+ specify:
9512 *
9513 * - {Open Options}[rdoc-ref:IO@Open+Options].
9514 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9515 *
9516 * Examples:
9517 *
9518 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9519 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9520 *
9521 */
9522
9523static VALUE
9524rb_io_initialize(int argc, VALUE *argv, VALUE io)
9525{
9526 VALUE fnum, vmode;
9527 VALUE opt;
9528
9529 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9530 return io_initialize(io, fnum, vmode, opt);
9531}
9532
9533static VALUE
9534io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9535{
9536 rb_io_t *fp;
9537 int fd, oflags = O_RDONLY;
9538 enum rb_io_mode fmode;
9539 struct rb_io_encoding convconfig;
9540#if defined(HAVE_FCNTL) && defined(F_GETFL)
9541 int ofmode;
9542#else
9543 struct stat st;
9544#endif
9545
9546 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9547
9548 fd = NUM2INT(fnum);
9549 if (rb_reserved_fd_p(fd)) {
9550 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9551 }
9552#if defined(HAVE_FCNTL) && defined(F_GETFL)
9553 oflags = fcntl(fd, F_GETFL);
9554 if (oflags == -1) rb_sys_fail(0);
9555#else
9556 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9557#endif
9558 rb_update_max_fd(fd);
9559#if defined(HAVE_FCNTL) && defined(F_GETFL)
9560 ofmode = rb_io_oflags_fmode(oflags);
9561 if (NIL_P(vmode)) {
9562 fmode = ofmode;
9563 }
9564 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9565 VALUE error = INT2FIX(EINVAL);
9567 }
9568#endif
9569 VALUE path = Qnil;
9570
9571 if (!NIL_P(opt)) {
9572 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9573 fmode |= FMODE_EXTERNAL;
9574 }
9575
9576 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9577 if (!NIL_P(path)) {
9578 StringValue(path);
9579 path = rb_str_new_frozen(path);
9580 }
9581 }
9582
9583 MakeOpenFile(io, fp);
9584 fp->self = io;
9585 fp->fd = fd;
9586 fp->mode = fmode;
9587 fp->encs = convconfig;
9588 fp->pathv = path;
9589 fp->timeout = Qnil;
9590 ccan_list_head_init(&fp->blocking_operations);
9591 fp->closing_ec = NULL;
9592 fp->wakeup_mutex = Qnil;
9593 fp->fork_generation = GET_VM()->fork_gen;
9594 clear_codeconv(fp);
9595 io_check_tty(fp);
9596 if (fileno(stdin) == fd)
9597 fp->stdio_file = stdin;
9598 else if (fileno(stdout) == fd)
9599 fp->stdio_file = stdout;
9600 else if (fileno(stderr) == fd)
9601 fp->stdio_file = stderr;
9602
9603 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9604 return io;
9605}
9606
9607/*
9608 * call-seq:
9609 * set_encoding_by_bom -> encoding or nil
9610 *
9611 * If the stream begins with a BOM
9612 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9613 * consumes the BOM and sets the external encoding accordingly;
9614 * returns the result encoding if found, or +nil+ otherwise:
9615 *
9616 * File.write('t.tmp', "\u{FEFF}abc")
9617 * io = File.open('t.tmp', 'rb')
9618 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9619 * io.close
9620 *
9621 * File.write('t.tmp', 'abc')
9622 * io = File.open('t.tmp', 'rb')
9623 * io.set_encoding_by_bom # => nil
9624 * io.close
9625 *
9626 * Raises an exception if the stream is not binmode
9627 * or its encoding has already been set.
9628 *
9629 */
9630
9631static VALUE
9632rb_io_set_encoding_by_bom(VALUE io)
9633{
9634 rb_io_t *fptr;
9635
9636 GetOpenFile(io, fptr);
9637 if (!(fptr->mode & FMODE_BINMODE)) {
9638 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9639 }
9640 if (fptr->encs.enc2) {
9641 rb_raise(rb_eArgError, "encoding conversion is set");
9642 }
9643 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9644 rb_raise(rb_eArgError, "encoding is set to %s already",
9645 rb_enc_name(fptr->encs.enc));
9646 }
9647 if (!io_set_encoding_by_bom(io)) return Qnil;
9648 return rb_enc_from_encoding(fptr->encs.enc);
9649}
9650
9651/*
9652 * call-seq:
9653 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9654 *
9655 * Opens the file at the given +path+ according to the given +mode+;
9656 * creates and returns a new File object for that file.
9657 *
9658 * The new File object is buffered mode (or non-sync mode), unless
9659 * +filename+ is a tty.
9660 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9661 *
9662 * Argument +path+ must be a valid file path:
9663 *
9664 * f = File.new('/etc/fstab')
9665 * f.close
9666 * f = File.new('t.txt')
9667 * f.close
9668 *
9669 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9670 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9671 *
9672 * f = File.new('t.tmp', 'w')
9673 * f.close
9674 * f = File.new('t.tmp', File::RDONLY)
9675 * f.close
9676 *
9677 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9678 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9679 *
9680 * f = File.new('t.tmp', File::CREAT, 0644)
9681 * f.close
9682 * f = File.new('t.tmp', File::CREAT, 0444)
9683 * f.close
9684 *
9685 * Optional keyword arguments +opts+ specify:
9686 *
9687 * - {Open Options}[rdoc-ref:IO@Open+Options].
9688 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9689 *
9690 */
9691
9692static VALUE
9693rb_file_initialize(int argc, VALUE *argv, VALUE io)
9694{
9695 if (RFILE(io)->fptr) {
9696 rb_raise(rb_eRuntimeError, "reinitializing File");
9697 }
9698 VALUE fname, vmode, vperm, opt;
9699 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9700 if (posargc < 3) { /* perm is File only */
9701 VALUE fd = rb_check_to_int(fname);
9702
9703 if (!NIL_P(fd)) {
9704 return io_initialize(io, fd, vmode, opt);
9705 }
9706 }
9707 return rb_open_file(io, fname, vmode, vperm, opt);
9708}
9709
9710/* :nodoc: */
9711static VALUE
9712rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9713{
9714 if (rb_block_given_p()) {
9715 VALUE cname = rb_obj_as_string(klass);
9716
9717 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9718 cname, cname);
9719 }
9720 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9721}
9722
9723
9724/*
9725 * call-seq:
9726 * IO.for_fd(fd, mode = 'r', **opts) -> io
9727 *
9728 * Synonym for IO.new.
9729 *
9730 */
9731
9732static VALUE
9733rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9734{
9735 VALUE io = rb_obj_alloc(klass);
9736 rb_io_initialize(argc, argv, io);
9737 return io;
9738}
9739
9740/*
9741 * call-seq:
9742 * ios.autoclose? -> true or false
9743 *
9744 * Returns +true+ if the underlying file descriptor of _ios_ will be
9745 * closed at its finalization or at calling #close, otherwise +false+.
9746 */
9747
9748static VALUE
9749rb_io_autoclose_p(VALUE io)
9750{
9751 rb_io_t *fptr = RFILE(io)->fptr;
9752 rb_io_check_closed(fptr);
9753 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9754}
9755
9756/*
9757 * call-seq:
9758 * io.autoclose = bool -> true or false
9759 *
9760 * Sets auto-close flag.
9761 *
9762 * f = File.open(File::NULL)
9763 * IO.for_fd(f.fileno).close
9764 * f.gets # raises Errno::EBADF
9765 *
9766 * f = File.open(File::NULL)
9767 * g = IO.for_fd(f.fileno)
9768 * g.autoclose = false
9769 * g.close
9770 * f.gets # won't cause Errno::EBADF
9771 */
9772
9773static VALUE
9774rb_io_set_autoclose(VALUE io, VALUE autoclose)
9775{
9776 rb_io_t *fptr;
9777 GetOpenFile(io, fptr);
9778 if (!RTEST(autoclose))
9779 fptr->mode |= FMODE_EXTERNAL;
9780 else
9781 fptr->mode &= ~FMODE_EXTERNAL;
9782 return autoclose;
9783}
9784
9785static VALUE
9786io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9787{
9788 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9789
9790 if (!RB_TEST(result)) {
9791 return Qnil;
9792 }
9793
9794 int mask = RB_NUM2INT(result);
9795
9796 if (mask & event) {
9797 if (return_io)
9798 return io;
9799 else
9800 return result;
9801 }
9802 else {
9803 return Qfalse;
9804 }
9805}
9806
9807/*
9808 * call-seq:
9809 * io.wait_readable -> truthy or falsy
9810 * io.wait_readable(timeout) -> truthy or falsy
9811 *
9812 * Waits until IO is readable and returns a truthy value, or a falsy
9813 * value when times out. Returns a truthy value immediately when
9814 * buffered data is available.
9815 */
9816
9817static VALUE
9818io_wait_readable(int argc, VALUE *argv, VALUE io)
9819{
9820 rb_io_t *fptr;
9821
9822 RB_IO_POINTER(io, fptr);
9824
9825 if (rb_io_read_pending(fptr)) return Qtrue;
9826
9827 rb_check_arity(argc, 0, 1);
9828 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9829
9830 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9831}
9832
9833/*
9834 * call-seq:
9835 * io.wait_writable -> truthy or falsy
9836 * io.wait_writable(timeout) -> truthy or falsy
9837 *
9838 * Waits until IO is writable and returns a truthy value or a falsy
9839 * value when times out.
9840 */
9841static VALUE
9842io_wait_writable(int argc, VALUE *argv, VALUE io)
9843{
9844 rb_io_t *fptr;
9845
9846 RB_IO_POINTER(io, fptr);
9848
9849 rb_check_arity(argc, 0, 1);
9850 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9851
9852 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9853}
9854
9855/*
9856 * call-seq:
9857 * io.wait_priority -> truthy or falsy
9858 * io.wait_priority(timeout) -> truthy or falsy
9859 *
9860 * Waits until IO is priority and returns a truthy value or a falsy
9861 * value when times out. Priority data is sent and received using
9862 * the Socket::MSG_OOB flag and is typically limited to streams.
9863 */
9864static VALUE
9865io_wait_priority(int argc, VALUE *argv, VALUE io)
9866{
9867 rb_io_t *fptr = NULL;
9868
9869 RB_IO_POINTER(io, fptr);
9871
9872 if (rb_io_read_pending(fptr)) return Qtrue;
9873
9874 rb_check_arity(argc, 0, 1);
9875 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9876
9877 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9878}
9879
9880static int
9881wait_mode_sym(VALUE mode)
9882{
9883 if (mode == ID2SYM(rb_intern("r"))) {
9884 return RB_WAITFD_IN;
9885 }
9886 if (mode == ID2SYM(rb_intern("read"))) {
9887 return RB_WAITFD_IN;
9888 }
9889 if (mode == ID2SYM(rb_intern("readable"))) {
9890 return RB_WAITFD_IN;
9891 }
9892 if (mode == ID2SYM(rb_intern("w"))) {
9893 return RB_WAITFD_OUT;
9894 }
9895 if (mode == ID2SYM(rb_intern("write"))) {
9896 return RB_WAITFD_OUT;
9897 }
9898 if (mode == ID2SYM(rb_intern("writable"))) {
9899 return RB_WAITFD_OUT;
9900 }
9901 if (mode == ID2SYM(rb_intern("rw"))) {
9902 return RB_WAITFD_IN|RB_WAITFD_OUT;
9903 }
9904 if (mode == ID2SYM(rb_intern("read_write"))) {
9905 return RB_WAITFD_IN|RB_WAITFD_OUT;
9906 }
9907 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9908 return RB_WAITFD_IN|RB_WAITFD_OUT;
9909 }
9910
9911 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9912}
9913
9914static inline enum rb_io_event
9915io_event_from_value(VALUE value)
9916{
9917 int events = RB_NUM2INT(value);
9918
9919 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9920
9921 return events;
9922}
9923
9924/*
9925 * call-seq:
9926 * io.wait(events, timeout) -> event mask, false or nil
9927 * io.wait(timeout = nil, mode = :read) -> self, true, or false
9928 *
9929 * Waits until the IO becomes ready for the specified events and returns the
9930 * subset of events that become ready, or a falsy value when times out.
9931 *
9932 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9933 * +IO::PRIORITY+.
9934 *
9935 * Returns an event mask (truthy value) immediately when buffered data is available.
9936 *
9937 * Optional parameter +mode+ is one of +:read+, +:write+, or
9938 * +:read_write+.
9939 */
9940
9941static VALUE
9942io_wait(int argc, VALUE *argv, VALUE io)
9943{
9944 VALUE timeout = Qundef;
9945 enum rb_io_event events = 0;
9946 int return_io = 0;
9947
9948 // The documented signature for this method is actually incorrect.
9949 // A single timeout is allowed in any position, and multiple symbols can be given.
9950 // Whether this is intentional or not, I don't know, and as such I consider this to
9951 // be a legacy/slow path.
9952 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9953 // We'd prefer to return the actual mask, but this form would return the io itself:
9954 return_io = 1;
9955
9956 // Slow/messy path:
9957 for (int i = 0; i < argc; i += 1) {
9958 if (RB_SYMBOL_P(argv[i])) {
9959 events |= wait_mode_sym(argv[i]);
9960 }
9961 else if (UNDEF_P(timeout)) {
9962 rb_time_interval(timeout = argv[i]);
9963 }
9964 else {
9965 rb_raise(rb_eArgError, "timeout given more than once");
9966 }
9967 }
9968
9969 if (UNDEF_P(timeout)) timeout = Qnil;
9970
9971 if (events == 0) {
9972 events = RUBY_IO_READABLE;
9973 }
9974 }
9975 else /* argc == 2 and neither are symbols */ {
9976 // This is the fast path:
9977 events = io_event_from_value(argv[0]);
9978 timeout = argv[1];
9979 }
9980
9981 if (events & RUBY_IO_READABLE) {
9982 rb_io_t *fptr = NULL;
9983 RB_IO_POINTER(io, fptr);
9984
9985 if (rb_io_read_pending(fptr)) {
9986 // This was the original behaviour:
9987 if (return_io) return Qtrue;
9988 // New behaviour always returns an event mask:
9989 else return RB_INT2NUM(RUBY_IO_READABLE);
9990 }
9991 }
9992
9993 return io_wait_event(io, events, timeout, return_io);
9994}
9995
9996static void
9997argf_mark(void *ptr)
9998{
9999 struct argf *p = ptr;
10000 rb_gc_mark(p->filename);
10001 rb_gc_mark(p->current_file);
10002 rb_gc_mark(p->argv);
10003 rb_gc_mark(p->inplace);
10004 rb_gc_mark(p->encs.ecopts);
10005}
10006
10007static size_t
10008argf_memsize(const void *ptr)
10009{
10010 const struct argf *p = ptr;
10011 size_t size = sizeof(*p);
10012 return size;
10013}
10014
10015static void
10016argf_compact(void *ptr)
10017{
10018 struct argf *p = ptr;
10019 p->filename = rb_gc_location(p->filename);
10020 p->current_file = rb_gc_location(p->current_file);
10021 p->argv = rb_gc_location(p->argv);
10022 p->inplace = rb_gc_location(p->inplace);
10023 p->encs.ecopts = rb_gc_location(p->encs.ecopts);
10024}
10025
10026static const rb_data_type_t argf_type = {
10027 "ARGF",
10028 {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_compact},
10029 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
10030};
10031
10032static inline void
10033argf_init(struct argf *p, VALUE v)
10034{
10035 p->filename = Qnil;
10036 p->current_file = Qnil;
10037 p->lineno = 0;
10038 p->argv = v;
10039}
10040
10041static VALUE
10042argf_alloc(VALUE klass)
10043{
10044 struct argf *p;
10045 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10046
10047 argf_init(p, Qnil);
10048 return argf;
10049}
10050
10051#undef rb_argv
10052
10053/* :nodoc: */
10054static VALUE
10055argf_initialize(VALUE argf, VALUE argv)
10056{
10057 memset(&ARGF, 0, sizeof(ARGF));
10058 argf_init(&ARGF, argv);
10059
10060 return argf;
10061}
10062
10063/* :nodoc: */
10064static VALUE
10065argf_initialize_copy(VALUE argf, VALUE orig)
10066{
10067 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10068 ARGF = argf_of(orig);
10069 ARGF.argv = rb_obj_dup(ARGF.argv);
10070 return argf;
10071}
10072
10073/*
10074 * call-seq:
10075 * ARGF.lineno = integer -> integer
10076 *
10077 * Sets the line number of ARGF as a whole to the given Integer.
10078 *
10079 * ARGF sets the line number automatically as you read data, so normally
10080 * you will not need to set it explicitly. To access the current line number
10081 * use ARGF.lineno.
10082 *
10083 * For example:
10084 *
10085 * ARGF.lineno #=> 0
10086 * ARGF.readline #=> "This is line 1\n"
10087 * ARGF.lineno #=> 1
10088 * ARGF.lineno = 0 #=> 0
10089 * ARGF.lineno #=> 0
10090 */
10091static VALUE
10092argf_set_lineno(VALUE argf, VALUE val)
10093{
10094 ARGF.lineno = NUM2INT(val);
10095 ARGF.last_lineno = ARGF.lineno;
10096 return val;
10097}
10098
10099/*
10100 * call-seq:
10101 * ARGF.lineno -> integer
10102 *
10103 * Returns the current line number of ARGF as a whole. This value
10104 * can be set manually with ARGF.lineno=.
10105 *
10106 * For example:
10107 *
10108 * ARGF.lineno #=> 0
10109 * ARGF.readline #=> "This is line 1\n"
10110 * ARGF.lineno #=> 1
10111 */
10112static VALUE
10113argf_lineno(VALUE argf)
10114{
10115 return INT2FIX(ARGF.lineno);
10116}
10117
10118static VALUE
10119argf_forward(int argc, VALUE *argv, VALUE argf)
10120{
10121 return forward_current(rb_frame_this_func(), argc, argv);
10122}
10123
10124#define next_argv() argf_next_argv(argf)
10125#define ARGF_GENERIC_INPUT_P() \
10126 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10127#define ARGF_FORWARD(argc, argv) do {\
10128 if (ARGF_GENERIC_INPUT_P())\
10129 return argf_forward((argc), (argv), argf);\
10130} while (0)
10131#define NEXT_ARGF_FORWARD(argc, argv) do {\
10132 if (!next_argv()) return Qnil;\
10133 ARGF_FORWARD((argc), (argv));\
10134} while (0)
10135
10136static void
10137argf_close(VALUE argf)
10138{
10139 VALUE file = ARGF.current_file;
10140 if (file == rb_stdin) return;
10141 if (RB_TYPE_P(file, T_FILE)) {
10142 rb_io_set_write_io(file, Qnil);
10143 }
10144 io_close(file);
10145 ARGF.init_p = -1;
10146}
10147
10148static int
10149argf_next_argv(VALUE argf)
10150{
10151 char *fn;
10152 rb_io_t *fptr;
10153 int stdout_binmode = 0;
10154 enum rb_io_mode fmode;
10155
10156 VALUE r_stdout = rb_ractor_stdout();
10157
10158 if (RB_TYPE_P(r_stdout, T_FILE)) {
10159 GetOpenFile(r_stdout, fptr);
10160 if (fptr->mode & FMODE_BINMODE)
10161 stdout_binmode = 1;
10162 }
10163
10164 if (ARGF.init_p == 0) {
10165 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10166 ARGF.next_p = 1;
10167 }
10168 else {
10169 ARGF.next_p = -1;
10170 }
10171 ARGF.init_p = 1;
10172 }
10173 else {
10174 if (NIL_P(ARGF.argv)) {
10175 ARGF.next_p = -1;
10176 }
10177 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10178 ARGF.next_p = 1;
10179 }
10180 }
10181
10182 if (ARGF.next_p == 1) {
10183 if (ARGF.init_p == 1) argf_close(argf);
10184 retry:
10185 if (RARRAY_LEN(ARGF.argv) > 0) {
10186 VALUE filename = rb_ary_shift(ARGF.argv);
10187 FilePathValue(filename);
10188 ARGF.filename = filename;
10189 filename = rb_str_encode_ospath(filename);
10190 fn = StringValueCStr(filename);
10191 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10192 ARGF.current_file = rb_stdin;
10193 if (ARGF.inplace) {
10194 rb_warn("Can't do inplace edit for stdio; skipping");
10195 goto retry;
10196 }
10197 }
10198 else {
10199 VALUE write_io = Qnil;
10200 int fr = rb_sysopen(filename, O_RDONLY, 0);
10201
10202 if (ARGF.inplace) {
10203 struct stat st;
10204#ifndef NO_SAFE_RENAME
10205 struct stat st2;
10206#endif
10207 VALUE str;
10208 int fw;
10209
10210 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10211 rb_io_close(r_stdout);
10212 }
10213 fstat(fr, &st);
10214 str = filename;
10215 if (!NIL_P(ARGF.inplace)) {
10216 VALUE suffix = ARGF.inplace;
10217 str = rb_str_dup(str);
10218 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10219 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10220 rb_enc_get(suffix), 0, Qnil))) {
10221 rb_str_append(str, suffix);
10222 }
10223#ifdef NO_SAFE_RENAME
10224 (void)close(fr);
10225 (void)unlink(RSTRING_PTR(str));
10226 if (rename(fn, RSTRING_PTR(str)) < 0) {
10227 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10228 filename, str, strerror(errno));
10229 goto retry;
10230 }
10231 fr = rb_sysopen(str, O_RDONLY, 0);
10232#else
10233 if (rename(fn, RSTRING_PTR(str)) < 0) {
10234 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10235 filename, str, strerror(errno));
10236 close(fr);
10237 goto retry;
10238 }
10239#endif
10240 }
10241 else {
10242#ifdef NO_SAFE_RENAME
10243 rb_fatal("Can't do inplace edit without backup");
10244#else
10245 if (unlink(fn) < 0) {
10246 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10247 filename, strerror(errno));
10248 close(fr);
10249 goto retry;
10250 }
10251#endif
10252 }
10253 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10254#ifndef NO_SAFE_RENAME
10255 fstat(fw, &st2);
10256#ifdef HAVE_FCHMOD
10257 fchmod(fw, st.st_mode);
10258#else
10259 chmod(fn, st.st_mode);
10260#endif
10261 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10262 int err;
10263#ifdef HAVE_FCHOWN
10264 err = fchown(fw, st.st_uid, st.st_gid);
10265#else
10266 err = chown(fn, st.st_uid, st.st_gid);
10267#endif
10268 if (err && getuid() == 0 && st2.st_uid == 0) {
10269 const char *wkfn = RSTRING_PTR(filename);
10270 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10271 filename, str, strerror(errno));
10272 (void)close(fr);
10273 (void)close(fw);
10274 (void)unlink(wkfn);
10275 goto retry;
10276 }
10277 }
10278#endif
10279 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10280 rb_ractor_stdout_set(write_io);
10281 if (stdout_binmode) rb_io_binmode(rb_stdout);
10282 }
10283 fmode = FMODE_READABLE;
10284 if (!ARGF.binmode) {
10285 fmode |= DEFAULT_TEXTMODE;
10286 }
10287 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10288 if (!NIL_P(write_io)) {
10289 rb_io_set_write_io(ARGF.current_file, write_io);
10290 }
10291 RB_GC_GUARD(filename);
10292 }
10293 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10294 GetOpenFile(ARGF.current_file, fptr);
10295 if (ARGF.encs.enc) {
10296 fptr->encs = ARGF.encs;
10297 clear_codeconv(fptr);
10298 }
10299 else {
10300 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10301 if (!ARGF.binmode) {
10303#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10304 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10305#endif
10306 }
10307 }
10308 ARGF.next_p = 0;
10309 }
10310 else {
10311 ARGF.next_p = 1;
10312 return FALSE;
10313 }
10314 }
10315 else if (ARGF.next_p == -1) {
10316 ARGF.current_file = rb_stdin;
10317 ARGF.filename = rb_str_new2("-");
10318 if (ARGF.inplace) {
10319 rb_warn("Can't do inplace edit for stdio");
10320 rb_ractor_stdout_set(orig_stdout);
10321 }
10322 }
10323 if (ARGF.init_p == -1) ARGF.init_p = 1;
10324 return TRUE;
10325}
10326
10327static VALUE
10328argf_getline(int argc, VALUE *argv, VALUE argf)
10329{
10330 VALUE line;
10331 long lineno = ARGF.lineno;
10332
10333 retry:
10334 if (!next_argv()) return Qnil;
10335 if (ARGF_GENERIC_INPUT_P()) {
10336 line = forward_current(idGets, argc, argv);
10337 }
10338 else {
10339 if (argc == 0 && rb_rs == rb_default_rs) {
10340 line = rb_io_gets(ARGF.current_file);
10341 }
10342 else {
10343 line = rb_io_getline(argc, argv, ARGF.current_file);
10344 }
10345 if (NIL_P(line) && ARGF.next_p != -1) {
10346 argf_close(argf);
10347 ARGF.next_p = 1;
10348 goto retry;
10349 }
10350 }
10351 if (!NIL_P(line)) {
10352 ARGF.lineno = ++lineno;
10353 ARGF.last_lineno = ARGF.lineno;
10354 }
10355 return line;
10356}
10357
10358static VALUE
10359argf_lineno_getter(ID id, VALUE *var)
10360{
10361 VALUE argf = *var;
10362 return INT2FIX(ARGF.last_lineno);
10363}
10364
10365static void
10366argf_lineno_setter(VALUE val, ID id, VALUE *var)
10367{
10368 VALUE argf = *var;
10369 int n = NUM2INT(val);
10370 ARGF.last_lineno = ARGF.lineno = n;
10371}
10372
10373void
10374rb_reset_argf_lineno(long n)
10375{
10376 ARGF.last_lineno = ARGF.lineno = n;
10377}
10378
10379static VALUE argf_gets(int, VALUE *, VALUE);
10380
10381/*
10382 * call-seq:
10383 * gets(sep=$/ [, getline_args]) -> string or nil
10384 * gets(limit [, getline_args]) -> string or nil
10385 * gets(sep, limit [, getline_args]) -> string or nil
10386 *
10387 * Returns (and assigns to <code>$_</code>) the next line from the list
10388 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10389 * no files are present on the command line. Returns +nil+ at end of
10390 * file. The optional argument specifies the record separator. The
10391 * separator is included with the contents of each record. A separator
10392 * of +nil+ reads the entire contents, and a zero-length separator
10393 * reads the input one paragraph at a time, where paragraphs are
10394 * divided by two consecutive newlines. If the first argument is an
10395 * integer, or optional second argument is given, the returning string
10396 * would not be longer than the given value in bytes. If multiple
10397 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10398 * the contents one file at a time.
10399 *
10400 * ARGV << "testfile"
10401 * print while gets
10402 *
10403 * <em>produces:</em>
10404 *
10405 * This is line one
10406 * This is line two
10407 * This is line three
10408 * And so on...
10409 *
10410 * The style of programming using <code>$_</code> as an implicit
10411 * parameter is gradually losing favor in the Ruby community.
10412 */
10413
10414static VALUE
10415rb_f_gets(int argc, VALUE *argv, VALUE recv)
10416{
10417 if (recv == argf) {
10418 return argf_gets(argc, argv, argf);
10419 }
10420 return forward(argf, idGets, argc, argv);
10421}
10422
10423/*
10424 * call-seq:
10425 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10426 * ARGF.gets(limit [, getline_args]) -> string or nil
10427 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10428 *
10429 * Returns the next line from the current file in ARGF.
10430 *
10431 * By default lines are assumed to be separated by <code>$/</code>;
10432 * to use a different character as a separator, supply it as a String
10433 * for the _sep_ argument.
10434 *
10435 * The optional _limit_ argument specifies how many characters of each line
10436 * to return. By default all characters are returned.
10437 *
10438 * See IO.readlines for details about getline_args.
10439 *
10440 */
10441static VALUE
10442argf_gets(int argc, VALUE *argv, VALUE argf)
10443{
10444 VALUE line;
10445
10446 line = argf_getline(argc, argv, argf);
10447 rb_lastline_set(line);
10448
10449 return line;
10450}
10451
10452VALUE
10454{
10455 VALUE line;
10456
10457 if (rb_rs != rb_default_rs) {
10458 return rb_f_gets(0, 0, argf);
10459 }
10460
10461 retry:
10462 if (!next_argv()) return Qnil;
10463 line = rb_io_gets(ARGF.current_file);
10464 if (NIL_P(line) && ARGF.next_p != -1) {
10465 rb_io_close(ARGF.current_file);
10466 ARGF.next_p = 1;
10467 goto retry;
10468 }
10469 rb_lastline_set(line);
10470 if (!NIL_P(line)) {
10471 ARGF.lineno++;
10472 ARGF.last_lineno = ARGF.lineno;
10473 }
10474
10475 return line;
10476}
10477
10478static VALUE argf_readline(int, VALUE *, VALUE);
10479
10480/*
10481 * call-seq:
10482 * readline(sep = $/, chomp: false) -> string
10483 * readline(limit, chomp: false) -> string
10484 * readline(sep, limit, chomp: false) -> string
10485 *
10486 * Equivalent to method Kernel#gets, except that it raises an exception
10487 * if called at end-of-stream:
10488 *
10489 * $ cat t.txt | ruby -e "p readlines; readline"
10490 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10491 * in `readline': end of file reached (EOFError)
10492 *
10493 * Optional keyword argument +chomp+ specifies whether line separators
10494 * are to be omitted.
10495 */
10496
10497static VALUE
10498rb_f_readline(int argc, VALUE *argv, VALUE recv)
10499{
10500 if (recv == argf) {
10501 return argf_readline(argc, argv, argf);
10502 }
10503 return forward(argf, rb_intern("readline"), argc, argv);
10504}
10505
10506
10507/*
10508 * call-seq:
10509 * ARGF.readline(sep=$/) -> string
10510 * ARGF.readline(limit) -> string
10511 * ARGF.readline(sep, limit) -> string
10512 *
10513 * Returns the next line from the current file in ARGF.
10514 *
10515 * By default lines are assumed to be separated by <code>$/</code>;
10516 * to use a different character as a separator, supply it as a String
10517 * for the _sep_ argument.
10518 *
10519 * The optional _limit_ argument specifies how many characters of each line
10520 * to return. By default all characters are returned.
10521 *
10522 * An EOFError is raised at the end of the file.
10523 */
10524static VALUE
10525argf_readline(int argc, VALUE *argv, VALUE argf)
10526{
10527 VALUE line;
10528
10529 if (!next_argv()) rb_eof_error();
10530 ARGF_FORWARD(argc, argv);
10531 line = argf_gets(argc, argv, argf);
10532 if (NIL_P(line)) {
10533 rb_eof_error();
10534 }
10535
10536 return line;
10537}
10538
10539static VALUE argf_readlines(int, VALUE *, VALUE);
10540
10541/*
10542 * call-seq:
10543 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10544 * readlines(limit, chomp: false, **enc_opts) -> array
10545 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10546 *
10547 * Returns an array containing the lines returned by calling
10548 * Kernel#gets until the end-of-stream is reached;
10549 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10550 *
10551 * With only string argument +sep+ given,
10552 * returns the remaining lines as determined by line separator +sep+,
10553 * or +nil+ if none;
10554 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10555 *
10556 * # Default separator.
10557 * $ cat t.txt | ruby -e "p readlines"
10558 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10559 *
10560 * # Specified separator.
10561 * $ cat t.txt | ruby -e "p readlines 'li'"
10562 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10563 *
10564 * # Get-all separator.
10565 * $ cat t.txt | ruby -e "p readlines nil"
10566 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10567 *
10568 * # Get-paragraph separator.
10569 * $ cat t.txt | ruby -e "p readlines ''"
10570 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10571 *
10572 * With only integer argument +limit+ given,
10573 * limits the number of bytes in the line;
10574 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10575 *
10576 * $cat t.txt | ruby -e "p readlines 10"
10577 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10578 *
10579 * $cat t.txt | ruby -e "p readlines 11"
10580 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10581 *
10582 * $cat t.txt | ruby -e "p readlines 12"
10583 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10584 *
10585 * With arguments +sep+ and +limit+ given,
10586 * combines the two behaviors
10587 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10588 *
10589 * Optional keyword argument +chomp+ specifies whether line separators
10590 * are to be omitted:
10591 *
10592 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10593 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10594 *
10595 * Optional keyword arguments +enc_opts+ specify encoding options;
10596 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10597 *
10598 */
10599
10600static VALUE
10601rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10602{
10603 if (recv == argf) {
10604 return argf_readlines(argc, argv, argf);
10605 }
10606 return forward(argf, rb_intern("readlines"), argc, argv);
10607}
10608
10609/*
10610 * call-seq:
10611 * ARGF.readlines(sep = $/, chomp: false) -> array
10612 * ARGF.readlines(limit, chomp: false) -> array
10613 * ARGF.readlines(sep, limit, chomp: false) -> array
10614 *
10615 * ARGF.to_a(sep = $/, chomp: false) -> array
10616 * ARGF.to_a(limit, chomp: false) -> array
10617 * ARGF.to_a(sep, limit, chomp: false) -> array
10618 *
10619 * Reads each file in ARGF in its entirety, returning an Array containing
10620 * lines from the files. Lines are assumed to be separated by _sep_.
10621 *
10622 * lines = ARGF.readlines
10623 * lines[0] #=> "This is line one\n"
10624 *
10625 * See +IO.readlines+ for a full description of all options.
10626 */
10627static VALUE
10628argf_readlines(int argc, VALUE *argv, VALUE argf)
10629{
10630 long lineno = ARGF.lineno;
10631 VALUE lines, ary;
10632
10633 ary = rb_ary_new();
10634 while (next_argv()) {
10635 if (ARGF_GENERIC_INPUT_P()) {
10636 lines = forward_current(rb_intern("readlines"), argc, argv);
10637 }
10638 else {
10639 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10640 argf_close(argf);
10641 }
10642 ARGF.next_p = 1;
10643 rb_ary_concat(ary, lines);
10644 ARGF.lineno = lineno + RARRAY_LEN(ary);
10645 ARGF.last_lineno = ARGF.lineno;
10646 }
10647 ARGF.init_p = 0;
10648 return ary;
10649}
10650
10651/*
10652 * call-seq:
10653 * `command` -> string
10654 *
10655 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10656 * sets global variable <tt>$?</tt> to the process status.
10657 *
10658 * This method has potential security vulnerabilities if called with untrusted input;
10659 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10660 *
10661 * Examples:
10662 *
10663 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10664 * $ `echo oops && exit 99` # => "oops\n"
10665 * $ $? # => #<Process::Status: pid 17088 exit 99>
10666 * $ $?.status # => 99>
10667 *
10668 * The built-in syntax <tt>%x{...}</tt> uses this method.
10669 *
10670 */
10671
10672static VALUE
10673rb_f_backquote(VALUE obj, VALUE str)
10674{
10675 VALUE port;
10676 VALUE result;
10677 rb_io_t *fptr;
10678
10679 StringValue(str);
10680 rb_last_status_clear();
10681 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10682 if (NIL_P(port)) return rb_str_new(0,0);
10683
10684 GetOpenFile(port, fptr);
10685 result = read_all(fptr, remain_size(fptr), Qnil);
10686 rb_io_close(port);
10687 rb_io_fptr_cleanup_all(fptr);
10688 RB_GC_GUARD(port);
10689
10690 return result;
10691}
10692
10693#ifdef HAVE_SYS_SELECT_H
10694#include <sys/select.h>
10695#endif
10696
10697static VALUE
10698select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10699{
10700 VALUE res, list;
10701 rb_fdset_t *rp, *wp, *ep;
10702 rb_io_t *fptr;
10703 long i;
10704 int max = 0, n;
10705 int pending = 0;
10706 struct timeval timerec;
10707
10708 if (!NIL_P(read)) {
10709 Check_Type(read, T_ARRAY);
10710 for (i=0; i<RARRAY_LEN(read); i++) {
10711 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10712 rb_fd_set(fptr->fd, &fds[0]);
10713 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10714 pending++;
10715 rb_fd_set(fptr->fd, &fds[3]);
10716 }
10717 if (max < fptr->fd) max = fptr->fd;
10718 }
10719 if (pending) { /* no blocking if there's buffered data */
10720 timerec.tv_sec = timerec.tv_usec = 0;
10721 tp = &timerec;
10722 }
10723 rp = &fds[0];
10724 }
10725 else
10726 rp = 0;
10727
10728 if (!NIL_P(write)) {
10729 Check_Type(write, T_ARRAY);
10730 for (i=0; i<RARRAY_LEN(write); i++) {
10731 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10732 GetOpenFile(write_io, fptr);
10733 rb_fd_set(fptr->fd, &fds[1]);
10734 if (max < fptr->fd) max = fptr->fd;
10735 }
10736 wp = &fds[1];
10737 }
10738 else
10739 wp = 0;
10740
10741 if (!NIL_P(except)) {
10742 Check_Type(except, T_ARRAY);
10743 for (i=0; i<RARRAY_LEN(except); i++) {
10744 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10745 VALUE write_io = GetWriteIO(io);
10746 GetOpenFile(io, fptr);
10747 rb_fd_set(fptr->fd, &fds[2]);
10748 if (max < fptr->fd) max = fptr->fd;
10749 if (io != write_io) {
10750 GetOpenFile(write_io, fptr);
10751 rb_fd_set(fptr->fd, &fds[2]);
10752 if (max < fptr->fd) max = fptr->fd;
10753 }
10754 }
10755 ep = &fds[2];
10756 }
10757 else {
10758 ep = 0;
10759 }
10760
10761 max++;
10762
10763 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10764 if (n < 0) {
10765 rb_sys_fail(0);
10766 }
10767 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10768
10769 res = rb_ary_new2(3);
10770 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10771 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10772 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10773
10774 if (rp) {
10775 list = RARRAY_AREF(res, 0);
10776 for (i=0; i< RARRAY_LEN(read); i++) {
10777 VALUE obj = rb_ary_entry(read, i);
10778 VALUE io = rb_io_get_io(obj);
10779 GetOpenFile(io, fptr);
10780 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10781 rb_fd_isset(fptr->fd, &fds[3])) {
10782 rb_ary_push(list, obj);
10783 }
10784 }
10785 }
10786
10787 if (wp) {
10788 list = RARRAY_AREF(res, 1);
10789 for (i=0; i< RARRAY_LEN(write); i++) {
10790 VALUE obj = rb_ary_entry(write, i);
10791 VALUE io = rb_io_get_io(obj);
10792 VALUE write_io = GetWriteIO(io);
10793 GetOpenFile(write_io, fptr);
10794 if (rb_fd_isset(fptr->fd, &fds[1])) {
10795 rb_ary_push(list, obj);
10796 }
10797 }
10798 }
10799
10800 if (ep) {
10801 list = RARRAY_AREF(res, 2);
10802 for (i=0; i< RARRAY_LEN(except); i++) {
10803 VALUE obj = rb_ary_entry(except, i);
10804 VALUE io = rb_io_get_io(obj);
10805 VALUE write_io = GetWriteIO(io);
10806 GetOpenFile(io, fptr);
10807 if (rb_fd_isset(fptr->fd, &fds[2])) {
10808 rb_ary_push(list, obj);
10809 }
10810 else if (io != write_io) {
10811 GetOpenFile(write_io, fptr);
10812 if (rb_fd_isset(fptr->fd, &fds[2])) {
10813 rb_ary_push(list, obj);
10814 }
10815 }
10816 }
10817 }
10818
10819 return res; /* returns an empty array on interrupt */
10820}
10821
10823 VALUE read, write, except;
10824 struct timeval *timeout;
10825 rb_fdset_t fdsets[4];
10826};
10827
10828static VALUE
10829select_call(VALUE arg)
10830{
10831 struct select_args *p = (struct select_args *)arg;
10832
10833 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10834}
10835
10836static VALUE
10837select_end(VALUE arg)
10838{
10839 struct select_args *p = (struct select_args *)arg;
10840 int i;
10841
10842 for (i = 0; i < numberof(p->fdsets); ++i)
10843 rb_fd_term(&p->fdsets[i]);
10844 return Qnil;
10845}
10846
10847static VALUE sym_normal, sym_sequential, sym_random,
10848 sym_willneed, sym_dontneed, sym_noreuse;
10849
10850#ifdef HAVE_POSIX_FADVISE
10851struct io_advise_struct {
10852 int fd;
10853 int advice;
10854 rb_off_t offset;
10855 rb_off_t len;
10856};
10857
10858static VALUE
10859io_advise_internal(void *arg)
10860{
10861 struct io_advise_struct *ptr = arg;
10862 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10863}
10864
10865static VALUE
10866io_advise_sym_to_const(VALUE sym)
10867{
10868#ifdef POSIX_FADV_NORMAL
10869 if (sym == sym_normal)
10870 return INT2NUM(POSIX_FADV_NORMAL);
10871#endif
10872
10873#ifdef POSIX_FADV_RANDOM
10874 if (sym == sym_random)
10875 return INT2NUM(POSIX_FADV_RANDOM);
10876#endif
10877
10878#ifdef POSIX_FADV_SEQUENTIAL
10879 if (sym == sym_sequential)
10880 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10881#endif
10882
10883#ifdef POSIX_FADV_WILLNEED
10884 if (sym == sym_willneed)
10885 return INT2NUM(POSIX_FADV_WILLNEED);
10886#endif
10887
10888#ifdef POSIX_FADV_DONTNEED
10889 if (sym == sym_dontneed)
10890 return INT2NUM(POSIX_FADV_DONTNEED);
10891#endif
10892
10893#ifdef POSIX_FADV_NOREUSE
10894 if (sym == sym_noreuse)
10895 return INT2NUM(POSIX_FADV_NOREUSE);
10896#endif
10897
10898 return Qnil;
10899}
10900
10901static VALUE
10902do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10903{
10904 int rv;
10905 struct io_advise_struct ias;
10906 VALUE num_adv;
10907
10908 num_adv = io_advise_sym_to_const(advice);
10909
10910 /*
10911 * The platform doesn't support this hint. We don't raise exception, instead
10912 * silently ignore it. Because IO::advise is only hint.
10913 */
10914 if (NIL_P(num_adv))
10915 return Qnil;
10916
10917 ias.fd = fptr->fd;
10918 ias.advice = NUM2INT(num_adv);
10919 ias.offset = offset;
10920 ias.len = len;
10921
10922 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10923 if (rv && rv != ENOSYS) {
10924 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10925 it returns the error code. */
10926 VALUE message = rb_sprintf("%"PRIsVALUE" "
10927 "(%"PRI_OFFT_PREFIX"d, "
10928 "%"PRI_OFFT_PREFIX"d, "
10929 "%"PRIsVALUE")",
10930 fptr->pathv, offset, len, advice);
10931 rb_syserr_fail_str(rv, message);
10932 }
10933
10934 return Qnil;
10935}
10936
10937#endif /* HAVE_POSIX_FADVISE */
10938
10939static void
10940advice_arg_check(VALUE advice)
10941{
10942 if (!SYMBOL_P(advice))
10943 rb_raise(rb_eTypeError, "advice must be a Symbol");
10944
10945 if (advice != sym_normal &&
10946 advice != sym_sequential &&
10947 advice != sym_random &&
10948 advice != sym_willneed &&
10949 advice != sym_dontneed &&
10950 advice != sym_noreuse) {
10951 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10952 }
10953}
10954
10955/*
10956 * call-seq:
10957 * advise(advice, offset = 0, len = 0) -> nil
10958 *
10959 * Invokes Posix system call
10960 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10961 * which announces an intention to access data from the current file
10962 * in a particular manner.
10963 *
10964 * The arguments and results are platform-dependent.
10965 *
10966 * The relevant data is specified by:
10967 *
10968 * - +offset+: The offset of the first byte of data.
10969 * - +len+: The number of bytes to be accessed;
10970 * if +len+ is zero, or is larger than the number of bytes remaining,
10971 * all remaining bytes will be accessed.
10972 *
10973 * Argument +advice+ is one of the following symbols:
10974 *
10975 * - +:normal+: The application has no advice to give
10976 * about its access pattern for the specified data.
10977 * If no advice is given for an open file, this is the default assumption.
10978 * - +:sequential+: The application expects to access the specified data sequentially
10979 * (with lower offsets read before higher ones).
10980 * - +:random+: The specified data will be accessed in random order.
10981 * - +:noreuse+: The specified data will be accessed only once.
10982 * - +:willneed+: The specified data will be accessed in the near future.
10983 * - +:dontneed+: The specified data will not be accessed in the near future.
10984 *
10985 * Not implemented on all platforms.
10986 *
10987 */
10988static VALUE
10989rb_io_advise(int argc, VALUE *argv, VALUE io)
10990{
10991 VALUE advice, offset, len;
10992 rb_off_t off, l;
10993 rb_io_t *fptr;
10994
10995 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10996 advice_arg_check(advice);
10997
10998 io = GetWriteIO(io);
10999 GetOpenFile(io, fptr);
11000
11001 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
11002 l = NIL_P(len) ? 0 : NUM2OFFT(len);
11003
11004#ifdef HAVE_POSIX_FADVISE
11005 return do_io_advise(fptr, advice, off, l);
11006#else
11007 ((void)off, (void)l); /* Ignore all hint */
11008 return Qnil;
11009#endif
11010}
11011
11012static int
11013is_pos_inf(VALUE x)
11014{
11015 double f;
11016 if (!RB_FLOAT_TYPE_P(x))
11017 return 0;
11018 f = RFLOAT_VALUE(x);
11019 return isinf(f) && 0 < f;
11020}
11021
11022/*
11023 * call-seq:
11024 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11025 *
11026 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
11027 * which monitors multiple file descriptors,
11028 * waiting until one or more of the file descriptors
11029 * becomes ready for some class of I/O operation.
11030 *
11031 * Not implemented on all platforms.
11032 *
11033 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11034 * is an array of IO objects.
11035 *
11036 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11037 * interval in seconds.
11038 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11039 * +nil+ and +Float::INFINITY+ means no timeout.
11040 *
11041 * The method monitors the \IO objects given in all three arrays,
11042 * waiting for some to be ready;
11043 * returns a 3-element array whose elements are:
11044 *
11045 * - An array of the objects in +read_ios+ that are ready for reading.
11046 * - An array of the objects in +write_ios+ that are ready for writing.
11047 * - An array of the objects in +error_ios+ have pending exceptions.
11048 *
11049 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11050 *
11051 * \IO.select peeks the buffer of \IO objects for testing readability.
11052 * If the \IO buffer is not empty, \IO.select immediately notifies
11053 * readability. This "peek" only happens for \IO objects. It does not
11054 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11055 *
11056 * The best way to use \IO.select is invoking it after non-blocking
11057 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11058 * raise an exception which is extended by IO::WaitReadable or
11059 * IO::WaitWritable. The modules notify how the caller should wait
11060 * with \IO.select. If IO::WaitReadable is raised, the caller should
11061 * wait for reading. If IO::WaitWritable is raised, the caller should
11062 * wait for writing.
11063 *
11064 * So, blocking read (#readpartial) can be emulated using
11065 * #read_nonblock and \IO.select as follows:
11066 *
11067 * begin
11068 * result = io_like.read_nonblock(maxlen)
11069 * rescue IO::WaitReadable
11070 * IO.select([io_like])
11071 * retry
11072 * rescue IO::WaitWritable
11073 * IO.select(nil, [io_like])
11074 * retry
11075 * end
11076 *
11077 * Especially, the combination of non-blocking methods and \IO.select is
11078 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11079 * has #to_io method to return underlying IO object. IO.select calls
11080 * #to_io to obtain the file descriptor to wait.
11081 *
11082 * This means that readability notified by \IO.select doesn't mean
11083 * readability from OpenSSL::SSL::SSLSocket object.
11084 *
11085 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11086 * some data. \IO.select doesn't see the buffer. So \IO.select can
11087 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11088 *
11089 * However, several more complicated situations exist.
11090 *
11091 * SSL is a protocol which is sequence of records.
11092 * The record consists of multiple bytes.
11093 * So, the remote side of SSL sends a partial record, IO.select
11094 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11095 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11096 *
11097 * Also, the remote side can request SSL renegotiation which forces
11098 * the local SSL engine to write some data.
11099 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11100 * system call and it can block.
11101 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11102 * IO::WaitWritable instead of blocking.
11103 * So, the caller should wait for ready for writability as above
11104 * example.
11105 *
11106 * The combination of non-blocking methods and \IO.select is also useful
11107 * for streams such as tty, pipe socket socket when multiple processes
11108 * read from a stream.
11109 *
11110 * Finally, Linux kernel developers don't guarantee that
11111 * readability of select(2) means readability of following read(2) even
11112 * for a single process;
11113 * see {select(2)}[https://linux.die.net/man/2/select]
11114 *
11115 * Invoking \IO.select before IO#readpartial works well as usual.
11116 * However it is not the best way to use \IO.select.
11117 *
11118 * The writability notified by select(2) doesn't show
11119 * how many bytes are writable.
11120 * IO#write method blocks until given whole string is written.
11121 * So, <tt>IO#write(two or more bytes)</tt> can block after
11122 * writability is notified by \IO.select. IO#write_nonblock is required
11123 * to avoid the blocking.
11124 *
11125 * Blocking write (#write) can be emulated using #write_nonblock and
11126 * IO.select as follows: IO::WaitReadable should also be rescued for
11127 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11128 *
11129 * while 0 < string.bytesize
11130 * begin
11131 * written = io_like.write_nonblock(string)
11132 * rescue IO::WaitReadable
11133 * IO.select([io_like])
11134 * retry
11135 * rescue IO::WaitWritable
11136 * IO.select(nil, [io_like])
11137 * retry
11138 * end
11139 * string = string.byteslice(written..-1)
11140 * end
11141 *
11142 * Example:
11143 *
11144 * rp, wp = IO.pipe
11145 * mesg = "ping "
11146 * 100.times {
11147 * # IO.select follows IO#read. Not the best way to use IO.select.
11148 * rs, ws, = IO.select([rp], [wp])
11149 * if r = rs[0]
11150 * ret = r.read(5)
11151 * print ret
11152 * case ret
11153 * when /ping/
11154 * mesg = "pong\n"
11155 * when /pong/
11156 * mesg = "ping "
11157 * end
11158 * end
11159 * if w = ws[0]
11160 * w.write(mesg)
11161 * end
11162 * }
11163 *
11164 * Output:
11165 *
11166 * ping pong
11167 * ping pong
11168 * ping pong
11169 * (snipped)
11170 * ping
11171 *
11172 */
11173
11174static VALUE
11175rb_f_select(int argc, VALUE *argv, VALUE obj)
11176{
11177 VALUE scheduler = rb_fiber_scheduler_current();
11178 if (scheduler != Qnil) {
11179 // It's optionally supported.
11180 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11181 if (!UNDEF_P(result)) return result;
11182 }
11183
11184 VALUE timeout;
11185 struct select_args args;
11186 struct timeval timerec;
11187 int i;
11188
11189 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11190 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11191 args.timeout = 0;
11192 }
11193 else {
11194 timerec = rb_time_interval(timeout);
11195 args.timeout = &timerec;
11196 }
11197
11198 for (i = 0; i < numberof(args.fdsets); ++i)
11199 rb_fd_init(&args.fdsets[i]);
11200
11201 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11202}
11203
11204#ifdef IOCTL_REQ_TYPE
11205 typedef IOCTL_REQ_TYPE ioctl_req_t;
11206#else
11207 typedef int ioctl_req_t;
11208# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11209#endif
11210
11211#ifdef HAVE_IOCTL
11212struct ioctl_arg {
11213 int fd;
11214 ioctl_req_t cmd;
11215 long narg;
11216};
11217
11218static VALUE
11219nogvl_ioctl(void *ptr)
11220{
11221 struct ioctl_arg *arg = ptr;
11222
11223 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11224}
11225
11226static int
11227do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11228{
11229 int retval;
11230 struct ioctl_arg arg;
11231
11232 arg.fd = io->fd;
11233 arg.cmd = cmd;
11234 arg.narg = narg;
11235
11236 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11237
11238 return retval;
11239}
11240#endif
11241
11242#define DEFAULT_IOCTL_NARG_LEN (256)
11243
11244#if defined(__linux__) && defined(_IOC_SIZE)
11245static long
11246linux_iocparm_len(ioctl_req_t cmd)
11247{
11248 long len;
11249
11250 if ((cmd & 0xFFFF0000) == 0) {
11251 /* legacy and unstructured ioctl number. */
11252 return DEFAULT_IOCTL_NARG_LEN;
11253 }
11254
11255 len = _IOC_SIZE(cmd);
11256
11257 /* paranoia check for silly drivers which don't keep ioctl convention */
11258 if (len < DEFAULT_IOCTL_NARG_LEN)
11259 len = DEFAULT_IOCTL_NARG_LEN;
11260
11261 return len;
11262}
11263#endif
11264
11265#ifdef HAVE_IOCTL
11266static long
11267ioctl_narg_len(ioctl_req_t cmd)
11268{
11269 long len;
11270
11271#ifdef IOCPARM_MASK
11272#ifndef IOCPARM_LEN
11273#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11274#endif
11275#endif
11276#ifdef IOCPARM_LEN
11277 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11278#elif defined(__linux__) && defined(_IOC_SIZE)
11279 len = linux_iocparm_len(cmd);
11280#else
11281 /* otherwise guess at what's safe */
11282 len = DEFAULT_IOCTL_NARG_LEN;
11283#endif
11284
11285 return len;
11286}
11287#endif
11288
11289#ifdef HAVE_FCNTL
11290#ifdef __linux__
11291typedef long fcntl_arg_t;
11292#else
11293/* posix */
11294typedef int fcntl_arg_t;
11295#endif
11296
11297static long
11298fcntl_narg_len(ioctl_req_t cmd)
11299{
11300 long len;
11301
11302 switch (cmd) {
11303#ifdef F_DUPFD
11304 case F_DUPFD:
11305 len = sizeof(fcntl_arg_t);
11306 break;
11307#endif
11308#ifdef F_DUP2FD /* bsd specific */
11309 case F_DUP2FD:
11310 len = sizeof(int);
11311 break;
11312#endif
11313#ifdef F_DUPFD_CLOEXEC /* linux specific */
11314 case F_DUPFD_CLOEXEC:
11315 len = sizeof(fcntl_arg_t);
11316 break;
11317#endif
11318#ifdef F_GETFD
11319 case F_GETFD:
11320 len = 1;
11321 break;
11322#endif
11323#ifdef F_SETFD
11324 case F_SETFD:
11325 len = sizeof(fcntl_arg_t);
11326 break;
11327#endif
11328#ifdef F_GETFL
11329 case F_GETFL:
11330 len = 1;
11331 break;
11332#endif
11333#ifdef F_SETFL
11334 case F_SETFL:
11335 len = sizeof(fcntl_arg_t);
11336 break;
11337#endif
11338#ifdef F_GETOWN
11339 case F_GETOWN:
11340 len = 1;
11341 break;
11342#endif
11343#ifdef F_SETOWN
11344 case F_SETOWN:
11345 len = sizeof(fcntl_arg_t);
11346 break;
11347#endif
11348#ifdef F_GETOWN_EX /* linux specific */
11349 case F_GETOWN_EX:
11350 len = sizeof(struct f_owner_ex);
11351 break;
11352#endif
11353#ifdef F_SETOWN_EX /* linux specific */
11354 case F_SETOWN_EX:
11355 len = sizeof(struct f_owner_ex);
11356 break;
11357#endif
11358#ifdef F_GETLK
11359 case F_GETLK:
11360 len = sizeof(struct flock);
11361 break;
11362#endif
11363#ifdef F_SETLK
11364 case F_SETLK:
11365 len = sizeof(struct flock);
11366 break;
11367#endif
11368#ifdef F_SETLKW
11369 case F_SETLKW:
11370 len = sizeof(struct flock);
11371 break;
11372#endif
11373#ifdef F_READAHEAD /* bsd specific */
11374 case F_READAHEAD:
11375 len = sizeof(int);
11376 break;
11377#endif
11378#ifdef F_RDAHEAD /* Darwin specific */
11379 case F_RDAHEAD:
11380 len = sizeof(int);
11381 break;
11382#endif
11383#ifdef F_GETSIG /* linux specific */
11384 case F_GETSIG:
11385 len = 1;
11386 break;
11387#endif
11388#ifdef F_SETSIG /* linux specific */
11389 case F_SETSIG:
11390 len = sizeof(fcntl_arg_t);
11391 break;
11392#endif
11393#ifdef F_GETLEASE /* linux specific */
11394 case F_GETLEASE:
11395 len = 1;
11396 break;
11397#endif
11398#ifdef F_SETLEASE /* linux specific */
11399 case F_SETLEASE:
11400 len = sizeof(fcntl_arg_t);
11401 break;
11402#endif
11403#ifdef F_NOTIFY /* linux specific */
11404 case F_NOTIFY:
11405 len = sizeof(fcntl_arg_t);
11406 break;
11407#endif
11408
11409 default:
11410 len = 256;
11411 break;
11412 }
11413
11414 return len;
11415}
11416#else /* HAVE_FCNTL */
11417static long
11418fcntl_narg_len(ioctl_req_t cmd)
11419{
11420 return 0;
11421}
11422#endif /* HAVE_FCNTL */
11423
11424#define NARG_SENTINEL 17
11425
11426static long
11427setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11428{
11429 long narg = 0;
11430 VALUE arg = *argp;
11431
11432 if (!RTEST(arg)) {
11433 narg = 0;
11434 }
11435 else if (FIXNUM_P(arg)) {
11436 narg = FIX2LONG(arg);
11437 }
11438 else if (arg == Qtrue) {
11439 narg = 1;
11440 }
11441 else {
11442 VALUE tmp = rb_check_string_type(arg);
11443
11444 if (NIL_P(tmp)) {
11445 narg = NUM2LONG(arg);
11446 }
11447 else {
11448 char *ptr;
11449 long len, slen;
11450
11451 *argp = arg = tmp;
11452 len = narg_len(cmd);
11453 rb_str_modify(arg);
11454
11455 slen = RSTRING_LEN(arg);
11456 /* expand for data + sentinel. */
11457 if (slen < len+1) {
11458 rb_str_resize(arg, len+1);
11459 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11460 slen = len+1;
11461 }
11462 /* a little sanity check here */
11463 ptr = RSTRING_PTR(arg);
11464 ptr[slen - 1] = NARG_SENTINEL;
11465 narg = (long)(SIGNED_VALUE)ptr;
11466 }
11467 }
11468
11469 return narg;
11470}
11471
11472static VALUE
11473finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11474{
11475 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11476 if (RB_TYPE_P(arg, T_STRING)) {
11477 char *ptr;
11478 long slen;
11479 RSTRING_GETMEM(arg, ptr, slen);
11480 if (ptr[slen-1] != NARG_SENTINEL)
11481 rb_raise(rb_eArgError, "return value overflowed string");
11482 ptr[slen-1] = '\0';
11483 }
11484
11485 return INT2NUM(retval);
11486}
11487
11488#ifdef HAVE_IOCTL
11489static VALUE
11490rb_ioctl(VALUE io, VALUE req, VALUE arg)
11491{
11492 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11493 rb_io_t *fptr;
11494 long narg;
11495 int retval;
11496
11497 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11498 GetOpenFile(io, fptr);
11499 retval = do_ioctl(fptr, cmd, narg);
11500 return finish_narg(retval, arg, fptr);
11501}
11502
11503/*
11504 * call-seq:
11505 * ioctl(integer_cmd, argument) -> integer
11506 *
11507 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11508 * which issues a low-level command to an I/O device.
11509 *
11510 * Issues a low-level command to an I/O device.
11511 * The arguments and returned value are platform-dependent.
11512 * The effect of the call is platform-dependent.
11513 *
11514 * If argument +argument+ is an integer, it is passed directly;
11515 * if it is a string, it is interpreted as a binary sequence of bytes.
11516 *
11517 * Not implemented on all platforms.
11518 *
11519 */
11520
11521static VALUE
11522rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11523{
11524 VALUE req, arg;
11525
11526 rb_scan_args(argc, argv, "11", &req, &arg);
11527 return rb_ioctl(io, req, arg);
11528}
11529#else
11530#define rb_io_ioctl rb_f_notimplement
11531#endif
11532
11533#ifdef HAVE_FCNTL
11534struct fcntl_arg {
11535 int fd;
11536 int cmd;
11537 long narg;
11538};
11539
11540static VALUE
11541nogvl_fcntl(void *ptr)
11542{
11543 struct fcntl_arg *arg = ptr;
11544
11545#if defined(F_DUPFD)
11546 if (arg->cmd == F_DUPFD)
11547 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11548#endif
11549 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11550}
11551
11552static int
11553do_fcntl(struct rb_io *io, int cmd, long narg)
11554{
11555 int retval;
11556 struct fcntl_arg arg;
11557
11558 arg.fd = io->fd;
11559 arg.cmd = cmd;
11560 arg.narg = narg;
11561
11562 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11563 if (retval != -1) {
11564 switch (cmd) {
11565#if defined(F_DUPFD)
11566 case F_DUPFD:
11567#endif
11568#if defined(F_DUPFD_CLOEXEC)
11569 case F_DUPFD_CLOEXEC:
11570#endif
11571 rb_update_max_fd(retval);
11572 }
11573 }
11574
11575 return retval;
11576}
11577
11578static VALUE
11579rb_fcntl(VALUE io, VALUE req, VALUE arg)
11580{
11581 int cmd = NUM2INT(req);
11582 rb_io_t *fptr;
11583 long narg;
11584 int retval;
11585
11586 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11587 GetOpenFile(io, fptr);
11588 retval = do_fcntl(fptr, cmd, narg);
11589 return finish_narg(retval, arg, fptr);
11590}
11591
11592/*
11593 * call-seq:
11594 * fcntl(integer_cmd, argument) -> integer
11595 *
11596 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11597 * which provides a mechanism for issuing low-level commands to control or query
11598 * a file-oriented I/O stream. Arguments and results are platform
11599 * dependent.
11600 *
11601 * If +argument+ is a number, its value is passed directly;
11602 * if it is a string, it is interpreted as a binary sequence of bytes.
11603 * (Array#pack might be a useful way to build this string.)
11604 *
11605 * Not implemented on all platforms.
11606 *
11607 */
11608
11609static VALUE
11610rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11611{
11612 VALUE req, arg;
11613
11614 rb_scan_args(argc, argv, "11", &req, &arg);
11615 return rb_fcntl(io, req, arg);
11616}
11617#else
11618#define rb_io_fcntl rb_f_notimplement
11619#endif
11620
11621#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11622/*
11623 * call-seq:
11624 * syscall(integer_callno, *arguments) -> integer
11625 *
11626 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11627 * which calls a specified function.
11628 *
11629 * Calls the operating system function identified by +integer_callno+;
11630 * returns the result of the function or raises SystemCallError if it failed.
11631 * The effect of the call is platform-dependent.
11632 * The arguments and returned value are platform-dependent.
11633 *
11634 * For each of +arguments+: if it is an integer, it is passed directly;
11635 * if it is a string, it is interpreted as a binary sequence of bytes.
11636 * There may be as many as nine such arguments.
11637 *
11638 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11639 * are platform-dependent.
11640 *
11641 * Note: Method +syscall+ is essentially unsafe and unportable.
11642 * The DL (Fiddle) library is preferred for safer and a bit
11643 * more portable programming.
11644 *
11645 * Not implemented on all platforms.
11646 *
11647 */
11648
11649static VALUE
11650rb_f_syscall(int argc, VALUE *argv, VALUE _)
11651{
11652 VALUE arg[8];
11653#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11654# define SYSCALL __syscall
11655# define NUM2SYSCALLID(x) NUM2LONG(x)
11656# define RETVAL2NUM(x) LONG2NUM(x)
11657# if SIZEOF_LONG == 8
11658 long num, retval = -1;
11659# elif SIZEOF_LONG_LONG == 8
11660 long long num, retval = -1;
11661# else
11662# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11663# endif
11664#elif defined(__linux__)
11665# define SYSCALL syscall
11666# define NUM2SYSCALLID(x) NUM2LONG(x)
11667# define RETVAL2NUM(x) LONG2NUM(x)
11668 /*
11669 * Linux man page says, syscall(2) function prototype is below.
11670 *
11671 * int syscall(int number, ...);
11672 *
11673 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11674 */
11675 long num, retval = -1;
11676#else
11677# define SYSCALL syscall
11678# define NUM2SYSCALLID(x) NUM2INT(x)
11679# define RETVAL2NUM(x) INT2NUM(x)
11680 int num, retval = -1;
11681#endif
11682 int i;
11683
11684 if (RTEST(ruby_verbose)) {
11686 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11687 }
11688
11689 if (argc == 0)
11690 rb_raise(rb_eArgError, "too few arguments for syscall");
11691 if (argc > numberof(arg))
11692 rb_raise(rb_eArgError, "too many arguments for syscall");
11693 num = NUM2SYSCALLID(argv[0]); ++argv;
11694 for (i = argc - 1; i--; ) {
11695 VALUE v = rb_check_string_type(argv[i]);
11696
11697 if (!NIL_P(v)) {
11698 StringValue(v);
11699 rb_str_modify(v);
11700 arg[i] = (VALUE)StringValueCStr(v);
11701 }
11702 else {
11703 arg[i] = (VALUE)NUM2LONG(argv[i]);
11704 }
11705 }
11706
11707 switch (argc) {
11708 case 1:
11709 retval = SYSCALL(num);
11710 break;
11711 case 2:
11712 retval = SYSCALL(num, arg[0]);
11713 break;
11714 case 3:
11715 retval = SYSCALL(num, arg[0],arg[1]);
11716 break;
11717 case 4:
11718 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11719 break;
11720 case 5:
11721 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11722 break;
11723 case 6:
11724 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11725 break;
11726 case 7:
11727 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11728 break;
11729 case 8:
11730 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11731 break;
11732 }
11733
11734 if (retval == -1)
11735 rb_sys_fail(0);
11736 return RETVAL2NUM(retval);
11737#undef SYSCALL
11738#undef NUM2SYSCALLID
11739#undef RETVAL2NUM
11740}
11741#else
11742#define rb_f_syscall rb_f_notimplement
11743#endif
11744
11745static VALUE
11746io_new_instance(VALUE args)
11747{
11748 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11749}
11750
11751static rb_encoding *
11752find_encoding(VALUE v)
11753{
11754 rb_encoding *enc = rb_find_encoding(v);
11755 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11756 return enc;
11757}
11758
11759static void
11760io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11761{
11762 rb_encoding *enc, *enc2;
11763 int ecflags = fptr->encs.ecflags;
11764 VALUE ecopts, tmp;
11765
11766 if (!NIL_P(v2)) {
11767 enc2 = find_encoding(v1);
11768 tmp = rb_check_string_type(v2);
11769 if (!NIL_P(tmp)) {
11770 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11771 /* Special case - "-" => no transcoding */
11772 enc = enc2;
11773 enc2 = NULL;
11774 }
11775 else
11776 enc = find_encoding(v2);
11777 if (enc == enc2) {
11778 /* Special case - "-" => no transcoding */
11779 enc2 = NULL;
11780 }
11781 }
11782 else {
11783 enc = find_encoding(v2);
11784 if (enc == enc2) {
11785 /* Special case - "-" => no transcoding */
11786 enc2 = NULL;
11787 }
11788 }
11789 if (enc2 == rb_ascii8bit_encoding()) {
11790 /* If external is ASCII-8BIT, no transcoding */
11791 enc = enc2;
11792 enc2 = NULL;
11793 }
11794 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11795 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11796 }
11797 else {
11798 if (NIL_P(v1)) {
11799 /* Set to default encodings */
11800 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11801 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11802 ecopts = Qnil;
11803 }
11804 else {
11805 tmp = rb_check_string_type(v1);
11806 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11807 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11808 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11809 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11810 }
11811 else {
11812 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11813 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11814 ecopts = Qnil;
11815 }
11816 }
11817 }
11818 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11819 fptr->encs.enc = enc;
11820 fptr->encs.enc2 = enc2;
11821 fptr->encs.ecflags = ecflags;
11822 fptr->encs.ecopts = ecopts;
11823 clear_codeconv(fptr);
11824
11825}
11826
11828 rb_io_t *fptr;
11829 VALUE v1;
11830 VALUE v2;
11831 VALUE opt;
11832};
11833
11834static VALUE
11835io_encoding_set_v(VALUE v)
11836{
11837 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11838 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11839 return Qnil;
11840}
11841
11842static VALUE
11843pipe_pair_close(VALUE rw)
11844{
11845 VALUE *rwp = (VALUE *)rw;
11846 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11847}
11848
11849/*
11850 * call-seq:
11851 * IO.pipe(**opts) -> [read_io, write_io]
11852 * IO.pipe(enc, **opts) -> [read_io, write_io]
11853 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11854 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11855 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11856 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11857 *
11858 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11859 * connected to each other.
11860 *
11861 * If argument +enc_string+ is given, it must be a string containing one of:
11862 *
11863 * - The name of the encoding to be used as the external encoding.
11864 * - The colon-separated names of two encodings to be used as the external
11865 * and internal encodings.
11866 *
11867 * If argument +int_enc+ is given, it must be an Encoding object
11868 * or encoding name string that specifies the internal encoding to be used;
11869 * if argument +ext_enc+ is also given, it must be an Encoding object
11870 * or encoding name string that specifies the external encoding to be used.
11871 *
11872 * The string read from +read_io+ is tagged with the external encoding;
11873 * if an internal encoding is also specified, the string is converted
11874 * to, and tagged with, that encoding.
11875 *
11876 * If any encoding is specified,
11877 * optional hash arguments specify the conversion option.
11878 *
11879 * Optional keyword arguments +opts+ specify:
11880 *
11881 * - {Open Options}[rdoc-ref:IO@Open+Options].
11882 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11883 *
11884 * With no block given, returns the two endpoints in an array:
11885 *
11886 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11887 *
11888 * With a block given, calls the block with the two endpoints;
11889 * closes both endpoints and returns the value of the block:
11890 *
11891 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11892 *
11893 * Output:
11894 *
11895 * #<IO:fd 6>
11896 * #<IO:fd 7>
11897 *
11898 * Not available on all platforms.
11899 *
11900 * In the example below, the two processes close the ends of the pipe
11901 * that they are not using. This is not just a cosmetic nicety. The
11902 * read end of a pipe will not generate an end of file condition if
11903 * there are any writers with the pipe still open. In the case of the
11904 * parent process, the <tt>rd.read</tt> will never return if it
11905 * does not first issue a <tt>wr.close</tt>:
11906 *
11907 * rd, wr = IO.pipe
11908 *
11909 * if fork
11910 * wr.close
11911 * puts "Parent got: <#{rd.read}>"
11912 * rd.close
11913 * Process.wait
11914 * else
11915 * rd.close
11916 * puts 'Sending message to parent'
11917 * wr.write "Hi Dad"
11918 * wr.close
11919 * end
11920 *
11921 * <em>produces:</em>
11922 *
11923 * Sending message to parent
11924 * Parent got: <Hi Dad>
11925 *
11926 */
11927
11928static VALUE
11929rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11930{
11931 int pipes[2], state;
11932 VALUE r, w, args[3], v1, v2;
11933 VALUE opt;
11934 rb_io_t *fptr, *fptr2;
11935 struct io_encoding_set_args ies_args;
11936 enum rb_io_mode fmode = 0;
11937 VALUE ret;
11938
11939 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11940 if (rb_pipe(pipes) < 0)
11941 rb_sys_fail(0);
11942
11943 args[0] = klass;
11944 args[1] = INT2NUM(pipes[0]);
11945 args[2] = INT2FIX(O_RDONLY);
11946 r = rb_protect(io_new_instance, (VALUE)args, &state);
11947 if (state) {
11948 close(pipes[0]);
11949 close(pipes[1]);
11950 rb_jump_tag(state);
11951 }
11952 GetOpenFile(r, fptr);
11953
11954 ies_args.fptr = fptr;
11955 ies_args.v1 = v1;
11956 ies_args.v2 = v2;
11957 ies_args.opt = opt;
11958 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11959 if (state) {
11960 close(pipes[1]);
11961 io_close(r);
11962 rb_jump_tag(state);
11963 }
11964
11965 args[1] = INT2NUM(pipes[1]);
11966 args[2] = INT2FIX(O_WRONLY);
11967 w = rb_protect(io_new_instance, (VALUE)args, &state);
11968 if (state) {
11969 close(pipes[1]);
11970 if (!NIL_P(r)) rb_io_close(r);
11971 rb_jump_tag(state);
11972 }
11973 GetOpenFile(w, fptr2);
11974 rb_io_synchronized(fptr2);
11975
11976 extract_binmode(opt, &fmode);
11977
11978 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11981 }
11982
11983#if DEFAULT_TEXTMODE
11984 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11985 fptr->mode &= ~FMODE_TEXTMODE;
11986 setmode(fptr->fd, O_BINARY);
11987 }
11988#if RUBY_CRLF_ENVIRONMENT
11991 }
11992#endif
11993#endif
11994 fptr->mode |= fmode;
11995#if DEFAULT_TEXTMODE
11996 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11997 fptr2->mode &= ~FMODE_TEXTMODE;
11998 setmode(fptr2->fd, O_BINARY);
11999 }
12000#endif
12001 fptr2->mode |= fmode;
12002
12003 ret = rb_assoc_new(r, w);
12004 if (rb_block_given_p()) {
12005 VALUE rw[2];
12006 rw[0] = r;
12007 rw[1] = w;
12008 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12009 }
12010 return ret;
12011}
12012
12014 int argc;
12015 VALUE *argv;
12016 VALUE io;
12017};
12018
12019static void
12020open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12021{
12022 VALUE path, v;
12023 VALUE vmode = Qnil, vperm = Qnil;
12024
12025 path = *argv++;
12026 argc--;
12027 FilePathValue(path);
12028 arg->io = 0;
12029 arg->argc = argc;
12030 arg->argv = argv;
12031 if (NIL_P(opt)) {
12032 vmode = INT2NUM(O_RDONLY);
12033 vperm = INT2FIX(0666);
12034 }
12035 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12036 int n;
12037
12038 v = rb_to_array_type(v);
12039 n = RARRAY_LENINT(v);
12040 rb_check_arity(n, 0, 3); /* rb_io_open */
12041 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12042 }
12043 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12044}
12045
12046static VALUE
12047io_s_foreach(VALUE v)
12048{
12049 struct getline_arg *arg = (void *)v;
12050 VALUE str;
12051
12052 if (arg->limit == 0)
12053 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12054 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12055 rb_lastline_set(str);
12056 rb_yield(str);
12057 }
12059 return Qnil;
12060}
12061
12062/*
12063 * call-seq:
12064 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12065 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12066 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12067 * IO.foreach(...) -> an_enumerator
12068 *
12069 * Calls the block with each successive line read from the stream.
12070 *
12071 * When called from class \IO (but not subclasses of \IO),
12072 * this method has potential security vulnerabilities if called with untrusted input;
12073 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12074 *
12075 * The first argument must be a string that is the path to a file.
12076 *
12077 * With only argument +path+ given, parses lines from the file at the given +path+,
12078 * as determined by the default line separator,
12079 * and calls the block with each successive line:
12080 *
12081 * File.foreach('t.txt') {|line| p line }
12082 *
12083 * Output: the same as above.
12084 *
12085 * For both forms, command and path, the remaining arguments are the same.
12086 *
12087 * With argument +sep+ given, parses lines as determined by that line separator
12088 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12089 *
12090 * File.foreach('t.txt', 'li') {|line| p line }
12091 *
12092 * Output:
12093 *
12094 * "First li"
12095 * "ne\nSecond li"
12096 * "ne\n\nThird li"
12097 * "ne\nFourth li"
12098 * "ne\n"
12099 *
12100 * Each paragraph:
12101 *
12102 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12103 *
12104 * Output:
12105 *
12106 * "First line\nSecond line\n\n"
12107 * "Third line\nFourth line\n"
12108 *
12109 * With argument +limit+ given, parses lines as determined by the default
12110 * line separator and the given line-length limit
12111 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12112 *
12113 * File.foreach('t.txt', 7) {|line| p line }
12114 *
12115 * Output:
12116 *
12117 * "First l"
12118 * "ine\n"
12119 * "Second "
12120 * "line\n"
12121 * "\n"
12122 * "Third l"
12123 * "ine\n"
12124 * "Fourth l"
12125 * "line\n"
12126 *
12127 * With arguments +sep+ and +limit+ given,
12128 * combines the two behaviors
12129 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12130 *
12131 * Optional keyword arguments +opts+ specify:
12132 *
12133 * - {Open Options}[rdoc-ref:IO@Open+Options].
12134 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12135 * - {Line Options}[rdoc-ref:IO@Line+IO].
12136 *
12137 * Returns an Enumerator if no block is given.
12138 *
12139 */
12140
12141static VALUE
12142rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12143{
12144 VALUE opt;
12145 int orig_argc = argc;
12146 struct foreach_arg arg;
12147 struct getline_arg garg;
12148
12149 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12150 RETURN_ENUMERATOR(self, orig_argc, argv);
12151 extract_getline_args(argc-1, argv+1, &garg);
12152 open_key_args(self, argc, argv, opt, &arg);
12153 if (NIL_P(arg.io)) return Qnil;
12154 extract_getline_opts(opt, &garg);
12155 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12156 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12157}
12158
12159static VALUE
12160io_s_readlines(VALUE v)
12161{
12162 struct getline_arg *arg = (void *)v;
12163 return io_readlines(arg, arg->io);
12164}
12165
12166/*
12167 * call-seq:
12168 * IO.readlines(path, sep = $/, **opts) -> array
12169 * IO.readlines(path, limit, **opts) -> array
12170 * IO.readlines(path, sep, limit, **opts) -> array
12171 *
12172 * Returns an array of all lines read from the stream.
12173 *
12174 * When called from class \IO (but not subclasses of \IO),
12175 * this method has potential security vulnerabilities if called with untrusted input;
12176 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12177 *
12178 * The first argument must be a string that is the path to a file.
12179 *
12180 * With only argument +path+ given, parses lines from the file at the given +path+,
12181 * as determined by the default line separator,
12182 * and returns those lines in an array:
12183 *
12184 * IO.readlines('t.txt')
12185 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12186 *
12187 * With argument +sep+ given, parses lines as determined by that line separator
12188 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12189 *
12190 * # Ordinary separator.
12191 * IO.readlines('t.txt', 'li')
12192 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12193 * # Get-paragraphs separator.
12194 * IO.readlines('t.txt', '')
12195 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12196 * # Get-all separator.
12197 * IO.readlines('t.txt', nil)
12198 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12199 *
12200 * With argument +limit+ given, parses lines as determined by the default
12201 * line separator and the given line-length limit
12202 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12203 *
12204 * IO.readlines('t.txt', 7)
12205 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12206 *
12207 * With arguments +sep+ and +limit+ given,
12208 * combines the two behaviors
12209 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12210 *
12211 * Optional keyword arguments +opts+ specify:
12212 *
12213 * - {Open Options}[rdoc-ref:IO@Open+Options].
12214 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12215 * - {Line Options}[rdoc-ref:IO@Line+IO].
12216 *
12217 */
12218
12219static VALUE
12220rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12221{
12222 VALUE opt;
12223 struct foreach_arg arg;
12224 struct getline_arg garg;
12225
12226 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12227 extract_getline_args(argc-1, argv+1, &garg);
12228 open_key_args(io, argc, argv, opt, &arg);
12229 if (NIL_P(arg.io)) return Qnil;
12230 extract_getline_opts(opt, &garg);
12231 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12232 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12233}
12234
12235static VALUE
12236io_s_read(VALUE v)
12237{
12238 struct foreach_arg *arg = (void *)v;
12239 return io_read(arg->argc, arg->argv, arg->io);
12240}
12241
12242struct seek_arg {
12243 VALUE io;
12244 VALUE offset;
12245 int mode;
12246};
12247
12248static VALUE
12249seek_before_access(VALUE argp)
12250{
12251 struct seek_arg *arg = (struct seek_arg *)argp;
12252 rb_io_binmode(arg->io);
12253 return rb_io_seek(arg->io, arg->offset, arg->mode);
12254}
12255
12256/*
12257 * call-seq:
12258 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12259 *
12260 * Opens the stream, reads and returns some or all of its content,
12261 * and closes the stream; returns +nil+ if no bytes were read.
12262 *
12263 * When called from class \IO (but not subclasses of \IO),
12264 * this method has potential security vulnerabilities if called with untrusted input;
12265 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12266 *
12267 * The first argument must be a string that is the path to a file.
12268 *
12269 * With only argument +path+ given, reads in text mode and returns the entire content
12270 * of the file at the given path:
12271 *
12272 * IO.read('t.txt')
12273 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12274 *
12275 * On Windows, text mode can terminate reading and leave bytes in the file
12276 * unread when encountering certain special bytes. Consider using
12277 * IO.binread if all bytes in the file should be read.
12278 *
12279 * With argument +length+, returns +length+ bytes if available:
12280 *
12281 * IO.read('t.txt', 7) # => "First l"
12282 * IO.read('t.txt', 700)
12283 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12284 *
12285 * With arguments +length+ and +offset+, returns +length+ bytes
12286 * if available, beginning at the given +offset+:
12287 *
12288 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12289 * IO.read('t.txt', 10, 200) # => nil
12290 *
12291 * Optional keyword arguments +opts+ specify:
12292 *
12293 * - {Open Options}[rdoc-ref:IO@Open+Options].
12294 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12295 *
12296 */
12297
12298static VALUE
12299rb_io_s_read(int argc, VALUE *argv, VALUE io)
12300{
12301 VALUE opt, offset;
12302 long off;
12303 struct foreach_arg arg;
12304
12305 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12306 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12307 rb_raise(rb_eArgError, "negative offset %ld given", off);
12308 }
12309 open_key_args(io, argc, argv, opt, &arg);
12310 if (NIL_P(arg.io)) return Qnil;
12311 if (!NIL_P(offset)) {
12312 struct seek_arg sarg;
12313 int state = 0;
12314 sarg.io = arg.io;
12315 sarg.offset = offset;
12316 sarg.mode = SEEK_SET;
12317 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12318 if (state) {
12319 rb_io_close(arg.io);
12320 rb_jump_tag(state);
12321 }
12322 if (arg.argc == 2) arg.argc = 1;
12323 }
12324 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12325}
12326
12327/*
12328 * call-seq:
12329 * IO.binread(path, length = nil, offset = 0) -> string or nil
12330 *
12331 * Behaves like IO.read, except that the stream is opened in binary mode
12332 * with ASCII-8BIT encoding.
12333 *
12334 * When called from class \IO (but not subclasses of \IO),
12335 * this method has potential security vulnerabilities if called with untrusted input;
12336 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12337 *
12338 */
12339
12340static VALUE
12341rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12342{
12343 VALUE offset;
12344 struct foreach_arg arg;
12345 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12346 enum {
12347 oflags = O_RDONLY
12348#ifdef O_BINARY
12349 |O_BINARY
12350#endif
12351 };
12352 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12353
12354 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12355 FilePathValue(argv[0]);
12356 convconfig.enc = rb_ascii8bit_encoding();
12357 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12358 if (NIL_P(arg.io)) return Qnil;
12359 arg.argv = argv+1;
12360 arg.argc = (argc > 1) ? 1 : 0;
12361 if (!NIL_P(offset)) {
12362 struct seek_arg sarg;
12363 int state = 0;
12364 sarg.io = arg.io;
12365 sarg.offset = offset;
12366 sarg.mode = SEEK_SET;
12367 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12368 if (state) {
12369 rb_io_close(arg.io);
12370 rb_jump_tag(state);
12371 }
12372 }
12373 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12374}
12375
12376static VALUE
12377io_s_write0(VALUE v)
12378{
12379 struct write_arg *arg = (void *)v;
12380 return io_write(arg->io,arg->str,arg->nosync);
12381}
12382
12383static VALUE
12384io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12385{
12386 VALUE string, offset, opt;
12387 struct foreach_arg arg;
12388 struct write_arg warg;
12389
12390 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12391
12392 if (NIL_P(opt)) opt = rb_hash_new();
12393 else opt = rb_hash_dup(opt);
12394
12395
12396 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12397 int mode = O_WRONLY|O_CREAT;
12398#ifdef O_BINARY
12399 if (binary) mode |= O_BINARY;
12400#endif
12401 if (NIL_P(offset)) mode |= O_TRUNC;
12402 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12403 }
12404 open_key_args(klass, argc, argv, opt, &arg);
12405
12406#ifndef O_BINARY
12407 if (binary) rb_io_binmode_m(arg.io);
12408#endif
12409
12410 if (NIL_P(arg.io)) return Qnil;
12411 if (!NIL_P(offset)) {
12412 struct seek_arg sarg;
12413 int state = 0;
12414 sarg.io = arg.io;
12415 sarg.offset = offset;
12416 sarg.mode = SEEK_SET;
12417 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12418 if (state) {
12419 rb_io_close(arg.io);
12420 rb_jump_tag(state);
12421 }
12422 }
12423
12424 warg.io = arg.io;
12425 warg.str = string;
12426 warg.nosync = 0;
12427
12428 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12429}
12430
12431/*
12432 * call-seq:
12433 * IO.write(path, data, offset = 0, **opts) -> integer
12434 *
12435 * Opens the stream, writes the given +data+ to it,
12436 * and closes the stream; returns the number of bytes written.
12437 *
12438 * When called from class \IO (but not subclasses of \IO),
12439 * this method has potential security vulnerabilities if called with untrusted input;
12440 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12441 *
12442 * The first argument must be a string that is the path to a file.
12443 *
12444 * With only argument +path+ given, writes the given +data+ to the file at that path:
12445 *
12446 * IO.write('t.tmp', 'abc') # => 3
12447 * File.read('t.tmp') # => "abc"
12448 *
12449 * If +offset+ is zero (the default), the file is overwritten:
12450 *
12451 * IO.write('t.tmp', 'A') # => 1
12452 * File.read('t.tmp') # => "A"
12453 *
12454 * If +offset+ in within the file content, the file is partly overwritten:
12455 *
12456 * IO.write('t.tmp', 'abcdef') # => 3
12457 * File.read('t.tmp') # => "abcdef"
12458 * # Offset within content.
12459 * IO.write('t.tmp', '012', 2) # => 3
12460 * File.read('t.tmp') # => "ab012f"
12461 *
12462 * If +offset+ is outside the file content,
12463 * the file is padded with null characters <tt>"\u0000"</tt>:
12464 *
12465 * IO.write('t.tmp', 'xyz', 10) # => 3
12466 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12467 *
12468 * Optional keyword arguments +opts+ specify:
12469 *
12470 * - {Open Options}[rdoc-ref:IO@Open+Options].
12471 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12472 *
12473 */
12474
12475static VALUE
12476rb_io_s_write(int argc, VALUE *argv, VALUE io)
12477{
12478 return io_s_write(argc, argv, io, 0);
12479}
12480
12481/*
12482 * call-seq:
12483 * IO.binwrite(path, string, offset = 0) -> integer
12484 *
12485 * Behaves like IO.write, except that the stream is opened in binary mode
12486 * with ASCII-8BIT encoding.
12487 *
12488 * When called from class \IO (but not subclasses of \IO),
12489 * this method has potential security vulnerabilities if called with untrusted input;
12490 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12491 *
12492 */
12493
12494static VALUE
12495rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12496{
12497 return io_s_write(argc, argv, io, 1);
12498}
12499
12501 VALUE src;
12502 VALUE dst;
12503 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12504 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12505
12506 rb_io_t *src_fptr;
12507 rb_io_t *dst_fptr;
12508 unsigned close_src : 1;
12509 unsigned close_dst : 1;
12510 int error_no;
12511 rb_off_t total;
12512 const char *syserr;
12513 const char *notimp;
12514 VALUE th;
12515 struct stat src_stat;
12516 struct stat dst_stat;
12517#ifdef HAVE_FCOPYFILE
12518 copyfile_state_t copyfile_state;
12519#endif
12520};
12521
12522static void *
12523exec_interrupts(void *arg)
12524{
12525 VALUE th = (VALUE)arg;
12526 rb_thread_execute_interrupts(th);
12527 return NULL;
12528}
12529
12530/*
12531 * returns TRUE if the preceding system call was interrupted
12532 * so we can continue. If the thread was interrupted, we
12533 * reacquire the GVL to execute interrupts before continuing.
12534 */
12535static int
12536maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12537{
12538 switch (errno) {
12539 case EINTR:
12540#if defined(ERESTART)
12541 case ERESTART:
12542#endif
12543 if (rb_thread_interrupted(stp->th)) {
12544 if (has_gvl)
12545 rb_thread_execute_interrupts(stp->th);
12546 else
12547 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12548 }
12549 return TRUE;
12550 }
12551 return FALSE;
12552}
12553
12555 VALUE scheduler;
12556
12557 rb_io_t *fptr;
12558 short events;
12559
12560 VALUE result;
12561};
12562
12563static void *
12564fiber_scheduler_wait_for(void * _arguments)
12565{
12566 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12567
12568 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12569
12570 return NULL;
12571}
12572
12573#if USE_POLL
12574# define IOWAIT_SYSCALL "poll"
12575STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12576STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12577static int
12578nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12579{
12581 if (scheduler != Qnil) {
12582 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12583 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12584 return RTEST(args.result);
12585 }
12586
12587 int fd = fptr->fd;
12588 if (fd == -1) return 0;
12589
12590 struct pollfd fds;
12591
12592 fds.fd = fd;
12593 fds.events = events;
12594
12595 int timeout_milliseconds = -1;
12596
12597 if (timeout) {
12598 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12599 }
12600
12601 return poll(&fds, 1, timeout_milliseconds);
12602}
12603#else /* !USE_POLL */
12604# define IOWAIT_SYSCALL "select"
12605static int
12606nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12607{
12609 if (scheduler != Qnil) {
12610 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12611 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12612 return RTEST(args.result);
12613 }
12614
12615 int fd = fptr->fd;
12616
12617 if (fd == -1) {
12618 errno = EBADF;
12619 return -1;
12620 }
12621
12622 rb_fdset_t fds;
12623 int ret;
12624
12625 rb_fd_init(&fds);
12626 rb_fd_set(fd, &fds);
12627
12628 switch (events) {
12629 case RB_WAITFD_IN:
12630 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12631 break;
12632 case RB_WAITFD_OUT:
12633 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12634 break;
12635 default:
12636 VM_UNREACHABLE(nogvl_wait_for);
12637 }
12638
12639 rb_fd_term(&fds);
12640
12641 // On timeout, this returns 0.
12642 return ret;
12643}
12644#endif /* !USE_POLL */
12645
12646static int
12647maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12648{
12649 int ret;
12650
12651 do {
12652 if (has_gvl) {
12654 }
12655 else {
12656 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12657 }
12658 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12659
12660 if (ret < 0) {
12661 stp->syserr = IOWAIT_SYSCALL;
12662 stp->error_no = errno;
12663 return ret;
12664 }
12665 return 0;
12666}
12667
12668static int
12669nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12670{
12671 int ret;
12672
12673 do {
12674 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12675 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12676
12677 if (ret < 0) {
12678 stp->syserr = IOWAIT_SYSCALL;
12679 stp->error_no = errno;
12680 return ret;
12681 }
12682 return 0;
12683}
12684
12685#ifdef USE_COPY_FILE_RANGE
12686
12687static ssize_t
12688simple_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)
12689{
12690#ifdef HAVE_COPY_FILE_RANGE
12691 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12692#else
12693 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12694#endif
12695}
12696
12697static int
12698nogvl_copy_file_range(struct copy_stream_struct *stp)
12699{
12700 ssize_t ss;
12701 rb_off_t src_size;
12702 rb_off_t copy_length, src_offset, *src_offset_ptr;
12703
12704 if (!S_ISREG(stp->src_stat.st_mode))
12705 return 0;
12706
12707 src_size = stp->src_stat.st_size;
12708 src_offset = stp->src_offset;
12709 if (src_offset >= (rb_off_t)0) {
12710 src_offset_ptr = &src_offset;
12711 }
12712 else {
12713 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12714 }
12715
12716 copy_length = stp->copy_length;
12717 if (copy_length < (rb_off_t)0) {
12718 if (src_offset < (rb_off_t)0) {
12719 rb_off_t current_offset;
12720 errno = 0;
12721 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12722 if (current_offset < (rb_off_t)0 && errno) {
12723 stp->syserr = "lseek";
12724 stp->error_no = errno;
12725 return (int)current_offset;
12726 }
12727 copy_length = src_size - current_offset;
12728 }
12729 else {
12730 copy_length = src_size - src_offset;
12731 }
12732 }
12733
12734 retry_copy_file_range:
12735# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12736 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12737 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12738# else
12739 ss = (ssize_t)copy_length;
12740# endif
12741 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12742 if (0 < ss) {
12743 stp->total += ss;
12744 copy_length -= ss;
12745 if (0 < copy_length) {
12746 goto retry_copy_file_range;
12747 }
12748 }
12749 if (ss < 0) {
12750 if (maygvl_copy_stream_continue_p(0, stp)) {
12751 goto retry_copy_file_range;
12752 }
12753 switch (errno) {
12754 case EINVAL:
12755 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12756 docker container) */
12757#ifdef ENOSYS
12758 case ENOSYS:
12759#endif
12760#ifdef EXDEV
12761 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12762#endif
12763 return 0;
12764 case EAGAIN:
12765#if EWOULDBLOCK != EAGAIN
12766 case EWOULDBLOCK:
12767#endif
12768 {
12769 int ret = nogvl_copy_stream_wait_write(stp);
12770 if (ret < 0) return ret;
12771 }
12772 goto retry_copy_file_range;
12773 case EBADF:
12774 {
12775 int e = errno;
12776 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12777
12778 if (flags != -1 && flags & O_APPEND) {
12779 return 0;
12780 }
12781 errno = e;
12782 }
12783 }
12784 stp->syserr = "copy_file_range";
12785 stp->error_no = errno;
12786 return (int)ss;
12787 }
12788 return 1;
12789}
12790#endif
12791
12792#ifdef HAVE_FCOPYFILE
12793static int
12794nogvl_fcopyfile(struct copy_stream_struct *stp)
12795{
12796 rb_off_t cur, ss = 0;
12797 const rb_off_t src_offset = stp->src_offset;
12798 int ret;
12799
12800 if (stp->copy_length >= (rb_off_t)0) {
12801 /* copy_length can't be specified in fcopyfile(3) */
12802 return 0;
12803 }
12804
12805 if (!S_ISREG(stp->src_stat.st_mode))
12806 return 0;
12807
12808 if (!S_ISREG(stp->dst_stat.st_mode))
12809 return 0;
12810 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12811 return 0;
12812 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12813 /* fcopyfile(3) appends src IO to dst IO and then truncates
12814 * dst IO to src IO's original size. */
12815 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12816 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12817 if (end > (rb_off_t)0) return 0;
12818 }
12819
12820 if (src_offset > (rb_off_t)0) {
12821 rb_off_t r;
12822
12823 /* get current offset */
12824 errno = 0;
12825 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12826 if (cur < (rb_off_t)0 && errno) {
12827 stp->error_no = errno;
12828 return 1;
12829 }
12830
12831 errno = 0;
12832 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12833 if (r < (rb_off_t)0 && errno) {
12834 stp->error_no = errno;
12835 return 1;
12836 }
12837 }
12838
12839 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12840 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12841 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12842
12843 if (ret == 0) { /* success */
12844 stp->total = ss;
12845 if (src_offset > (rb_off_t)0) {
12846 rb_off_t r;
12847 errno = 0;
12848 /* reset offset */
12849 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12850 if (r < (rb_off_t)0 && errno) {
12851 stp->error_no = errno;
12852 return 1;
12853 }
12854 }
12855 }
12856 else {
12857 switch (errno) {
12858 case ENOTSUP:
12859 case EPERM:
12860 case EINVAL:
12861 return 0;
12862 }
12863 stp->syserr = "fcopyfile";
12864 stp->error_no = errno;
12865 return (int)ret;
12866 }
12867 return 1;
12868}
12869#endif
12870
12871#ifdef HAVE_SENDFILE
12872
12873# ifdef __linux__
12874# define USE_SENDFILE
12875
12876# ifdef HAVE_SYS_SENDFILE_H
12877# include <sys/sendfile.h>
12878# endif
12879
12880static ssize_t
12881simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12882{
12883 return sendfile(out_fd, in_fd, offset, (size_t)count);
12884}
12885
12886# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12887/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12888 * without cpuset -l 0.
12889 */
12890# define USE_SENDFILE
12891
12892static ssize_t
12893simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12894{
12895 int r;
12896 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12897 rb_off_t sbytes;
12898# ifdef __APPLE__
12899 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12900 sbytes = count;
12901# else
12902 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12903# endif
12904 if (r != 0 && sbytes == 0) return r;
12905 if (offset) {
12906 *offset += sbytes;
12907 }
12908 else {
12909 lseek(in_fd, sbytes, SEEK_CUR);
12910 }
12911 return (ssize_t)sbytes;
12912}
12913
12914# endif
12915
12916#endif
12917
12918#ifdef USE_SENDFILE
12919static int
12920nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12921{
12922 ssize_t ss;
12923 rb_off_t src_size;
12924 rb_off_t copy_length;
12925 rb_off_t src_offset;
12926 int use_pread;
12927
12928 if (!S_ISREG(stp->src_stat.st_mode))
12929 return 0;
12930
12931 src_size = stp->src_stat.st_size;
12932#ifndef __linux__
12933 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12934 return 0;
12935#endif
12936
12937 src_offset = stp->src_offset;
12938 use_pread = src_offset >= (rb_off_t)0;
12939
12940 copy_length = stp->copy_length;
12941 if (copy_length < (rb_off_t)0) {
12942 if (use_pread)
12943 copy_length = src_size - src_offset;
12944 else {
12945 rb_off_t cur;
12946 errno = 0;
12947 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12948 if (cur < (rb_off_t)0 && errno) {
12949 stp->syserr = "lseek";
12950 stp->error_no = errno;
12951 return (int)cur;
12952 }
12953 copy_length = src_size - cur;
12954 }
12955 }
12956
12957 retry_sendfile:
12958# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12959 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12960 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12961# else
12962 ss = (ssize_t)copy_length;
12963# endif
12964 if (use_pread) {
12965 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12966 }
12967 else {
12968 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12969 }
12970 if (0 < ss) {
12971 stp->total += ss;
12972 copy_length -= ss;
12973 if (0 < copy_length) {
12974 goto retry_sendfile;
12975 }
12976 }
12977 if (ss < 0) {
12978 if (maygvl_copy_stream_continue_p(0, stp))
12979 goto retry_sendfile;
12980 switch (errno) {
12981 case EINVAL:
12982#ifdef ENOSYS
12983 case ENOSYS:
12984#endif
12985#ifdef EOPNOTSUP
12986 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12987 see also: [Feature #16965] */
12988 case EOPNOTSUP:
12989#endif
12990 return 0;
12991 case EAGAIN:
12992#if EWOULDBLOCK != EAGAIN
12993 case EWOULDBLOCK:
12994#endif
12995 {
12996 int ret;
12997#ifndef __linux__
12998 /*
12999 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
13000 * select() reports regular files to always be "ready", so
13001 * there is no need to select() on it.
13002 * Other OSes may have the same limitation for sendfile() which
13003 * allow us to bypass maygvl_copy_stream_wait_read()...
13004 */
13005 ret = maygvl_copy_stream_wait_read(0, stp);
13006 if (ret < 0) return ret;
13007#endif
13008 ret = nogvl_copy_stream_wait_write(stp);
13009 if (ret < 0) return ret;
13010 }
13011 goto retry_sendfile;
13012 }
13013 stp->syserr = "sendfile";
13014 stp->error_no = errno;
13015 return (int)ss;
13016 }
13017 return 1;
13018}
13019#endif
13020
13021static ssize_t
13022maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13023{
13024 if (has_gvl)
13025 return rb_io_read_memory(fptr, buf, count);
13026 else
13027 return read(fptr->fd, buf, count);
13028}
13029
13030static ssize_t
13031maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13032{
13033 ssize_t ss;
13034 retry_read:
13035 if (offset < (rb_off_t)0) {
13036 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13037 }
13038 else {
13039 ss = pread(stp->src_fptr->fd, buf, len, offset);
13040 }
13041 if (ss == 0) {
13042 return 0;
13043 }
13044 if (ss < 0) {
13045 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13046 goto retry_read;
13047 switch (errno) {
13048 case EAGAIN:
13049#if EWOULDBLOCK != EAGAIN
13050 case EWOULDBLOCK:
13051#endif
13052 {
13053 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13054 if (ret < 0) return ret;
13055 }
13056 goto retry_read;
13057#ifdef ENOSYS
13058 case ENOSYS:
13059 stp->notimp = "pread";
13060 return ss;
13061#endif
13062 }
13063 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13064 stp->error_no = errno;
13065 }
13066 return ss;
13067}
13068
13069static int
13070nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13071{
13072 ssize_t ss;
13073 int off = 0;
13074 while (len) {
13075 ss = write(stp->dst_fptr->fd, buf+off, len);
13076 if (ss < 0) {
13077 if (maygvl_copy_stream_continue_p(0, stp))
13078 continue;
13079 if (io_again_p(errno)) {
13080 int ret = nogvl_copy_stream_wait_write(stp);
13081 if (ret < 0) return ret;
13082 continue;
13083 }
13084 stp->syserr = "write";
13085 stp->error_no = errno;
13086 return (int)ss;
13087 }
13088 off += (int)ss;
13089 len -= (int)ss;
13090 stp->total += ss;
13091 }
13092 return 0;
13093}
13094
13095static void
13096nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13097{
13098 char buf[1024*16];
13099 size_t len;
13100 ssize_t ss;
13101 int ret;
13102 rb_off_t copy_length;
13103 rb_off_t src_offset;
13104 int use_eof;
13105 int use_pread;
13106
13107 copy_length = stp->copy_length;
13108 use_eof = copy_length < (rb_off_t)0;
13109 src_offset = stp->src_offset;
13110 use_pread = src_offset >= (rb_off_t)0;
13111
13112 if (use_pread && stp->close_src) {
13113 rb_off_t r;
13114 errno = 0;
13115 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13116 if (r < (rb_off_t)0 && errno) {
13117 stp->syserr = "lseek";
13118 stp->error_no = errno;
13119 return;
13120 }
13121 src_offset = (rb_off_t)-1;
13122 use_pread = 0;
13123 }
13124
13125 while (use_eof || 0 < copy_length) {
13126 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13127 len = (size_t)copy_length;
13128 }
13129 else {
13130 len = sizeof(buf);
13131 }
13132 if (use_pread) {
13133 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13134 if (0 < ss)
13135 src_offset += ss;
13136 }
13137 else {
13138 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13139 }
13140 if (ss <= 0) /* EOF or error */
13141 return;
13142
13143 ret = nogvl_copy_stream_write(stp, buf, ss);
13144 if (ret < 0)
13145 return;
13146
13147 if (!use_eof)
13148 copy_length -= ss;
13149 }
13150}
13151
13152static void *
13153nogvl_copy_stream_func(void *arg)
13154{
13155 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13156#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13157 int ret;
13158#endif
13159
13160#ifdef USE_COPY_FILE_RANGE
13161 ret = nogvl_copy_file_range(stp);
13162 if (ret != 0)
13163 goto finish; /* error or success */
13164#endif
13165
13166#ifdef HAVE_FCOPYFILE
13167 ret = nogvl_fcopyfile(stp);
13168 if (ret != 0)
13169 goto finish; /* error or success */
13170#endif
13171
13172#ifdef USE_SENDFILE
13173 ret = nogvl_copy_stream_sendfile(stp);
13174 if (ret != 0)
13175 goto finish; /* error or success */
13176#endif
13177
13178 nogvl_copy_stream_read_write(stp);
13179
13180#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13181 finish:
13182#endif
13183 return 0;
13184}
13185
13186static VALUE
13187copy_stream_fallback_body(VALUE arg)
13188{
13189 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13190 const int buflen = 16*1024;
13191 VALUE n;
13192 VALUE buf = rb_str_buf_new(buflen);
13193 rb_off_t rest = stp->copy_length;
13194 rb_off_t off = stp->src_offset;
13195 ID read_method = id_readpartial;
13196
13197 if (!stp->src_fptr) {
13198 if (!rb_respond_to(stp->src, read_method)) {
13199 read_method = id_read;
13200 }
13201 }
13202
13203 while (1) {
13204 long numwrote;
13205 long l;
13206 rb_str_make_independent(buf);
13207 if (stp->copy_length < (rb_off_t)0) {
13208 l = buflen;
13209 }
13210 else {
13211 if (rest == 0) {
13212 rb_str_resize(buf, 0);
13213 break;
13214 }
13215 l = buflen < rest ? buflen : (long)rest;
13216 }
13217 if (!stp->src_fptr) {
13218 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13219
13220 if (read_method == id_read && NIL_P(rc))
13221 break;
13222 }
13223 else {
13224 ssize_t ss;
13225 rb_str_resize(buf, buflen);
13226 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13227 rb_str_resize(buf, ss > 0 ? ss : 0);
13228 if (ss < 0)
13229 return Qnil;
13230 if (ss == 0)
13231 rb_eof_error();
13232 if (off >= (rb_off_t)0)
13233 off += ss;
13234 }
13235 n = rb_io_write(stp->dst, buf);
13236 numwrote = NUM2LONG(n);
13237 stp->total += numwrote;
13238 rest -= numwrote;
13239 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13240 break;
13241 }
13242 }
13243
13244 return Qnil;
13245}
13246
13247static VALUE
13248copy_stream_fallback(struct copy_stream_struct *stp)
13249{
13250 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13251 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13252 }
13253 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13254 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13255 rb_eEOFError, (VALUE)0);
13256 return Qnil;
13257}
13258
13259static VALUE
13260copy_stream_body(VALUE arg)
13261{
13262 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13263 VALUE src_io = stp->src, dst_io = stp->dst;
13264 const int common_oflags = 0
13265#ifdef O_NOCTTY
13266 | O_NOCTTY
13267#endif
13268 ;
13269
13270 stp->th = rb_thread_current();
13271
13272 stp->total = 0;
13273
13274 if (src_io == argf ||
13275 !(RB_TYPE_P(src_io, T_FILE) ||
13276 RB_TYPE_P(src_io, T_STRING) ||
13277 rb_respond_to(src_io, rb_intern("to_path")))) {
13278 stp->src_fptr = NULL;
13279 }
13280 else {
13281 int stat_ret;
13282 VALUE tmp_io = rb_io_check_io(src_io);
13283 if (!NIL_P(tmp_io)) {
13284 src_io = tmp_io;
13285 }
13286 else if (!RB_TYPE_P(src_io, T_FILE)) {
13287 VALUE args[2];
13288 FilePathValue(src_io);
13289 args[0] = src_io;
13290 args[1] = INT2NUM(O_RDONLY|common_oflags);
13291 src_io = rb_class_new_instance(2, args, rb_cFile);
13292 stp->src = src_io;
13293 stp->close_src = 1;
13294 }
13295 RB_IO_POINTER(src_io, stp->src_fptr);
13296 rb_io_check_byte_readable(stp->src_fptr);
13297
13298 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13299 if (stat_ret < 0) {
13300 stp->syserr = "fstat";
13301 stp->error_no = errno;
13302 return Qnil;
13303 }
13304 }
13305
13306 if (dst_io == argf ||
13307 !(RB_TYPE_P(dst_io, T_FILE) ||
13308 RB_TYPE_P(dst_io, T_STRING) ||
13309 rb_respond_to(dst_io, rb_intern("to_path")))) {
13310 stp->dst_fptr = NULL;
13311 }
13312 else {
13313 int stat_ret;
13314 VALUE tmp_io = rb_io_check_io(dst_io);
13315 if (!NIL_P(tmp_io)) {
13316 dst_io = GetWriteIO(tmp_io);
13317 }
13318 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13319 VALUE args[3];
13320 FilePathValue(dst_io);
13321 args[0] = dst_io;
13322 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13323 args[2] = INT2FIX(0666);
13324 dst_io = rb_class_new_instance(3, args, rb_cFile);
13325 stp->dst = dst_io;
13326 stp->close_dst = 1;
13327 }
13328 else {
13329 dst_io = GetWriteIO(dst_io);
13330 stp->dst = dst_io;
13331 }
13332 RB_IO_POINTER(dst_io, stp->dst_fptr);
13333 rb_io_check_writable(stp->dst_fptr);
13334
13335 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13336 if (stat_ret < 0) {
13337 stp->syserr = "fstat";
13338 stp->error_no = errno;
13339 return Qnil;
13340 }
13341 }
13342
13343#ifdef O_BINARY
13344 if (stp->src_fptr)
13345 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13346#endif
13347 if (stp->dst_fptr)
13348 io_ascii8bit_binmode(stp->dst_fptr);
13349
13350 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13351 size_t len = stp->src_fptr->rbuf.len;
13352 VALUE str;
13353 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13354 len = (size_t)stp->copy_length;
13355 }
13356 str = rb_str_buf_new(len);
13357 rb_str_resize(str,len);
13358 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13359 if (stp->dst_fptr) { /* IO or filename */
13360 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13361 rb_sys_fail_on_write(stp->dst_fptr);
13362 }
13363 else /* others such as StringIO */
13364 rb_io_write(dst_io, str);
13365 rb_str_resize(str, 0);
13366 stp->total += len;
13367 if (stp->copy_length >= (rb_off_t)0)
13368 stp->copy_length -= len;
13369 }
13370
13371 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13372 rb_raise(rb_eIOError, "flush failed");
13373 }
13374
13375 if (stp->copy_length == 0)
13376 return Qnil;
13377
13378 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13379 return copy_stream_fallback(stp);
13380 }
13381
13382 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13383 return Qnil;
13384}
13385
13386static VALUE
13387copy_stream_finalize(VALUE arg)
13388{
13389 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13390
13391#ifdef HAVE_FCOPYFILE
13392 if (stp->copyfile_state) {
13393 copyfile_state_free(stp->copyfile_state);
13394 }
13395#endif
13396
13397 if (stp->close_src) {
13398 rb_io_close_m(stp->src);
13399 }
13400 if (stp->close_dst) {
13401 rb_io_close_m(stp->dst);
13402 }
13403 if (stp->syserr) {
13404 rb_syserr_fail(stp->error_no, stp->syserr);
13405 }
13406 if (stp->notimp) {
13407 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13408 }
13409 return Qnil;
13410}
13411
13412/*
13413 * call-seq:
13414 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13415 *
13416 * Copies from the given +src+ to the given +dst+,
13417 * returning the number of bytes copied.
13418 *
13419 * - The given +src+ must be one of the following:
13420 *
13421 * - The path to a readable file, from which source data is to be read.
13422 * - An \IO-like object, opened for reading and capable of responding
13423 * to method +:readpartial+ or method +:read+.
13424 *
13425 * - The given +dst+ must be one of the following:
13426 *
13427 * - The path to a writable file, to which data is to be written.
13428 * - An \IO-like object, opened for writing and capable of responding
13429 * to method +:write+.
13430 *
13431 * The examples here use file <tt>t.txt</tt> as source:
13432 *
13433 * File.read('t.txt')
13434 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13435 * File.read('t.txt').size # => 47
13436 *
13437 * If only arguments +src+ and +dst+ are given,
13438 * the entire source stream is copied:
13439 *
13440 * # Paths.
13441 * IO.copy_stream('t.txt', 't.tmp') # => 47
13442 *
13443 * # IOs (recall that a File is also an IO).
13444 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13445 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13446 * IO.copy_stream(src_io, dst_io) # => 47
13447 * src_io.close
13448 * dst_io.close
13449 *
13450 * With argument +src_length+ a non-negative integer,
13451 * no more than that many bytes are copied:
13452 *
13453 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13454 * File.read('t.tmp') # => "First line"
13455 *
13456 * With argument +src_offset+ also given,
13457 * the source stream is read beginning at that offset:
13458 *
13459 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13460 * IO.read('t.tmp') # => "Second line"
13461 *
13462 */
13463static VALUE
13464rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13465{
13466 VALUE src, dst, length, src_offset;
13467 struct copy_stream_struct st;
13468
13469 MEMZERO(&st, struct copy_stream_struct, 1);
13470
13471 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13472
13473 st.src = src;
13474 st.dst = dst;
13475
13476 st.src_fptr = NULL;
13477 st.dst_fptr = NULL;
13478
13479 if (NIL_P(length))
13480 st.copy_length = (rb_off_t)-1;
13481 else
13482 st.copy_length = NUM2OFFT(length);
13483
13484 if (NIL_P(src_offset))
13485 st.src_offset = (rb_off_t)-1;
13486 else
13487 st.src_offset = NUM2OFFT(src_offset);
13488
13489 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13490
13491 return OFFT2NUM(st.total);
13492}
13493
13494/*
13495 * call-seq:
13496 * external_encoding -> encoding or nil
13497 *
13498 * Returns the Encoding object that represents the encoding of the stream,
13499 * or +nil+ if the stream is in write mode and no encoding is specified.
13500 *
13501 * See {Encodings}[rdoc-ref:File@Encodings].
13502 *
13503 */
13504
13505static VALUE
13506rb_io_external_encoding(VALUE io)
13507{
13508 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13509
13510 if (fptr->encs.enc2) {
13511 return rb_enc_from_encoding(fptr->encs.enc2);
13512 }
13513 if (fptr->mode & FMODE_WRITABLE) {
13514 if (fptr->encs.enc)
13515 return rb_enc_from_encoding(fptr->encs.enc);
13516 return Qnil;
13517 }
13518 return rb_enc_from_encoding(io_read_encoding(fptr));
13519}
13520
13521/*
13522 * call-seq:
13523 * internal_encoding -> encoding or nil
13524 *
13525 * Returns the Encoding object that represents the encoding of the internal string,
13526 * if conversion is specified,
13527 * or +nil+ otherwise.
13528 *
13529 * See {Encodings}[rdoc-ref:File@Encodings].
13530 *
13531 */
13532
13533static VALUE
13534rb_io_internal_encoding(VALUE io)
13535{
13536 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13537
13538 if (!fptr->encs.enc2) return Qnil;
13539 return rb_enc_from_encoding(io_read_encoding(fptr));
13540}
13541
13542/*
13543 * call-seq:
13544 * set_encoding(ext_enc) -> self
13545 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13546 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13547 *
13548 * See {Encodings}[rdoc-ref:File@Encodings].
13549 *
13550 * Argument +ext_enc+, if given, must be an Encoding object
13551 * or a String with the encoding name;
13552 * it is assigned as the encoding for the stream.
13553 *
13554 * Argument +int_enc+, if given, must be an Encoding object
13555 * or a String with the encoding name;
13556 * it is assigned as the encoding for the internal string.
13557 *
13558 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13559 * containing two colon-separated encoding names;
13560 * corresponding Encoding objects are assigned as the external
13561 * and internal encodings for the stream.
13562 *
13563 * If the external encoding of a string is binary/ASCII-8BIT,
13564 * the internal encoding of the string is set to nil, since no
13565 * transcoding is needed.
13566 *
13567 * Optional keyword arguments +enc_opts+ specify
13568 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13569 *
13570 */
13571
13572static VALUE
13573rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13574{
13575 rb_io_t *fptr;
13576 VALUE v1, v2, opt;
13577
13578 if (!RB_TYPE_P(io, T_FILE)) {
13579 return forward(io, id_set_encoding, argc, argv);
13580 }
13581
13582 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13583 GetOpenFile(io, fptr);
13584 io_encoding_set(fptr, v1, v2, opt);
13585 return io;
13586}
13587
13588void
13589rb_stdio_set_default_encoding(void)
13590{
13591 VALUE val = Qnil;
13592
13593#ifdef _WIN32
13594 if (isatty(fileno(stdin))) {
13595 rb_encoding *external = rb_locale_encoding();
13596 rb_encoding *internal = rb_default_internal_encoding();
13597 if (!internal) internal = rb_default_external_encoding();
13598 io_encoding_set(RFILE(rb_stdin)->fptr,
13599 rb_enc_from_encoding(external),
13600 rb_enc_from_encoding(internal),
13601 Qnil);
13602 }
13603 else
13604#endif
13605 rb_io_set_encoding(1, &val, rb_stdin);
13606 rb_io_set_encoding(1, &val, rb_stdout);
13607 rb_io_set_encoding(1, &val, rb_stderr);
13608}
13609
13610static inline int
13611global_argf_p(VALUE arg)
13612{
13613 return arg == argf;
13614}
13615
13616typedef VALUE (*argf_encoding_func)(VALUE io);
13617
13618static VALUE
13619argf_encoding(VALUE argf, argf_encoding_func func)
13620{
13621 if (!RTEST(ARGF.current_file)) {
13622 return rb_enc_default_external();
13623 }
13624 return func(rb_io_check_io(ARGF.current_file));
13625}
13626
13627/*
13628 * call-seq:
13629 * ARGF.external_encoding -> encoding
13630 *
13631 * Returns the external encoding for files read from ARGF as an Encoding
13632 * object. The external encoding is the encoding of the text as stored in a
13633 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13634 * represent this text within Ruby.
13635 *
13636 * To set the external encoding use ARGF.set_encoding.
13637 *
13638 * For example:
13639 *
13640 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13641 *
13642 */
13643static VALUE
13644argf_external_encoding(VALUE argf)
13645{
13646 return argf_encoding(argf, rb_io_external_encoding);
13647}
13648
13649/*
13650 * call-seq:
13651 * ARGF.internal_encoding -> encoding
13652 *
13653 * Returns the internal encoding for strings read from ARGF as an
13654 * Encoding object.
13655 *
13656 * If ARGF.set_encoding has been called with two encoding names, the second
13657 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13658 * value is returned. Failing that, if a default external encoding was
13659 * specified on the command-line, that value is used. If the encoding is
13660 * unknown, +nil+ is returned.
13661 */
13662static VALUE
13663argf_internal_encoding(VALUE argf)
13664{
13665 return argf_encoding(argf, rb_io_internal_encoding);
13666}
13667
13668/*
13669 * call-seq:
13670 * ARGF.set_encoding(ext_enc) -> ARGF
13671 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13672 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13673 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13674 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13675 *
13676 * If single argument is specified, strings read from ARGF are tagged with
13677 * the encoding specified.
13678 *
13679 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13680 * the read string is converted from the first encoding (external encoding)
13681 * to the second encoding (internal encoding), then tagged with the second
13682 * encoding.
13683 *
13684 * If two arguments are specified, they must be encoding objects or encoding
13685 * names. Again, the first specifies the external encoding; the second
13686 * specifies the internal encoding.
13687 *
13688 * If the external encoding and the internal encoding are specified, the
13689 * optional Hash argument can be used to adjust the conversion process. The
13690 * structure of this hash is explained in the String#encode documentation.
13691 *
13692 * For example:
13693 *
13694 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13695 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13696 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13697 * # to UTF-8.
13698 */
13699static VALUE
13700argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13701{
13702 rb_io_t *fptr;
13703
13704 if (!next_argv()) {
13705 rb_raise(rb_eArgError, "no stream to set encoding");
13706 }
13707 rb_io_set_encoding(argc, argv, ARGF.current_file);
13708 GetOpenFile(ARGF.current_file, fptr);
13709 ARGF.encs = fptr->encs;
13710 return argf;
13711}
13712
13713/*
13714 * call-seq:
13715 * ARGF.tell -> Integer
13716 * ARGF.pos -> Integer
13717 *
13718 * Returns the current offset (in bytes) of the current file in ARGF.
13719 *
13720 * ARGF.pos #=> 0
13721 * ARGF.gets #=> "This is line one\n"
13722 * ARGF.pos #=> 17
13723 *
13724 */
13725static VALUE
13726argf_tell(VALUE argf)
13727{
13728 if (!next_argv()) {
13729 rb_raise(rb_eArgError, "no stream to tell");
13730 }
13731 ARGF_FORWARD(0, 0);
13732 return rb_io_tell(ARGF.current_file);
13733}
13734
13735/*
13736 * call-seq:
13737 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13738 *
13739 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13740 * the value of _whence_. See IO#seek for further details.
13741 */
13742static VALUE
13743argf_seek_m(int argc, VALUE *argv, VALUE argf)
13744{
13745 if (!next_argv()) {
13746 rb_raise(rb_eArgError, "no stream to seek");
13747 }
13748 ARGF_FORWARD(argc, argv);
13749 return rb_io_seek_m(argc, argv, ARGF.current_file);
13750}
13751
13752/*
13753 * call-seq:
13754 * ARGF.pos = position -> Integer
13755 *
13756 * Seeks to the position given by _position_ (in bytes) in ARGF.
13757 *
13758 * For example:
13759 *
13760 * ARGF.pos = 17
13761 * ARGF.gets #=> "This is line two\n"
13762 */
13763static VALUE
13764argf_set_pos(VALUE argf, VALUE offset)
13765{
13766 if (!next_argv()) {
13767 rb_raise(rb_eArgError, "no stream to set position");
13768 }
13769 ARGF_FORWARD(1, &offset);
13770 return rb_io_set_pos(ARGF.current_file, offset);
13771}
13772
13773/*
13774 * call-seq:
13775 * ARGF.rewind -> 0
13776 *
13777 * Positions the current file to the beginning of input, resetting
13778 * ARGF.lineno to zero.
13779 *
13780 * ARGF.readline #=> "This is line one\n"
13781 * ARGF.rewind #=> 0
13782 * ARGF.lineno #=> 0
13783 * ARGF.readline #=> "This is line one\n"
13784 */
13785static VALUE
13786argf_rewind(VALUE argf)
13787{
13788 VALUE ret;
13789 int old_lineno;
13790
13791 if (!next_argv()) {
13792 rb_raise(rb_eArgError, "no stream to rewind");
13793 }
13794 ARGF_FORWARD(0, 0);
13795 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13796 ret = rb_io_rewind(ARGF.current_file);
13797 if (!global_argf_p(argf)) {
13798 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13799 }
13800 return ret;
13801}
13802
13803/*
13804 * call-seq:
13805 * ARGF.fileno -> integer
13806 * ARGF.to_i -> integer
13807 *
13808 * Returns an integer representing the numeric file descriptor for
13809 * the current file. Raises an ArgumentError if there isn't a current file.
13810 *
13811 * ARGF.fileno #=> 3
13812 */
13813static VALUE
13814argf_fileno(VALUE argf)
13815{
13816 if (!next_argv()) {
13817 rb_raise(rb_eArgError, "no stream");
13818 }
13819 ARGF_FORWARD(0, 0);
13820 return rb_io_fileno(ARGF.current_file);
13821}
13822
13823/*
13824 * call-seq:
13825 * ARGF.to_io -> IO
13826 *
13827 * Returns an IO object representing the current file. This will be a
13828 * File object unless the current file is a stream such as STDIN.
13829 *
13830 * For example:
13831 *
13832 * ARGF.to_io #=> #<File:glark.txt>
13833 * ARGF.to_io #=> #<IO:<STDIN>>
13834 */
13835static VALUE
13836argf_to_io(VALUE argf)
13837{
13838 next_argv();
13839 ARGF_FORWARD(0, 0);
13840 return ARGF.current_file;
13841}
13842
13843/*
13844 * call-seq:
13845 * ARGF.eof? -> true or false
13846 * ARGF.eof -> true or false
13847 *
13848 * Returns true if the current file in ARGF is at end of file, i.e. it has
13849 * no data to read. The stream must be opened for reading or an IOError
13850 * will be raised.
13851 *
13852 * $ echo "eof" | ruby argf.rb
13853 *
13854 * ARGF.eof? #=> false
13855 * 3.times { ARGF.readchar }
13856 * ARGF.eof? #=> false
13857 * ARGF.readchar #=> "\n"
13858 * ARGF.eof? #=> true
13859 */
13860
13861static VALUE
13862argf_eof(VALUE argf)
13863{
13864 next_argv();
13865 if (RTEST(ARGF.current_file)) {
13866 if (ARGF.init_p == 0) return Qtrue;
13867 next_argv();
13868 ARGF_FORWARD(0, 0);
13869 if (rb_io_eof(ARGF.current_file)) {
13870 return Qtrue;
13871 }
13872 }
13873 return Qfalse;
13874}
13875
13876/*
13877 * call-seq:
13878 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13879 *
13880 * Reads _length_ bytes from ARGF. The files named on the command line
13881 * are concatenated and treated as a single file by this method, so when
13882 * called without arguments the contents of this pseudo file are returned in
13883 * their entirety.
13884 *
13885 * _length_ must be a non-negative integer or +nil+.
13886 *
13887 * If _length_ is a positive integer, +read+ tries to read
13888 * _length_ bytes without any conversion (binary mode).
13889 * It returns +nil+ if an EOF is encountered before anything can be read.
13890 * Fewer than _length_ bytes are returned if an EOF is encountered during
13891 * the read.
13892 * In the case of an integer _length_, the resulting string is always
13893 * in ASCII-8BIT encoding.
13894 *
13895 * If _length_ is omitted or is +nil+, it reads until EOF
13896 * and the encoding conversion is applied, if applicable.
13897 * A string is returned even if EOF is encountered before any data is read.
13898 *
13899 * If _length_ is zero, it returns an empty string (<code>""</code>).
13900 *
13901 * If the optional _outbuf_ argument is present,
13902 * it must reference a String, which will receive the data.
13903 * The _outbuf_ will contain only the received data after the method call
13904 * even if it is not empty at the beginning.
13905 *
13906 * For example:
13907 *
13908 * $ echo "small" > small.txt
13909 * $ echo "large" > large.txt
13910 * $ ./glark.rb small.txt large.txt
13911 *
13912 * ARGF.read #=> "small\nlarge"
13913 * ARGF.read(200) #=> "small\nlarge"
13914 * ARGF.read(2) #=> "sm"
13915 * ARGF.read(0) #=> ""
13916 *
13917 * Note that this method behaves like the fread() function in C.
13918 * This means it retries to invoke read(2) system calls to read data
13919 * with the specified length.
13920 * If you need the behavior like a single read(2) system call,
13921 * consider ARGF#readpartial or ARGF#read_nonblock.
13922 */
13923
13924static VALUE
13925argf_read(int argc, VALUE *argv, VALUE argf)
13926{
13927 VALUE tmp, str, length;
13928 long len = 0;
13929
13930 rb_scan_args(argc, argv, "02", &length, &str);
13931 if (!NIL_P(length)) {
13932 len = NUM2LONG(argv[0]);
13933 }
13934 if (!NIL_P(str)) {
13935 StringValue(str);
13936 rb_str_resize(str,0);
13937 argv[1] = Qnil;
13938 }
13939
13940 retry:
13941 if (!next_argv()) {
13942 return str;
13943 }
13944 if (ARGF_GENERIC_INPUT_P()) {
13945 tmp = argf_forward(argc, argv, argf);
13946 }
13947 else {
13948 tmp = io_read(argc, argv, ARGF.current_file);
13949 }
13950 if (NIL_P(str)) str = tmp;
13951 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13952 if (NIL_P(tmp) || NIL_P(length)) {
13953 if (ARGF.next_p != -1) {
13954 argf_close(argf);
13955 ARGF.next_p = 1;
13956 goto retry;
13957 }
13958 }
13959 else if (argc >= 1) {
13960 long slen = RSTRING_LEN(str);
13961 if (slen < len) {
13962 argv[0] = LONG2NUM(len - slen);
13963 goto retry;
13964 }
13965 }
13966 return str;
13967}
13968
13970 int argc;
13971 VALUE *argv;
13972 VALUE argf;
13973};
13974
13975static VALUE
13976argf_forward_call(VALUE arg)
13977{
13978 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13979 argf_forward(p->argc, p->argv, p->argf);
13980 return Qnil;
13981}
13982
13983static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13984 int nonblock);
13985
13986/*
13987 * call-seq:
13988 * ARGF.readpartial(maxlen) -> string
13989 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13990 *
13991 * Reads at most _maxlen_ bytes from the ARGF stream.
13992 *
13993 * If the optional _outbuf_ argument is present,
13994 * it must reference a String, which will receive the data.
13995 * The _outbuf_ will contain only the received data after the method call
13996 * even if it is not empty at the beginning.
13997 *
13998 * It raises EOFError on end of ARGF stream.
13999 * Since ARGF stream is a concatenation of multiple files,
14000 * internally EOF is occur for each file.
14001 * ARGF.readpartial returns empty strings for EOFs except the last one and
14002 * raises EOFError for the last one.
14003 *
14004 */
14005
14006static VALUE
14007argf_readpartial(int argc, VALUE *argv, VALUE argf)
14008{
14009 return argf_getpartial(argc, argv, argf, Qnil, 0);
14010}
14011
14012/*
14013 * call-seq:
14014 * ARGF.read_nonblock(maxlen[, options]) -> string
14015 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14016 *
14017 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14018 */
14019
14020static VALUE
14021argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14022{
14023 VALUE opts;
14024
14025 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14026
14027 if (!NIL_P(opts))
14028 argc--;
14029
14030 return argf_getpartial(argc, argv, argf, opts, 1);
14031}
14032
14033static VALUE
14034argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14035{
14036 VALUE tmp, str, length;
14037 int no_exception;
14038
14039 rb_scan_args(argc, argv, "11", &length, &str);
14040 if (!NIL_P(str)) {
14041 StringValue(str);
14042 argv[1] = str;
14043 }
14044 no_exception = no_exception_p(opts);
14045
14046 if (!next_argv()) {
14047 if (!NIL_P(str)) {
14048 rb_str_resize(str, 0);
14049 }
14050 rb_eof_error();
14051 }
14052 if (ARGF_GENERIC_INPUT_P()) {
14053 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14054 struct argf_call_arg arg;
14055 arg.argc = argc;
14056 arg.argv = argv;
14057 arg.argf = argf;
14058 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14059 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14060 }
14061 else {
14062 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14063 }
14064 if (NIL_P(tmp)) {
14065 if (ARGF.next_p == -1) {
14066 return io_nonblock_eof(no_exception);
14067 }
14068 argf_close(argf);
14069 ARGF.next_p = 1;
14070 if (RARRAY_LEN(ARGF.argv) == 0) {
14071 return io_nonblock_eof(no_exception);
14072 }
14073 if (NIL_P(str))
14074 str = rb_str_new(NULL, 0);
14075 return str;
14076 }
14077 return tmp;
14078}
14079
14080/*
14081 * call-seq:
14082 * ARGF.getc -> String or nil
14083 *
14084 * Reads the next character from ARGF and returns it as a String. Returns
14085 * +nil+ at the end of the stream.
14086 *
14087 * ARGF treats the files named on the command line as a single file created
14088 * by concatenating their contents. After returning the last character of the
14089 * first file, it returns the first character of the second file, and so on.
14090 *
14091 * For example:
14092 *
14093 * $ echo "foo" > file
14094 * $ ruby argf.rb file
14095 *
14096 * ARGF.getc #=> "f"
14097 * ARGF.getc #=> "o"
14098 * ARGF.getc #=> "o"
14099 * ARGF.getc #=> "\n"
14100 * ARGF.getc #=> nil
14101 * ARGF.getc #=> nil
14102 */
14103static VALUE
14104argf_getc(VALUE argf)
14105{
14106 VALUE ch;
14107
14108 retry:
14109 if (!next_argv()) return Qnil;
14110 if (ARGF_GENERIC_INPUT_P()) {
14111 ch = forward_current(rb_intern("getc"), 0, 0);
14112 }
14113 else {
14114 ch = rb_io_getc(ARGF.current_file);
14115 }
14116 if (NIL_P(ch) && ARGF.next_p != -1) {
14117 argf_close(argf);
14118 ARGF.next_p = 1;
14119 goto retry;
14120 }
14121
14122 return ch;
14123}
14124
14125/*
14126 * call-seq:
14127 * ARGF.getbyte -> Integer or nil
14128 *
14129 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14130 * the end of the stream.
14131 *
14132 * For example:
14133 *
14134 * $ echo "foo" > file
14135 * $ ruby argf.rb file
14136 *
14137 * ARGF.getbyte #=> 102
14138 * ARGF.getbyte #=> 111
14139 * ARGF.getbyte #=> 111
14140 * ARGF.getbyte #=> 10
14141 * ARGF.getbyte #=> nil
14142 */
14143static VALUE
14144argf_getbyte(VALUE argf)
14145{
14146 VALUE ch;
14147
14148 retry:
14149 if (!next_argv()) return Qnil;
14150 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14151 ch = forward_current(rb_intern("getbyte"), 0, 0);
14152 }
14153 else {
14154 ch = rb_io_getbyte(ARGF.current_file);
14155 }
14156 if (NIL_P(ch) && ARGF.next_p != -1) {
14157 argf_close(argf);
14158 ARGF.next_p = 1;
14159 goto retry;
14160 }
14161
14162 return ch;
14163}
14164
14165/*
14166 * call-seq:
14167 * ARGF.readchar -> String or nil
14168 *
14169 * Reads the next character from ARGF and returns it as a String. Raises
14170 * an EOFError after the last character of the last file has been read.
14171 *
14172 * For example:
14173 *
14174 * $ echo "foo" > file
14175 * $ ruby argf.rb file
14176 *
14177 * ARGF.readchar #=> "f"
14178 * ARGF.readchar #=> "o"
14179 * ARGF.readchar #=> "o"
14180 * ARGF.readchar #=> "\n"
14181 * ARGF.readchar #=> end of file reached (EOFError)
14182 */
14183static VALUE
14184argf_readchar(VALUE argf)
14185{
14186 VALUE ch;
14187
14188 retry:
14189 if (!next_argv()) rb_eof_error();
14190 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14191 ch = forward_current(rb_intern("getc"), 0, 0);
14192 }
14193 else {
14194 ch = rb_io_getc(ARGF.current_file);
14195 }
14196 if (NIL_P(ch) && ARGF.next_p != -1) {
14197 argf_close(argf);
14198 ARGF.next_p = 1;
14199 goto retry;
14200 }
14201
14202 return ch;
14203}
14204
14205/*
14206 * call-seq:
14207 * ARGF.readbyte -> Integer
14208 *
14209 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14210 * an EOFError after the last byte of the last file has been read.
14211 *
14212 * For example:
14213 *
14214 * $ echo "foo" > file
14215 * $ ruby argf.rb file
14216 *
14217 * ARGF.readbyte #=> 102
14218 * ARGF.readbyte #=> 111
14219 * ARGF.readbyte #=> 111
14220 * ARGF.readbyte #=> 10
14221 * ARGF.readbyte #=> end of file reached (EOFError)
14222 */
14223static VALUE
14224argf_readbyte(VALUE argf)
14225{
14226 VALUE c;
14227
14228 NEXT_ARGF_FORWARD(0, 0);
14229 c = argf_getbyte(argf);
14230 if (NIL_P(c)) {
14231 rb_eof_error();
14232 }
14233 return c;
14234}
14235
14236#define FOREACH_ARGF() while (next_argv())
14237
14238static VALUE
14239argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14240{
14241 const VALUE current = ARGF.current_file;
14242 rb_yield_values2(argc, argv);
14243 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14245 }
14246 return Qnil;
14247}
14248
14249#define ARGF_block_call(mid, argc, argv, func, argf) \
14250 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14251 func, argf, rb_keyword_given_p())
14252
14253static void
14254argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14255{
14256 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14257 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14258}
14259
14260static VALUE
14261argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14262{
14263 if (!global_argf_p(argf)) {
14264 ARGF.last_lineno = ++ARGF.lineno;
14265 }
14266 return argf_block_call_i(i, argf, argc, argv, blockarg);
14267}
14268
14269static void
14270argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14271{
14272 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14273 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14274}
14275
14276/*
14277 * call-seq:
14278 * ARGF.each(sep=$/) {|line| block } -> ARGF
14279 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14280 * ARGF.each(...) -> an_enumerator
14281 *
14282 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14283 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14284 * ARGF.each_line(...) -> an_enumerator
14285 *
14286 * Returns an enumerator which iterates over each line (separated by _sep_,
14287 * which defaults to your platform's newline character) of each file in
14288 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14289 * block, otherwise an enumerator is returned.
14290 * The optional _limit_ argument is an Integer specifying the maximum
14291 * length of each line; longer lines will be split according to this limit.
14292 *
14293 * This method allows you to treat the files supplied on the command line as
14294 * a single file consisting of the concatenation of each named file. After
14295 * the last line of the first file has been returned, the first line of the
14296 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14297 * used to determine the filename of the current line and line number of the
14298 * whole input, respectively.
14299 *
14300 * For example, the following code prints out each line of each named file
14301 * prefixed with its line number, displaying the filename once per file:
14302 *
14303 * ARGF.each_line do |line|
14304 * puts ARGF.filename if ARGF.file.lineno == 1
14305 * puts "#{ARGF.file.lineno}: #{line}"
14306 * end
14307 *
14308 * While the following code prints only the first file's name at first, and
14309 * the contents with line number counted through all named files.
14310 *
14311 * ARGF.each_line do |line|
14312 * puts ARGF.filename if ARGF.lineno == 1
14313 * puts "#{ARGF.lineno}: #{line}"
14314 * end
14315 */
14316static VALUE
14317argf_each_line(int argc, VALUE *argv, VALUE argf)
14318{
14319 RETURN_ENUMERATOR(argf, argc, argv);
14320 FOREACH_ARGF() {
14321 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14322 }
14323 return argf;
14324}
14325
14326/*
14327 * call-seq:
14328 * ARGF.each_byte {|byte| block } -> ARGF
14329 * ARGF.each_byte -> an_enumerator
14330 *
14331 * Iterates over each byte of each file in +ARGV+.
14332 * A byte is returned as an Integer in the range 0..255.
14333 *
14334 * This method allows you to treat the files supplied on the command line as
14335 * a single file consisting of the concatenation of each named file. After
14336 * the last byte of the first file has been returned, the first byte of the
14337 * second file is returned. The ARGF.filename method can be used to
14338 * determine the filename of the current byte.
14339 *
14340 * If no block is given, an enumerator is returned instead.
14341 *
14342 * For example:
14343 *
14344 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14345 *
14346 */
14347static VALUE
14348argf_each_byte(VALUE argf)
14349{
14350 RETURN_ENUMERATOR(argf, 0, 0);
14351 FOREACH_ARGF() {
14352 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14353 }
14354 return argf;
14355}
14356
14357/*
14358 * call-seq:
14359 * ARGF.each_char {|char| block } -> ARGF
14360 * ARGF.each_char -> an_enumerator
14361 *
14362 * Iterates over each character of each file in ARGF.
14363 *
14364 * This method allows you to treat the files supplied on the command line as
14365 * a single file consisting of the concatenation of each named file. After
14366 * the last character of the first file has been returned, the first
14367 * character of the second file is returned. The ARGF.filename method can
14368 * be used to determine the name of the file in which the current character
14369 * appears.
14370 *
14371 * If no block is given, an enumerator is returned instead.
14372 */
14373static VALUE
14374argf_each_char(VALUE argf)
14375{
14376 RETURN_ENUMERATOR(argf, 0, 0);
14377 FOREACH_ARGF() {
14378 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14379 }
14380 return argf;
14381}
14382
14383/*
14384 * call-seq:
14385 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14386 * ARGF.each_codepoint -> an_enumerator
14387 *
14388 * Iterates over each codepoint of each file in ARGF.
14389 *
14390 * This method allows you to treat the files supplied on the command line as
14391 * a single file consisting of the concatenation of each named file. After
14392 * the last codepoint of the first file has been returned, the first
14393 * codepoint of the second file is returned. The ARGF.filename method can
14394 * be used to determine the name of the file in which the current codepoint
14395 * appears.
14396 *
14397 * If no block is given, an enumerator is returned instead.
14398 */
14399static VALUE
14400argf_each_codepoint(VALUE argf)
14401{
14402 RETURN_ENUMERATOR(argf, 0, 0);
14403 FOREACH_ARGF() {
14404 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14405 }
14406 return argf;
14407}
14408
14409/*
14410 * call-seq:
14411 * ARGF.filename -> String
14412 * ARGF.path -> String
14413 *
14414 * Returns the current filename. "-" is returned when the current file is
14415 * STDIN.
14416 *
14417 * For example:
14418 *
14419 * $ echo "foo" > foo
14420 * $ echo "bar" > bar
14421 * $ echo "glark" > glark
14422 *
14423 * $ ruby argf.rb foo bar glark
14424 *
14425 * ARGF.filename #=> "foo"
14426 * ARGF.read(5) #=> "foo\nb"
14427 * ARGF.filename #=> "bar"
14428 * ARGF.skip
14429 * ARGF.filename #=> "glark"
14430 */
14431static VALUE
14432argf_filename(VALUE argf)
14433{
14434 next_argv();
14435 return ARGF.filename;
14436}
14437
14438static VALUE
14439argf_filename_getter(ID id, VALUE *var)
14440{
14441 return argf_filename(*var);
14442}
14443
14444/*
14445 * call-seq:
14446 * ARGF.file -> IO or File object
14447 *
14448 * Returns the current file as an IO or File object.
14449 * <code>$stdin</code> is returned when the current file is STDIN.
14450 *
14451 * For example:
14452 *
14453 * $ echo "foo" > foo
14454 * $ echo "bar" > bar
14455 *
14456 * $ ruby argf.rb foo bar
14457 *
14458 * ARGF.file #=> #<File:foo>
14459 * ARGF.read(5) #=> "foo\nb"
14460 * ARGF.file #=> #<File:bar>
14461 */
14462static VALUE
14463argf_file(VALUE argf)
14464{
14465 next_argv();
14466 return ARGF.current_file;
14467}
14468
14469/*
14470 * call-seq:
14471 * ARGF.binmode -> ARGF
14472 *
14473 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14474 * be reset to non-binary mode. This option has the following effects:
14475 *
14476 * * Newline conversion is disabled.
14477 * * Encoding conversion is disabled.
14478 * * Content is treated as ASCII-8BIT.
14479 */
14480static VALUE
14481argf_binmode_m(VALUE argf)
14482{
14483 ARGF.binmode = 1;
14484 next_argv();
14485 ARGF_FORWARD(0, 0);
14486 rb_io_ascii8bit_binmode(ARGF.current_file);
14487 return argf;
14488}
14489
14490/*
14491 * call-seq:
14492 * ARGF.binmode? -> true or false
14493 *
14494 * Returns true if ARGF is being read in binary mode; false otherwise.
14495 * To enable binary mode use ARGF.binmode.
14496 *
14497 * For example:
14498 *
14499 * ARGF.binmode? #=> false
14500 * ARGF.binmode
14501 * ARGF.binmode? #=> true
14502 */
14503static VALUE
14504argf_binmode_p(VALUE argf)
14505{
14506 return RBOOL(ARGF.binmode);
14507}
14508
14509/*
14510 * call-seq:
14511 * ARGF.skip -> ARGF
14512 *
14513 * Sets the current file to the next file in ARGV. If there aren't any more
14514 * files it has no effect.
14515 *
14516 * For example:
14517 *
14518 * $ ruby argf.rb foo bar
14519 * ARGF.filename #=> "foo"
14520 * ARGF.skip
14521 * ARGF.filename #=> "bar"
14522 */
14523static VALUE
14524argf_skip(VALUE argf)
14525{
14526 if (ARGF.init_p && ARGF.next_p == 0) {
14527 argf_close(argf);
14528 ARGF.next_p = 1;
14529 }
14530 return argf;
14531}
14532
14533/*
14534 * call-seq:
14535 * ARGF.close -> ARGF
14536 *
14537 * Closes the current file and skips to the next file in ARGV. If there are
14538 * no more files to open, just closes the current file. STDIN will not be
14539 * closed.
14540 *
14541 * For example:
14542 *
14543 * $ ruby argf.rb foo bar
14544 *
14545 * ARGF.filename #=> "foo"
14546 * ARGF.close
14547 * ARGF.filename #=> "bar"
14548 * ARGF.close
14549 */
14550static VALUE
14551argf_close_m(VALUE argf)
14552{
14553 next_argv();
14554 argf_close(argf);
14555 if (ARGF.next_p != -1) {
14556 ARGF.next_p = 1;
14557 }
14558 ARGF.lineno = 0;
14559 return argf;
14560}
14561
14562/*
14563 * call-seq:
14564 * ARGF.closed? -> true or false
14565 *
14566 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14567 * ARGF.close to actually close the current file.
14568 */
14569static VALUE
14570argf_closed(VALUE argf)
14571{
14572 next_argv();
14573 ARGF_FORWARD(0, 0);
14574 return rb_io_closed_p(ARGF.current_file);
14575}
14576
14577/*
14578 * call-seq:
14579 * ARGF.to_s -> String
14580 *
14581 * Returns "ARGF".
14582 */
14583static VALUE
14584argf_to_s(VALUE argf)
14585{
14586 return rb_str_new2("ARGF");
14587}
14588
14589/*
14590 * call-seq:
14591 * ARGF.inplace_mode -> String
14592 *
14593 * Returns the file extension appended to the names of backup copies of
14594 * modified files under in-place edit mode. This value can be set using
14595 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14596 */
14597static VALUE
14598argf_inplace_mode_get(VALUE argf)
14599{
14600 if (!ARGF.inplace) return Qnil;
14601 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14602 return rb_str_dup(ARGF.inplace);
14603}
14604
14605static VALUE
14606opt_i_get(ID id, VALUE *var)
14607{
14608 return argf_inplace_mode_get(*var);
14609}
14610
14611/*
14612 * call-seq:
14613 * ARGF.inplace_mode = ext -> ARGF
14614 *
14615 * Sets the filename extension for in-place editing mode to the given String.
14616 * The backup copy of each file being edited has this value appended to its
14617 * filename.
14618 *
14619 * For example:
14620 *
14621 * $ ruby argf.rb file.txt
14622 *
14623 * ARGF.inplace_mode = '.bak'
14624 * ARGF.each_line do |line|
14625 * print line.sub("foo","bar")
14626 * end
14627 *
14628 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14629 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14630 * "bar".
14631 */
14632static VALUE
14633argf_inplace_mode_set(VALUE argf, VALUE val)
14634{
14635 if (!RTEST(val)) {
14636 ARGF.inplace = Qfalse;
14637 }
14638 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14639 ARGF.inplace = Qnil;
14640 }
14641 else {
14642 ARGF.inplace = rb_str_new_frozen(val);
14643 }
14644 return argf;
14645}
14646
14647static void
14648opt_i_set(VALUE val, ID id, VALUE *var)
14649{
14650 argf_inplace_mode_set(*var, val);
14651}
14652
14653void
14654ruby_set_inplace_mode(const char *suffix)
14655{
14656 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14657}
14658
14659/*
14660 * call-seq:
14661 * ARGF.argv -> ARGV
14662 *
14663 * Returns the +ARGV+ array, which contains the arguments passed to your
14664 * script, one per element.
14665 *
14666 * For example:
14667 *
14668 * $ ruby argf.rb -v glark.txt
14669 *
14670 * ARGF.argv #=> ["-v", "glark.txt"]
14671 *
14672 */
14673static VALUE
14674argf_argv(VALUE argf)
14675{
14676 return ARGF.argv;
14677}
14678
14679static VALUE
14680argf_argv_getter(ID id, VALUE *var)
14681{
14682 return argf_argv(*var);
14683}
14684
14685VALUE
14687{
14688 return ARGF.argv;
14689}
14690
14691/*
14692 * call-seq:
14693 * ARGF.to_write_io -> io
14694 *
14695 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14696 * enabled.
14697 */
14698static VALUE
14699argf_write_io(VALUE argf)
14700{
14701 if (!RTEST(ARGF.current_file)) {
14702 rb_raise(rb_eIOError, "not opened for writing");
14703 }
14704 return GetWriteIO(ARGF.current_file);
14705}
14706
14707/*
14708 * call-seq:
14709 * ARGF.write(*objects) -> integer
14710 *
14711 * Writes each of the given +objects+ if inplace mode.
14712 */
14713static VALUE
14714argf_write(int argc, VALUE *argv, VALUE argf)
14715{
14716 return rb_io_writev(argf_write_io(argf), argc, argv);
14717}
14718
14719void
14720rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14721{
14722 rb_readwrite_syserr_fail(waiting, errno, mesg);
14723}
14724
14725void
14726rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14727{
14728 VALUE arg, c = Qnil;
14729 arg = mesg ? rb_str_new2(mesg) : Qnil;
14730 switch (waiting) {
14731 case RB_IO_WAIT_WRITABLE:
14732 switch (n) {
14733 case EAGAIN:
14734 c = rb_eEAGAINWaitWritable;
14735 break;
14736#if EAGAIN != EWOULDBLOCK
14737 case EWOULDBLOCK:
14738 c = rb_eEWOULDBLOCKWaitWritable;
14739 break;
14740#endif
14741 case EINPROGRESS:
14742 c = rb_eEINPROGRESSWaitWritable;
14743 break;
14744 default:
14746 }
14747 break;
14748 case RB_IO_WAIT_READABLE:
14749 switch (n) {
14750 case EAGAIN:
14751 c = rb_eEAGAINWaitReadable;
14752 break;
14753#if EAGAIN != EWOULDBLOCK
14754 case EWOULDBLOCK:
14755 c = rb_eEWOULDBLOCKWaitReadable;
14756 break;
14757#endif
14758 case EINPROGRESS:
14759 c = rb_eEINPROGRESSWaitReadable;
14760 break;
14761 default:
14763 }
14764 break;
14765 default:
14766 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14767 }
14769}
14770
14771static VALUE
14772get_LAST_READ_LINE(ID _x, VALUE *_y)
14773{
14774 return rb_lastline_get();
14775}
14776
14777static void
14778set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14779{
14780 rb_lastline_set(val);
14781}
14782
14783/*
14784 * Document-class: IOError
14785 *
14786 * Raised when an IO operation fails.
14787 *
14788 * File.open("/etc/hosts") {|f| f << "example"}
14789 * #=> IOError: not opened for writing
14790 *
14791 * File.open("/etc/hosts") {|f| f.close; f.read }
14792 * #=> IOError: closed stream
14793 *
14794 * Note that some IO failures raise <code>SystemCallError</code>s
14795 * and these are not subclasses of IOError:
14796 *
14797 * File.open("does/not/exist")
14798 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14799 */
14800
14801/*
14802 * Document-class: EOFError
14803 *
14804 * Raised by some IO operations when reaching the end of file. Many IO
14805 * methods exist in two forms,
14806 *
14807 * one that returns +nil+ when the end of file is reached, the other
14808 * raises EOFError.
14809 *
14810 * EOFError is a subclass of IOError.
14811 *
14812 * file = File.open("/etc/hosts")
14813 * file.read
14814 * file.gets #=> nil
14815 * file.readline #=> EOFError: end of file reached
14816 * file.close
14817 */
14818
14819/*
14820 * Document-class: ARGF
14821 *
14822 * == \ARGF and +ARGV+
14823 *
14824 * The \ARGF object works with the array at global variable +ARGV+
14825 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14826 *
14827 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14828 *
14829 * Initially, it contains the command-line arguments and options
14830 * that are passed to the Ruby program;
14831 * the program can modify that array as it likes.
14832 *
14833 * - **ARGF** may be thought of as the <b>argument files</b> object.
14834 *
14835 * It can access file streams and/or the <tt>$stdin</tt> stream,
14836 * based on what it finds in +ARGV+.
14837 * This provides a convenient way for the command line
14838 * to specify streams for a Ruby program to read.
14839 *
14840 * == Reading
14841 *
14842 * \ARGF may read from _source_ streams,
14843 * which at any particular time are determined by the content of +ARGV+.
14844 *
14845 * === Simplest Case
14846 *
14847 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14848 * the source is <tt>$stdin</tt>:
14849 *
14850 * - \File +t.rb+:
14851 *
14852 * p ['ARGV', ARGV]
14853 * p ['ARGF.read', ARGF.read]
14854 *
14855 * - Commands and outputs
14856 * (see below for the content of files +foo.txt+ and +bar.txt+):
14857 *
14858 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14859 * ["ARGV", []]
14860 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14861 *
14862 * $ cat foo.txt bar.txt | ruby t.rb
14863 * ["ARGV", []]
14864 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14865 *
14866 * === About the Examples
14867 *
14868 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14869 *
14870 * $ cat foo.txt
14871 * Foo 0
14872 * Foo 1
14873 * $ cat bar.txt
14874 * Bar 0
14875 * Bar 1
14876 * Bar 2
14877 * Bar 3
14878 *
14879 * === Sources in +ARGV+
14880 *
14881 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14882 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14883 * the sources are found in +ARGV+.
14884 *
14885 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14886 * and is one of:
14887 *
14888 * - The string path to a file that may be opened as a stream.
14889 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14890 *
14891 * Each element that is _not_ one of these
14892 * should be removed from +ARGV+ before \ARGF accesses that source.
14893 *
14894 * In the following example:
14895 *
14896 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14897 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14898 *
14899 * Example:
14900 *
14901 * - \File +t.rb+:
14902 *
14903 * # Print arguments (and options, if any) found on command line.
14904 * p ['ARGV', ARGV]
14905 *
14906 * - Command and output:
14907 *
14908 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14909 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14910 *
14911 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14912 *
14913 * - \File +t.rb+:
14914 *
14915 * p "ARGV: #{ARGV}"
14916 * p "Line: #{ARGF.read}" # Read everything from all specified streams.
14917 *
14918 * - Command and output:
14919 *
14920 * $ ruby t.rb foo.txt bar.txt
14921 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14922 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14923 *
14924 * Because the value at +ARGV+ is an ordinary array,
14925 * you can manipulate it to control which sources \ARGF considers:
14926 *
14927 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14928 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14929 *
14930 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14931 * when all sources have been accessed, the array is empty:
14932 *
14933 * - \File +t.rb+:
14934 *
14935 * until ARGV.empty? && ARGF.eof?
14936 * p "ARGV: #{ARGV}"
14937 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14938 * end
14939 *
14940 * - Command and output:
14941 *
14942 * $ ruby t.rb foo.txt bar.txt
14943 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14944 * "Line: Foo 0\n"
14945 * "ARGV: [\"bar.txt\"]"
14946 * "Line: Foo 1\n"
14947 * "ARGV: [\"bar.txt\"]"
14948 * "Line: Bar 0\n"
14949 * "ARGV: []"
14950 * "Line: Bar 1\n"
14951 * "ARGV: []"
14952 * "Line: Bar 2\n"
14953 * "ARGV: []"
14954 * "Line: Bar 3\n"
14955 *
14956 * ==== Filepaths in +ARGV+
14957 *
14958 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14959 *
14960 * This program prints what it reads from files at the paths specified
14961 * on the command line:
14962 *
14963 * - \File +t.rb+:
14964 *
14965 * p ['ARGV', ARGV]
14966 * # Read and print all content from the specified sources.
14967 * p ['ARGF.read', ARGF.read]
14968 *
14969 * - Command and output:
14970 *
14971 * $ ruby t.rb foo.txt bar.txt
14972 * ["ARGV", [foo.txt, bar.txt]
14973 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14974 *
14975 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14976 *
14977 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14978 *
14979 * - \File +t.rb+:
14980 *
14981 * p ['ARGV', ARGV]
14982 * p ['ARGF.read', ARGF.read]
14983 *
14984 * - Command and output:
14985 *
14986 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14987 * ["ARGV", ["-"]]
14988 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14989 *
14990 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
14991 * (exception:
14992 * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
14993 *
14994 * - Command and output:
14995 *
14996 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
14997 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14998 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14999 *
15000 * ==== Mixtures and Repetitions in +ARGV+
15001 *
15002 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
15003 * and character <tt>'-'</tt>, including repetitions.
15004 *
15005 * ==== Modifications to +ARGV+
15006 *
15007 * The running Ruby program may make any modifications to the +ARGV+ array;
15008 * the current value of +ARGV+ affects \ARGF reading.
15009 *
15010 * ==== Empty +ARGV+
15011 *
15012 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15013 * or raises an exception, depending on the specific method.
15014 *
15015 * === More Read Methods
15016 *
15017 * As seen above, method ARGF#read reads the content of all sources
15018 * into a single string.
15019 * Other \ARGF methods provide other ways to access that content;
15020 * these include:
15021 *
15022 * - Byte access: #each_byte, #getbyte, #readbyte.
15023 * - Character access: #each_char, #getc, #readchar.
15024 * - Codepoint access: #each_codepoint.
15025 * - Line access: #each_line, #gets, #readline, #readlines.
15026 * - Source access: #read, #read_nonblock, #readpartial.
15027 *
15028 * === About \Enumerable
15029 *
15030 * \ARGF includes module Enumerable.
15031 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15032 *
15033 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15034 * _not_ from +ARGV+;
15035 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15036 * not an array of the strings from +ARGV+:
15037 *
15038 * - \File +t.rb+:
15039 *
15040 * p ['ARGV', ARGV]
15041 * p ['ARGF.entries', ARGF.entries]
15042 *
15043 * - Command and output:
15044 *
15045 * $ ruby t.rb foo.txt bar.txt
15046 * ["ARGV", ["foo.txt", "bar.txt"]]
15047 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15048 *
15049 * == Writing
15050 *
15051 * If <i>inplace mode</i> is in effect,
15052 * \ARGF may write to target streams,
15053 * which at any particular time are determined by the content of ARGV.
15054 *
15055 * Methods about inplace mode:
15056 *
15057 * - #inplace_mode
15058 * - #inplace_mode=
15059 * - #to_write_io
15060 *
15061 * Methods for writing:
15062 *
15063 * - #print
15064 * - #printf
15065 * - #putc
15066 * - #puts
15067 * - #write
15068 *
15069 */
15070
15071/*
15072 * An instance of class \IO (commonly called a _stream_)
15073 * represents an input/output stream in the underlying operating system.
15074 * Class \IO is the basis for input and output in Ruby.
15075 *
15076 * Class File is the only class in the Ruby core that is a subclass of \IO.
15077 * Some classes in the Ruby standard library are also subclasses of \IO;
15078 * these include TCPSocket and UDPSocket.
15079 *
15080 * The global constant ARGF (also accessible as <tt>$<</tt>)
15081 * provides an IO-like stream that allows access to all file paths
15082 * found in ARGV (or found in STDIN if ARGV is empty).
15083 * ARGF is not itself a subclass of \IO.
15084 *
15085 * Class StringIO provides an IO-like stream that handles a String.
15086 * StringIO is not itself a subclass of \IO.
15087 *
15088 * Important objects based on \IO include:
15089 *
15090 * - $stdin.
15091 * - $stdout.
15092 * - $stderr.
15093 * - Instances of class File.
15094 *
15095 * An instance of \IO may be created using:
15096 *
15097 * - IO.new: returns a new \IO object for the given integer file descriptor.
15098 * - IO.open: passes a new \IO object to the given block.
15099 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15100 * of a newly-launched subprocess.
15101 * - Kernel#open: Returns a new \IO object connected to a given source:
15102 * stream, file, or subprocess.
15103 *
15104 * Like a File stream, an \IO stream has:
15105 *
15106 * - A read/write mode, which may be read-only, write-only, or read/write;
15107 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
15108 * - A data mode, which may be text-only or binary;
15109 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15110 * - Internal and external encodings;
15111 * see {Encodings}[rdoc-ref:File@Encodings].
15112 *
15113 * And like other \IO streams, it has:
15114 *
15115 * - A position, which determines where in the stream the next
15116 * read or write is to occur;
15117 * see {Position}[rdoc-ref:IO@Position].
15118 * - A line number, which is a special, line-oriented, "position"
15119 * (different from the position mentioned above);
15120 * see {Line Number}[rdoc-ref:IO@Line+Number].
15121 *
15122 * == Extension <tt>io/console</tt>
15123 *
15124 * Extension <tt>io/console</tt> provides numerous methods
15125 * for interacting with the console;
15126 * requiring it adds numerous methods to class \IO.
15127 *
15128 * == Example Files
15129 *
15130 * Many examples here use these variables:
15131 *
15132 * :include: doc/examples/files.rdoc
15133 *
15134 * == Open Options
15135 *
15136 * A number of \IO methods accept optional keyword arguments
15137 * that determine how a new stream is to be opened:
15138 *
15139 * - +:mode+: Stream mode.
15140 * - +:flags+: Integer file open flags;
15141 * If +mode+ is also given, the two are bitwise-ORed.
15142 * - +:external_encoding+: External encoding for the stream.
15143 * - +:internal_encoding+: Internal encoding for the stream.
15144 * <tt>'-'</tt> is a synonym for the default internal encoding.
15145 * If the value is +nil+ no conversion occurs.
15146 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15147 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15148 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15149 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15150 * when the stream closes; otherwise it remains open.
15151 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15152 * #path method.
15153 *
15154 * Also available are the options offered in String#encode,
15155 * which may control conversion between external and internal encoding.
15156 *
15157 * == Basic \IO
15158 *
15159 * You can perform basic stream \IO with these methods,
15160 * which typically operate on multi-byte strings:
15161 *
15162 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15163 * - IO#write: Writes zero or more strings to the stream;
15164 * each given object that is not already a string is converted via +to_s+.
15165 *
15166 * === Position
15167 *
15168 * An \IO stream has a nonnegative integer _position_,
15169 * which is the byte offset at which the next read or write is to occur.
15170 * A new stream has position zero (and line number zero);
15171 * method +rewind+ resets the position (and line number) to zero.
15172 *
15173 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15174 * Encoding::Converter instances used for that \IO.
15175 *
15176 * The relevant methods:
15177 *
15178 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15179 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15180 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15181 * relative to a given position +whence+
15182 * (indicating the beginning, end, or current position).
15183 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15184 *
15185 * === Open and Closed Streams
15186 *
15187 * A new \IO stream may be open for reading, open for writing, or both.
15188 *
15189 * A stream is automatically closed when claimed by the garbage collector.
15190 *
15191 * Attempted reading or writing on a closed stream raises an exception.
15192 *
15193 * The relevant methods:
15194 *
15195 * - IO#close: Closes the stream for both reading and writing.
15196 * - IO#close_read: Closes the stream for reading.
15197 * - IO#close_write: Closes the stream for writing.
15198 * - IO#closed?: Returns whether the stream is closed.
15199 *
15200 * === End-of-Stream
15201 *
15202 * You can query whether a stream is positioned at its end:
15203 *
15204 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15205 *
15206 * You can reposition to end-of-stream by using method IO#seek:
15207 *
15208 * f = File.new('t.txt')
15209 * f.eof? # => false
15210 * f.seek(0, :END)
15211 * f.eof? # => true
15212 * f.close
15213 *
15214 * Or by reading all stream content (which is slower than using IO#seek):
15215 *
15216 * f.rewind
15217 * f.eof? # => false
15218 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15219 * f.eof? # => true
15220 *
15221 * == Line \IO
15222 *
15223 * Class \IO supports line-oriented
15224 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15225 *
15226 * === Line Input
15227 *
15228 * Class \IO supports line-oriented input for
15229 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15230 *
15231 * ==== \File Line Input
15232 *
15233 * You can read lines from a file using these methods:
15234 *
15235 * - IO.foreach: Reads each line and passes it to the given block.
15236 * - IO.readlines: Reads and returns all lines in an array.
15237 *
15238 * For each of these methods:
15239 *
15240 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15241 * - Line parsing depends on the effective <i>line separator</i>;
15242 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15243 * - The length of each returned line depends on the effective <i>line limit</i>;
15244 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15245 *
15246 * ==== Stream Line Input
15247 *
15248 * You can read lines from an \IO stream using these methods:
15249 *
15250 * - IO#each_line: Reads each remaining line, passing it to the given block.
15251 * - IO#gets: Returns the next line.
15252 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15253 * - IO#readlines: Returns all remaining lines in an array.
15254 *
15255 * For each of these methods:
15256 *
15257 * - Reading may begin mid-line,
15258 * depending on the stream's _position_;
15259 * see {Position}[rdoc-ref:IO@Position].
15260 * - Line parsing depends on the effective <i>line separator</i>;
15261 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15262 * - The length of each returned line depends on the effective <i>line limit</i>;
15263 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15264 *
15265 * ===== Line Separator
15266 *
15267 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15268 * the string that determines what is considered a line;
15269 * it is sometimes called the <i>input record separator</i>.
15270 *
15271 * The default line separator is taken from global variable <tt>$/</tt>,
15272 * whose initial value is <tt>"\n"</tt>.
15273 *
15274 * Generally, the line to be read next is all data
15275 * from the current {position}[rdoc-ref:IO@Position]
15276 * to the next line separator
15277 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15278 *
15279 * f = File.new('t.txt')
15280 * # Method gets with no sep argument returns the next line, according to $/.
15281 * f.gets # => "First line\n"
15282 * f.gets # => "Second line\n"
15283 * f.gets # => "\n"
15284 * f.gets # => "Fourth line\n"
15285 * f.gets # => "Fifth line\n"
15286 * f.close
15287 *
15288 * You can use a different line separator by passing argument +sep+:
15289 *
15290 * f = File.new('t.txt')
15291 * f.gets('l') # => "First l"
15292 * f.gets('li') # => "ine\nSecond li"
15293 * f.gets('lin') # => "ne\n\nFourth lin"
15294 * f.gets # => "e\n"
15295 * f.close
15296 *
15297 * Or by setting global variable <tt>$/</tt>:
15298 *
15299 * f = File.new('t.txt')
15300 * $/ = 'l'
15301 * f.gets # => "First l"
15302 * f.gets # => "ine\nSecond l"
15303 * f.gets # => "ine\n\nFourth l"
15304 * f.close
15305 *
15306 * ===== Special Line Separator Values
15307 *
15308 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15309 * accepts two special values for parameter +sep+:
15310 *
15311 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15312 *
15313 * f = File.new('t.txt')
15314 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15315 * f.close
15316 *
15317 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15318 * (paragraphs being separated by two consecutive line separators):
15319 *
15320 * f = File.new('t.txt')
15321 * f.gets('') # => "First line\nSecond line\n\n"
15322 * f.gets('') # => "Fourth line\nFifth line\n"
15323 * f.close
15324 *
15325 * ===== Line Limit
15326 *
15327 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15328 * uses an integer <i>line limit</i>,
15329 * which restricts the number of bytes that may be returned.
15330 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15331 * than the limit).
15332 *
15333 * The default limit value is <tt>-1</tt>;
15334 * any negative limit value means that there is no limit.
15335 *
15336 * If there is no limit, the line is determined only by +sep+.
15337 *
15338 * # Text with 1-byte characters.
15339 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15340 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15341 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15342 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15343 * # No more than one line.
15344 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15345 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15346 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15347 *
15348 * # Text with 2-byte characters, which will not be split.
15349 * File.open('t.rus') {|f| f.gets(1).size } # => 1
15350 * File.open('t.rus') {|f| f.gets(2).size } # => 1
15351 * File.open('t.rus') {|f| f.gets(3).size } # => 2
15352 * File.open('t.rus') {|f| f.gets(4).size } # => 2
15353 *
15354 * ===== Line Separator and Line Limit
15355 *
15356 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15357 *
15358 * - Returns the next line as determined by line separator +sep+.
15359 * - But returns no more bytes than are allowed by the limit +limit+.
15360 *
15361 * Example:
15362 *
15363 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15364 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15365 *
15366 * ===== Line Number
15367 *
15368 * A readable \IO stream has a non-negative integer <i>line number</i>:
15369 *
15370 * - IO#lineno: Returns the line number.
15371 * - IO#lineno=: Resets and returns the line number.
15372 *
15373 * Unless modified by a call to method IO#lineno=,
15374 * the line number is the number of lines read
15375 * by certain line-oriented methods,
15376 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15377 *
15378 * - IO.foreach: Increments the line number on each call to the block.
15379 * - IO#each_line: Increments the line number on each call to the block.
15380 * - IO#gets: Increments the line number.
15381 * - IO#readline: Increments the line number.
15382 * - IO#readlines: Increments the line number for each line read.
15383 *
15384 * A new stream is initially has line number zero (and position zero);
15385 * method +rewind+ resets the line number (and position) to zero:
15386 *
15387 * f = File.new('t.txt')
15388 * f.lineno # => 0
15389 * f.gets # => "First line\n"
15390 * f.lineno # => 1
15391 * f.rewind
15392 * f.lineno # => 0
15393 * f.close
15394 *
15395 * Reading lines from a stream usually changes its line number:
15396 *
15397 * f = File.new('t.txt', 'r')
15398 * f.lineno # => 0
15399 * f.readline # => "This is line one.\n"
15400 * f.lineno # => 1
15401 * f.readline # => "This is the second line.\n"
15402 * f.lineno # => 2
15403 * f.readline # => "Here's the third line.\n"
15404 * f.lineno # => 3
15405 * f.eof? # => true
15406 * f.close
15407 *
15408 * Iterating over lines in a stream usually changes its line number:
15409 *
15410 * File.open('t.txt') do |f|
15411 * f.each_line do |line|
15412 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15413 * end
15414 * end
15415 *
15416 * Output:
15417 *
15418 * "position=11 eof?=false lineno=1"
15419 * "position=23 eof?=false lineno=2"
15420 * "position=24 eof?=false lineno=3"
15421 * "position=36 eof?=false lineno=4"
15422 * "position=47 eof?=true lineno=5"
15423 *
15424 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15425 * the line number does not affect where the next read or write will occur:
15426 *
15427 * f = File.new('t.txt')
15428 * f.lineno = 1000
15429 * f.lineno # => 1000
15430 * f.gets # => "First line\n"
15431 * f.lineno # => 1001
15432 * f.close
15433 *
15434 * Associated with the line number is the global variable <tt>$.</tt>:
15435 *
15436 * - When a stream is opened, <tt>$.</tt> is not set;
15437 * its value is left over from previous activity in the process:
15438 *
15439 * $. = 41
15440 * f = File.new('t.txt')
15441 * $. = 41
15442 * # => 41
15443 * f.close
15444 *
15445 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15446 *
15447 * f0 = File.new('t.txt')
15448 * f1 = File.new('t.dat')
15449 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15450 * $. # => 5
15451 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15452 * $. # => 1
15453 * f0.close
15454 * f1.close
15455 *
15456 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15457 *
15458 * f = File.new('t.txt')
15459 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15460 * $. # => 5
15461 * f.rewind
15462 * f.seek(0, :SET)
15463 * $. # => 5
15464 * f.close
15465 *
15466 * === Line Output
15467 *
15468 * You can write to an \IO stream line-by-line using this method:
15469 *
15470 * - IO#puts: Writes objects to the stream.
15471 *
15472 * == Character \IO
15473 *
15474 * You can process an \IO stream character-by-character using these methods:
15475 *
15476 * - IO#getc: Reads and returns the next character from the stream.
15477 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15478 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15479 * - IO#putc: Writes a character to the stream.
15480 * - IO#each_char: Reads each remaining character in the stream,
15481 * passing the character to the given block.
15482 *
15483 * == Byte \IO
15484 *
15485 * You can process an \IO stream byte-by-byte using these methods:
15486 *
15487 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15488 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15489 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15490 * - IO#each_byte: Reads each remaining byte in the stream,
15491 * passing the byte to the given block.
15492 *
15493 * == Codepoint \IO
15494 *
15495 * You can process an \IO stream codepoint-by-codepoint:
15496 *
15497 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15498 *
15499 * == What's Here
15500 *
15501 * First, what's elsewhere. Class \IO:
15502 *
15503 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15504 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15505 * which provides dozens of additional methods.
15506 *
15507 * Here, class \IO provides methods that are useful for:
15508 *
15509 * - {Creating}[rdoc-ref:IO@Creating]
15510 * - {Reading}[rdoc-ref:IO@Reading]
15511 * - {Writing}[rdoc-ref:IO@Writing]
15512 * - {Positioning}[rdoc-ref:IO@Positioning]
15513 * - {Iterating}[rdoc-ref:IO@Iterating]
15514 * - {Settings}[rdoc-ref:IO@Settings]
15515 * - {Querying}[rdoc-ref:IO@Querying]
15516 * - {Buffering}[rdoc-ref:IO@Buffering]
15517 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15518 * - {Other}[rdoc-ref:IO@Other]
15519 *
15520 * === Creating
15521 *
15522 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15523 * integer file descriptor.
15524 * - ::open: Creates a new \IO object.
15525 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15526 * - ::popen: Creates an \IO object to interact with a subprocess.
15527 * - ::select: Selects which given \IO instances are ready for reading,
15528 * writing, or have pending exceptions.
15529 *
15530 * === Reading
15531 *
15532 * - ::binread: Returns a binary string with all or a subset of bytes
15533 * from the given file.
15534 * - ::read: Returns a string with all or a subset of bytes from the given file.
15535 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15536 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15537 * - #getc: Returns the next character read from +self+ as a string.
15538 * - #gets: Returns the line read from +self+.
15539 * - #pread: Returns all or the next _n_ bytes read from +self+,
15540 * not updating the receiver's offset.
15541 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15542 * for a given _n_.
15543 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15544 * in non-block mode.
15545 * - #readbyte: Returns the next byte read from +self+;
15546 * same as #getbyte, but raises an exception on end-of-stream.
15547 * - #readchar: Returns the next character read from +self+;
15548 * same as #getc, but raises an exception on end-of-stream.
15549 * - #readline: Returns the next line read from +self+;
15550 * same as #getline, but raises an exception of end-of-stream.
15551 * - #readlines: Returns an array of all lines read read from +self+.
15552 * - #readpartial: Returns up to the given number of bytes from +self+.
15553 *
15554 * === Writing
15555 *
15556 * - ::binwrite: Writes the given string to the file at the given filepath,
15557 * in binary mode.
15558 * - ::write: Writes the given string to +self+.
15559 * - #<<: Appends the given string to +self+.
15560 * - #print: Prints last read line or given objects to +self+.
15561 * - #printf: Writes to +self+ based on the given format string and objects.
15562 * - #putc: Writes a character to +self+.
15563 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15564 * - #pwrite: Writes the given string at the given offset,
15565 * not updating the receiver's offset.
15566 * - #write: Writes one or more given strings to +self+.
15567 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15568 *
15569 * === Positioning
15570 *
15571 * - #lineno: Returns the current line number in +self+.
15572 * - #lineno=: Sets the line number is +self+.
15573 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15574 * - #pos=: Sets the byte offset in +self+.
15575 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15576 * - #rewind: Positions +self+ to the beginning of input.
15577 * - #seek: Sets the offset for +self+ relative to given position.
15578 *
15579 * === Iterating
15580 *
15581 * - ::foreach: Yields each line of given file to the block.
15582 * - #each (aliased as #each_line): Calls the given block
15583 * with each successive line in +self+.
15584 * - #each_byte: Calls the given block with each successive byte in +self+
15585 * as an integer.
15586 * - #each_char: Calls the given block with each successive character in +self+
15587 * as a string.
15588 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15589 * as an integer.
15590 *
15591 * === Settings
15592 *
15593 * - #autoclose=: Sets whether +self+ auto-closes.
15594 * - #binmode: Sets +self+ to binary mode.
15595 * - #close: Closes +self+.
15596 * - #close_on_exec=: Sets the close-on-exec flag.
15597 * - #close_read: Closes +self+ for reading.
15598 * - #close_write: Closes +self+ for writing.
15599 * - #set_encoding: Sets the encoding for +self+.
15600 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15601 * Unicode byte-order-mark.
15602 * - #sync=: Sets the sync-mode to the given value.
15603 *
15604 * === Querying
15605 *
15606 * - #autoclose?: Returns whether +self+ auto-closes.
15607 * - #binmode?: Returns whether +self+ is in binary mode.
15608 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15609 * - #closed?: Returns whether +self+ is closed.
15610 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15611 * - #external_encoding: Returns the external encoding object for +self+.
15612 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15613 * - #internal_encoding: Returns the internal encoding object for +self+.
15614 * - #pid: Returns the process ID of a child process associated with +self+,
15615 * if +self+ was created by ::popen.
15616 * - #stat: Returns the File::Stat object containing status information for +self+.
15617 * - #sync: Returns whether +self+ is in sync-mode.
15618 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15619 *
15620 * === Buffering
15621 *
15622 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15623 * - #flush: Flushes any buffered data within +self+ to the underlying
15624 * operating system.
15625 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15626 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15627 * - #ungetc: Prepends buffer for +self+ with given string.
15628 *
15629 * === Low-Level Access
15630 *
15631 * - ::sysopen: Opens the file given by its path,
15632 * returning the integer file descriptor.
15633 * - #advise: Announces the intention to access data from +self+ in a specific way.
15634 * - #fcntl: Passes a low-level command to the file specified
15635 * by the given file descriptor.
15636 * - #ioctl: Passes a low-level command to the device specified
15637 * by the given file descriptor.
15638 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15639 * - #sysseek: Sets the offset for +self+.
15640 * - #syswrite: Writes the given string to +self+ using a low-level write.
15641 *
15642 * === Other
15643 *
15644 * - ::copy_stream: Copies data from a source to a destination,
15645 * each of which is a filepath or an \IO-like object.
15646 * - ::try_convert: Returns a new \IO object resulting from converting
15647 * the given object.
15648 * - #inspect: Returns the string representation of +self+.
15649 *
15650 */
15651
15652void
15653Init_IO(void)
15654{
15655 VALUE rb_cARGF;
15656#ifdef __CYGWIN__
15657#include <sys/cygwin.h>
15658 static struct __cygwin_perfile pf[] =
15659 {
15660 {"", O_RDONLY | O_BINARY},
15661 {"", O_WRONLY | O_BINARY},
15662 {"", O_RDWR | O_BINARY},
15663 {"", O_APPEND | O_BINARY},
15664 {NULL, 0}
15665 };
15666 cygwin_internal(CW_PERFILE, pf);
15667#endif
15668
15671
15672 id_write = rb_intern_const("write");
15673 id_read = rb_intern_const("read");
15674 id_getc = rb_intern_const("getc");
15675 id_flush = rb_intern_const("flush");
15676 id_readpartial = rb_intern_const("readpartial");
15677 id_set_encoding = rb_intern_const("set_encoding");
15678 id_fileno = rb_intern_const("fileno");
15679
15680 rb_define_global_function("syscall", rb_f_syscall, -1);
15681
15682 rb_define_global_function("open", rb_f_open, -1);
15683 rb_define_global_function("printf", rb_f_printf, -1);
15684 rb_define_global_function("print", rb_f_print, -1);
15685 rb_define_global_function("putc", rb_f_putc, 1);
15686 rb_define_global_function("puts", rb_f_puts, -1);
15687 rb_define_global_function("gets", rb_f_gets, -1);
15688 rb_define_global_function("readline", rb_f_readline, -1);
15689 rb_define_global_function("select", rb_f_select, -1);
15690
15691 rb_define_global_function("readlines", rb_f_readlines, -1);
15692
15693 rb_define_global_function("`", rb_f_backquote, 1);
15694
15695 rb_define_global_function("p", rb_f_p, -1);
15696 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15697
15698 rb_cIO = rb_define_class("IO", rb_cObject);
15700
15701 /* Can be raised by IO operations when IO#timeout= is set. */
15703
15704 /* Readable event mask for IO#wait. */
15705 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15706 /* Writable event mask for IO#wait. */
15707 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15708 /* Priority event mask for IO#wait. */
15709 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15710
15711 /* exception to wait for reading. see IO.select. */
15713 /* exception to wait for writing. see IO.select. */
15715 /* exception to wait for reading by EAGAIN. see IO.select. */
15716 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15717 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15718 /* exception to wait for writing by EAGAIN. see IO.select. */
15719 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15720 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15721#if EAGAIN == EWOULDBLOCK
15722 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15723 /* same as IO::EAGAINWaitReadable */
15724 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15725 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15726 /* same as IO::EAGAINWaitWritable */
15727 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15728#else
15729 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15730 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15731 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15732 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15733 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15734 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15735#endif
15736 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15737 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15738 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15739 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15740 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15741 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15742
15743#if 0
15744 /* This is necessary only for forcing rdoc handle File::open */
15745 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15746#endif
15747
15748 rb_define_alloc_func(rb_cIO, io_alloc);
15749 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15750 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15751 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15752 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15753 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15754 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15755 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15756 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15757 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15758 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15759 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15760 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15761 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15762 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15763 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15764
15765 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15766
15768 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15769
15770 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15771 rb_vm_register_global_object(rb_default_rs);
15772 rb_rs = rb_default_rs;
15774 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15775 rb_gvar_ractor_local("$/"); // not local but ractor safe
15776 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15777 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15778 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15779
15780 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15781 rb_gvar_ractor_local("$_");
15782
15783 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15784 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15785
15786 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15787 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15788 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15789 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15790
15791 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15792 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15793 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15794 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15795 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15796
15797 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15798 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15799
15800 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15801 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15802
15803 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15804 rb_define_alias(rb_cIO, "to_i", "fileno");
15805 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15806
15807 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15808 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15809
15810 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15811 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15812 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15813 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15814
15815 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15816 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15817
15818 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15819
15820 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15821 rb_define_method(rb_cIO, "read", io_read, -1);
15822 rb_define_method(rb_cIO, "write", io_write_m, -1);
15823 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15824 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15825 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15826 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15827 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15828 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15829 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15831 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15832 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15833 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15834 /* Set I/O position from the beginning */
15835 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15836 /* Set I/O position from the current position */
15837 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15838 /* Set I/O position from the end */
15839 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15840#ifdef SEEK_DATA
15841 /* Set I/O position to the next location containing data */
15842 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15843#endif
15844#ifdef SEEK_HOLE
15845 /* Set I/O position to the next hole */
15846 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15847#endif
15848 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15849 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15850 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15851 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15852 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15853
15854 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15855 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15856
15857 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15858 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15859 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15860 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15861
15862 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15863 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15864 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15865 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15866 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15867 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15868
15869 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15870 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15871 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15872
15873 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15874 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15875
15876 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15877
15878 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15879 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15880 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15881 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15882
15883 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15884 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15885
15886 rb_define_method(rb_cIO, "wait", io_wait, -1);
15887
15888 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15889 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15890 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15891
15892 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15893 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15894 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15895 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15896
15897 rb_gvar_ractor_local("$stdin");
15898 rb_gvar_ractor_local("$stdout");
15899 rb_gvar_ractor_local("$>");
15900 rb_gvar_ractor_local("$stderr");
15901
15903 rb_stdin = rb_io_prep_stdin();
15905 rb_stdout = rb_io_prep_stdout();
15907 rb_stderr = rb_io_prep_stderr();
15908
15909 orig_stdout = rb_stdout;
15910 orig_stderr = rb_stderr;
15911
15912 /* Holds the original stdin */
15914 /* Holds the original stdout */
15916 /* Holds the original stderr */
15918
15919#if 0
15920 /* Hack to get rdoc to regard ARGF as a class: */
15921 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15922#endif
15923
15924 rb_cARGF = rb_class_new(rb_cObject);
15925 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15926 rb_define_alloc_func(rb_cARGF, argf_alloc);
15927
15929
15930 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15931 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15932 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15933 rb_define_alias(rb_cARGF, "inspect", "to_s");
15934 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15935
15936 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15937 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15938 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15939 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15940 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15941 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15942 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15943 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15944 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15945
15946 rb_define_method(rb_cARGF, "read", argf_read, -1);
15947 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15948 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15949 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15950 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15951 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15952 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15953 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15954 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15955 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15956 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15957 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15958 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15959 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15960 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15961 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15962 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15963 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15964 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15965 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15966
15967 rb_define_method(rb_cARGF, "write", argf_write, -1);
15968 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15969 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15970 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15971 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15972
15973 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15974 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15975 rb_define_method(rb_cARGF, "file", argf_file, 0);
15976 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15977 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15978 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15979
15980 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15981 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15982
15983 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15984 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15985
15986 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15987 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15988 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15989
15990 argf = rb_class_new_instance(0, 0, rb_cARGF);
15991
15993 /*
15994 * ARGF is a stream designed for use in scripts that process files given
15995 * as command-line arguments or passed in via STDIN.
15996 *
15997 * See ARGF (the class) for more details.
15998 */
16000
16001 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
16002 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
16003 ARGF.filename = rb_str_new2("-");
16004
16005 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
16006 rb_gvar_ractor_local("$-i");
16007
16008 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16009
16010#if defined (_WIN32) || defined(__CYGWIN__)
16011 atexit(pipe_atexit);
16012#endif
16013
16014 Init_File();
16015
16016 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16017
16018 sym_mode = ID2SYM(rb_intern_const("mode"));
16019 sym_perm = ID2SYM(rb_intern_const("perm"));
16020 sym_flags = ID2SYM(rb_intern_const("flags"));
16021 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16022 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16023 sym_encoding = ID2SYM(rb_id_encoding());
16024 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16025 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16026 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16027 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16028 sym_normal = ID2SYM(rb_intern_const("normal"));
16029 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16030 sym_random = ID2SYM(rb_intern_const("random"));
16031 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16032 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16033 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16034 sym_SET = ID2SYM(rb_intern_const("SET"));
16035 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16036 sym_END = ID2SYM(rb_intern_const("END"));
16037#ifdef SEEK_DATA
16038 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16039#endif
16040#ifdef SEEK_HOLE
16041 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16042#endif
16043 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16044 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16045}
16046
16047#include "io.rbinc"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:138
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1697
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1479
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:851
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1515
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1626
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2843
int rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt,...)
Identical to rb_scan_args(), except it also accepts kw_splat.
Definition class.c:3146
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
Definition class.c:3133
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:941
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2922
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:400
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:134
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h: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:1677
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
void rb_notimplement(void)
Definition error.c:3836
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:476
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:508
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1440
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:680
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3905
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:14726
VALUE rb_eIOError
IOError exception.
Definition io.c:189
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1427
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3995
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:3911
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:475
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
VALUE rb_eEOFError
EOFError exception.
Definition io.c:188
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14720
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2121
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1450
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:65
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3228
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:682
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2123
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2164
VALUE rb_cIO
IO class.
Definition io.c:187
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
Definition object.c:2152
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
VALUE rb_stdin
STDIN constant.
Definition io.c:201
VALUE rb_stderr
STDERR constant.
Definition io.c:201
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:247
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:589
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:693
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:191
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:192
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1297
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
Definition object.c:3209
VALUE rb_cFile
File class.
Definition file.c:175
VALUE rb_stdout
STDOUT constant.
Definition io.c:201
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3222
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:1665
int rb_enc_str_coderange(VALUE str)
Scans the passed string to collect its code range.
Definition string.c:1280
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3803
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c:1164
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
Definition transcode.c:2600
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
Definition transcode.c:2097
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
Definition transcode.c:1475
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
Definition transcode.h:69
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
Definition transcode.h:41
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1770
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1814
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
Definition transcode.c:1931
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
Definition transcode.c:2651
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
Definition transcode.c:1996
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
Definition transcode.c:2914
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4272
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4278
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1731
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1781
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c: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:8609
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4304
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:427
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
Definition io.c:8754
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2351
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9183
VALUE rb_io_ungetbyte(VALUE io, VALUE b)
Identical to rb_io_ungetc(), except it doesn't take the encoding of the passed IO into account.
Definition io.c:5173
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5079
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:374
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
Definition io.c:9364
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:248
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:328
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:206
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2696
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
Definition io.c:9163
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:6374
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6328
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5237
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7376
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10453
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:7259
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:7266
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5748
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:1883
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:1877
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:2963
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1167
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:681
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:4102
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1681
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1532
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:1334
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1841
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:2304
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3870
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1146
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4585
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3692
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:4044
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:3257
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3557
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3675
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:3051
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:2031
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1514
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c:2163
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1449
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
Definition io.c:1604
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
Definition thread.c:1432
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:3019
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1598
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1455
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2958
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:438
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:2125
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:497
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3064
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:4235
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:838
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:147
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:6460
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:6593
#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:245
rb_io_event
Type of events that an IO can wait.
Definition io.h:81
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:82
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition io.h:84
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition io.h:83
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:153
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
Definition io.h:237
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:427
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:177
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:200
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition io.c:1024
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
Definition io.c:1592
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
Definition io.c:7076
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:6742
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2899
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:150
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:9410
#define FMODE_APPEND
The IO is opened for appending.
Definition io.h:192
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition io.h:450
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition io.h:185
#define FMODE_BINMODE
The IO is in "binary mode".
Definition io.h:164
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
Definition io.c:1651
int capa
Designed capacity of the buffer.
Definition io.h:11
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition io.h:421
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
Definition io.c:1610
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:190
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:2
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:171
int off
Offset inside of ptr.
Definition io.h:5
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
Definition io.c:2973
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, enum rb_io_mode *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
Definition io.c:6867
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:208
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition io.h:228
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
Definition io.c:5675
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
Definition io.c:817
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:5856
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:886
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:2016
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:996
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
Definition io.h:214
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:823
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3425
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1549
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
Definition io.c:9276
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:834
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1048
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
Definition io.c:1666
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:796
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1515
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7363
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1454
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:2822
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:2882
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:2870
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:2858
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:1930
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition sprintf.c:209
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
Definition vm_eval.c:1406
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1372
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition off_t.h:55
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:442
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:488
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:79
#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:498
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14686
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9062
#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:228
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:640
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:271
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:452
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:616
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:446
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
Definition scheduler.h:70
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:482
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:652
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread instead of...
Definition scheduler.c:233
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:628
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:458
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:4370
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
@ RUBY_Qfalse
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
C99 shim for <stdbool.h>
Ruby's File and IO.
Definition rfile.h:35
Definition io.c:236
Definition win32.h:226
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:203
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
Decomposed encoding flags (e.g.
Definition io.h:119
int ecflags
Flags.
Definition io.h:129
VALUE ecopts
Flags as Ruby hash.
Definition io.h:137
rb_encoding * enc2
External encoding.
Definition io.h:123
rb_encoding * enc
Internal encoding.
Definition io.h:121
IO buffers.
Definition io.h:94
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:97
int off
Offset inside of ptr.
Definition io.h:100
int len
Length of the buffer.
Definition io.h:103
int capa
Designed capacity of the buffer.
Definition io.h:106
Ruby's IO, metadata and buffers.
Definition io.h:280
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:315
enum rb_io_mode mode
mode flags: FMODE_XXXs
Definition io.h:295
void(* finalize)(struct rb_io *, int)
finalize proc
Definition io.h:311
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:337
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:348
struct rb_io_encoding encs
Decomposed encoding flags.
Definition io.h:333
VALUE self
The IO's Ruby level counterpart.
Definition io.h:283
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:385
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:391
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:287
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:375
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:330
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:361
int fd
file descriptor.
Definition io.h:291
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:322
int lineno
number of lines read
Definition io.h:303
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:357
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:344
rb_pid_t pid
child's pid (for pipes)
Definition io.h:299
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:368
VALUE pathv
pathname for file
Definition io.h:307
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