Ruby 3.5.0dev (2025-06-26 revision 4b1de7378d038109d85b5ab8b817de13c1217a3f)
io.c (4b1de7378d038109d85b5ab8b817de13c1217a3f)
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17#include "ruby/io/buffer.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <stddef.h>
22
23/* non-Linux poll may not work on all FDs */
24#if defined(HAVE_POLL)
25# if defined(__linux__)
26# define USE_POLL 1
27# endif
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29# define USE_POLL 1
30# endif
31#endif
32
33#ifndef USE_POLL
34# define USE_POLL 0
35#endif
36
37#undef free
38#define free(x) xfree(x)
39
40#if defined(DOSISH) || defined(__CYGWIN__)
41#include <io.h>
42#endif
43
44#include <sys/types.h>
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
49#endif
50
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
53#endif
54
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
56# define USE_SETVBUF
57#endif
58
59#ifdef __QNXNTO__
60#include <unix.h>
61#endif
62
63#include <sys/types.h>
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
65#include <sys/ioctl.h>
66#endif
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
68#include <fcntl.h>
69#elif defined(HAVE_SYS_FCNTL_H)
70#include <sys/fcntl.h>
71#endif
72
73#ifdef HAVE_SYS_TIME_H
74# include <sys/time.h>
75#endif
76
77#include <sys/stat.h>
78
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
81#endif
82
83#if !defined NOFILE
84# define NOFILE 64
85#endif
86
87#ifdef HAVE_UNISTD_H
88#include <unistd.h>
89#endif
90
91#ifdef HAVE_SYSCALL_H
92#include <syscall.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
95#endif
96
97#ifdef HAVE_SYS_UIO_H
98#include <sys/uio.h>
99#endif
100
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h> /* for WNOHANG on BSD */
103#endif
104
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
107
108# ifndef COPYFILE_STATE_COPIED
109/*
110 * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
111 * COPYFILE_STATE_COPIED. Since the only use of the former here
112 * requires the latter, we disable the former when the latter is undefined.
113 */
114# undef HAVE_FCOPYFILE
115# endif
116
117#endif
118
120#include "ccan/list/list.h"
121#include "dln.h"
122#include "encindex.h"
123#include "id.h"
124#include "internal.h"
125#include "internal/class.h"
126#include "internal/encoding.h"
127#include "internal/error.h"
128#include "internal/inits.h"
129#include "internal/io.h"
130#include "internal/numeric.h"
131#include "internal/object.h"
132#include "internal/process.h"
133#include "internal/thread.h"
134#include "internal/transcode.h"
135#include "internal/variable.h"
136#include "ruby/io.h"
137#include "ruby/io/buffer.h"
138#include "ruby/missing.h"
139#include "ruby/thread.h"
140#include "ruby/util.h"
141#include "ruby_atomic.h"
142#include "ruby/ractor.h"
143
144#if !USE_POLL
145# include "vm_core.h"
146#endif
147
148#include "builtin.h"
149
150#ifndef O_ACCMODE
151#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
152#endif
153
154#ifndef PIPE_BUF
155# ifdef _POSIX_PIPE_BUF
156# define PIPE_BUF _POSIX_PIPE_BUF
157# else
158# define PIPE_BUF 512 /* is this ok? */
159# endif
160#endif
161
162#ifndef EWOULDBLOCK
163# define EWOULDBLOCK EAGAIN
164#endif
165
166#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
167/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
168off_t __syscall(quad_t number, ...);
169#endif
170
171#define IO_RBUF_CAPA_MIN 8192
172#define IO_CBUF_CAPA_MIN (128*1024)
173#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174#define IO_WBUF_CAPA_MIN 8192
175
176#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
177
178/* define system APIs */
179#ifdef _WIN32
180#undef open
181#define open rb_w32_uopen
182#undef rename
183#define rename(f, t) rb_w32_urename((f), (t))
184#include "win32/file.h"
185#endif
186
193
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196static VALUE rb_eEWOULDBLOCKWaitReadable;
197static VALUE rb_eEWOULDBLOCKWaitWritable;
198static VALUE rb_eEINPROGRESSWaitWritable;
199static VALUE rb_eEINPROGRESSWaitReadable;
200
202static VALUE orig_stdout, orig_stderr;
203
205VALUE rb_rs;
208
209static VALUE argf;
210
211static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
212static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
213static VALUE sym_textmode, sym_binmode, sym_autoclose;
214static VALUE sym_SET, sym_CUR, sym_END;
215static VALUE sym_wait_readable, sym_wait_writable;
216#ifdef SEEK_DATA
217static VALUE sym_DATA;
218#endif
219#ifdef SEEK_HOLE
220static VALUE sym_HOLE;
221#endif
222
223static VALUE prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path);
224
225VALUE
226rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
227{
228 return rb_thread_io_blocking_call(io, function, argument, events);
229}
230
231VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
232{
233 return rb_io_blocking_region_wait(io, function, argument, 0);
234}
235
236struct argf {
237 VALUE filename, current_file;
238 long last_lineno; /* $. */
239 long lineno;
240 VALUE argv;
241 VALUE inplace;
242 struct rb_io_encoding encs;
243 int8_t init_p, next_p, binmode;
244};
245
246static rb_atomic_t max_file_descriptor = NOFILE;
247void
249{
250 rb_atomic_t afd = (rb_atomic_t)fd;
251 rb_atomic_t max_fd = max_file_descriptor;
252 int err;
253
254 if (fd < 0 || afd <= max_fd)
255 return;
256
257#if defined(HAVE_FCNTL) && defined(F_GETFL)
258 err = fcntl(fd, F_GETFL) == -1;
259#else
260 {
261 struct stat buf;
262 err = fstat(fd, &buf) != 0;
263 }
264#endif
265 if (err && errno == EBADF) {
266 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
267 }
268
269 while (max_fd < afd) {
270 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
271 }
272}
273
274void
275rb_maygvl_fd_fix_cloexec(int fd)
276{
277 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
278#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
279 int flags, flags2, ret;
280 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
281 if (flags == -1) {
282 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
283 }
284 if (fd <= 2)
285 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
286 else
287 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
288 if (flags != flags2) {
289 ret = fcntl(fd, F_SETFD, flags2);
290 if (ret != 0) {
291 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
292 }
293 }
294#endif
295}
296
297void
299{
300 rb_maygvl_fd_fix_cloexec(fd);
302}
303
304/* this is only called once */
305static int
306rb_fix_detect_o_cloexec(int fd)
307{
308#if defined(O_CLOEXEC) && defined(F_GETFD)
309 int flags = fcntl(fd, F_GETFD);
310
311 if (flags == -1)
312 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
313
314 if (flags & FD_CLOEXEC)
315 return 1;
316#endif /* fall through if O_CLOEXEC does not work: */
317 rb_maygvl_fd_fix_cloexec(fd);
318 return 0;
319}
320
321static inline bool
322io_again_p(int e)
323{
324 return (e == EWOULDBLOCK) || (e == EAGAIN);
325}
326
327int
328rb_cloexec_open(const char *pathname, int flags, mode_t mode)
329{
330 int ret;
331 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
332
333 static const int retry_interval = 0;
334 static const int retry_max_count = 10000;
335
336 int retry_count = 0;
337
338#ifdef O_CLOEXEC
339 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
340 flags |= O_CLOEXEC;
341#elif defined O_NOINHERIT
342 flags |= O_NOINHERIT;
343#endif
344
345 while ((ret = open(pathname, flags, mode)) == -1) {
346 int e = errno;
347 if (!io_again_p(e)) break;
348 if (retry_count++ >= retry_max_count) break;
349
350 sleep(retry_interval);
351 }
352
353 if (ret < 0) return ret;
354 if (ret <= 2 || o_cloexec_state == 0) {
355 rb_maygvl_fd_fix_cloexec(ret);
356 }
357 else if (o_cloexec_state > 0) {
358 return ret;
359 }
360 else {
361 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
362 }
363 return ret;
364}
365
366int
368{
369 /* Don't allocate standard file descriptors: 0, 1, 2 */
370 return rb_cloexec_fcntl_dupfd(oldfd, 3);
371}
372
373int
374rb_cloexec_dup2(int oldfd, int newfd)
375{
376 int ret;
377
378 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
379 * rb_cloexec_dup2 succeeds as dup2. */
380 if (oldfd == newfd) {
381 ret = newfd;
382 }
383 else {
384#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
385 static int try_dup3 = 1;
386 if (2 < newfd && try_dup3) {
387 ret = dup3(oldfd, newfd, O_CLOEXEC);
388 if (ret != -1)
389 return ret;
390 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
391 if (errno == ENOSYS) {
392 try_dup3 = 0;
393 ret = dup2(oldfd, newfd);
394 }
395 }
396 else {
397 ret = dup2(oldfd, newfd);
398 }
399#else
400 ret = dup2(oldfd, newfd);
401#endif
402 if (ret < 0) return ret;
403 }
404 rb_maygvl_fd_fix_cloexec(ret);
405 return ret;
406}
407
408static int
409rb_fd_set_nonblock(int fd)
410{
411#ifdef _WIN32
412 return rb_w32_set_nonblock(fd);
413#elif defined(F_GETFL)
414 int oflags = fcntl(fd, F_GETFL);
415
416 if (oflags == -1)
417 return -1;
418 if (oflags & O_NONBLOCK)
419 return 0;
420 oflags |= O_NONBLOCK;
421 return fcntl(fd, F_SETFL, oflags);
422#endif
423 return 0;
424}
425
426int
427rb_cloexec_pipe(int descriptors[2])
428{
429#ifdef HAVE_PIPE2
430 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
431#else
432 int result = pipe(descriptors);
433#endif
434
435 if (result < 0)
436 return result;
437
438#ifdef __CYGWIN__
439 if (result == 0 && descriptors[1] == -1) {
440 close(descriptors[0]);
441 descriptors[0] = -1;
442 errno = ENFILE;
443 return -1;
444 }
445#endif
446
447#ifndef HAVE_PIPE2
448 rb_maygvl_fd_fix_cloexec(descriptors[0]);
449 rb_maygvl_fd_fix_cloexec(descriptors[1]);
450
451#ifndef _WIN32
452 rb_fd_set_nonblock(descriptors[0]);
453 rb_fd_set_nonblock(descriptors[1]);
454#endif
455#endif
456
457 return result;
458}
459
460int
461rb_cloexec_fcntl_dupfd(int fd, int minfd)
462{
463 int ret;
464
465#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
466 static int try_dupfd_cloexec = 1;
467 if (try_dupfd_cloexec) {
468 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
469 if (ret != -1) {
470 if (ret <= 2)
471 rb_maygvl_fd_fix_cloexec(ret);
472 return ret;
473 }
474 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
475 if (errno == EINVAL) {
476 ret = fcntl(fd, F_DUPFD, minfd);
477 if (ret != -1) {
478 try_dupfd_cloexec = 0;
479 }
480 }
481 }
482 else {
483 ret = fcntl(fd, F_DUPFD, minfd);
484 }
485#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
486 ret = fcntl(fd, F_DUPFD, minfd);
487#else
488 ret = dup(fd);
489 if (ret >= 0 && ret < minfd) {
490 const int prev_fd = ret;
491 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
492 close(prev_fd);
493 }
494 return ret;
495#endif
496 if (ret < 0) return ret;
497 rb_maygvl_fd_fix_cloexec(ret);
498 return ret;
499}
500
501#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
502#define ARGF argf_of(argf)
503
504#define GetWriteIO(io) rb_io_get_write_io(io)
505
506#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
507#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
508#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
509#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
510
511#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
512#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
513#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
514
515#if defined(_WIN32)
516#define WAIT_FD_IN_WIN32(fptr) \
517 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
518#else
519#define WAIT_FD_IN_WIN32(fptr)
520#endif
521
522#define READ_CHECK(fptr) do {\
523 if (!READ_DATA_PENDING(fptr)) {\
524 WAIT_FD_IN_WIN32(fptr);\
525 rb_io_check_closed(fptr);\
526 }\
527} while(0)
528
529#ifndef S_ISSOCK
530# ifdef _S_ISSOCK
531# define S_ISSOCK(m) _S_ISSOCK(m)
532# else
533# ifdef _S_IFSOCK
534# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
535# else
536# ifdef S_IFSOCK
537# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
538# endif
539# endif
540# endif
541#endif
542
543static int io_fflush(rb_io_t *);
544static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
545static void clear_codeconv(rb_io_t *fptr);
546
547#define FMODE_SIGNAL_ON_EPIPE (1<<17)
548
549#define fptr_signal_on_epipe(fptr) \
550 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
551
552#define fptr_set_signal_on_epipe(fptr, flag) \
553 ((flag) ? \
554 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
555 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
556
557extern ID ruby_static_id_signo;
558
559NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
560static void
561rb_sys_fail_on_write(rb_io_t *fptr)
562{
563 int e = errno;
564 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
565#if defined EPIPE
566 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
567 const VALUE sig =
568# if defined SIGPIPE
569 INT2FIX(SIGPIPE) - INT2FIX(0) +
570# endif
571 INT2FIX(0);
572 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
573 }
574#endif
575 rb_exc_raise(errinfo);
576}
577
578#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
579#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
580#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
581# define RUBY_CRLF_ENVIRONMENT 1
582#else
583# define RUBY_CRLF_ENVIRONMENT 0
584#endif
585
586#if RUBY_CRLF_ENVIRONMENT
587/* Windows */
588# define DEFAULT_TEXTMODE FMODE_TEXTMODE
589# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
590/*
591 * CRLF newline is set as default newline decorator.
592 * If only CRLF newline conversion is needed, we use binary IO process
593 * with OS's text mode for IO performance improvement.
594 * If encoding conversion is needed or a user sets text mode, we use encoding
595 * conversion IO process and universal newline decorator by default.
596 */
597#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
598#define WRITECONV_MASK ( \
599 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
600 ECONV_STATEFUL_DECORATOR_MASK|\
601 0)
602#define NEED_WRITECONV(fptr) ( \
603 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
604 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
605 0)
606#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
607
608#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
609 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
610 if (((fptr)->mode & FMODE_READABLE) &&\
611 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
612 setmode((fptr)->fd, O_BINARY);\
613 }\
614 else {\
615 setmode((fptr)->fd, O_TEXT);\
616 }\
617 }\
618} while(0)
619
620#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
621 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
622 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
623 }\
624} while(0)
625
626/*
627 * IO unread with taking care of removed '\r' in text mode.
628 */
629static void
630io_unread(rb_io_t *fptr, bool discard_rbuf)
631{
632 rb_off_t r, pos;
633 ssize_t read_size;
634 long i;
635 long newlines = 0;
636 long extra_max;
637 char *p;
638 char *buf;
639
640 rb_io_check_closed(fptr);
641 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
642 return;
643 }
644
645 errno = 0;
646 if (!rb_w32_fd_is_text(fptr->fd)) {
647 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
648 if (r < 0 && errno) {
649 if (errno == ESPIPE)
650 fptr->mode |= FMODE_DUPLEX;
651 if (!discard_rbuf) return;
652 }
653
654 goto end;
655 }
656
657 pos = lseek(fptr->fd, 0, SEEK_CUR);
658 if (pos < 0 && errno) {
659 if (errno == ESPIPE)
660 fptr->mode |= FMODE_DUPLEX;
661 if (!discard_rbuf) goto end;
662 }
663
664 /* add extra offset for removed '\r' in rbuf */
665 extra_max = (long)(pos - fptr->rbuf.len);
666 p = fptr->rbuf.ptr + fptr->rbuf.off;
667
668 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
669 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
670 newlines++;
671 }
672
673 for (i = 0; i < fptr->rbuf.len; i++) {
674 if (*p == '\n') newlines++;
675 if (extra_max == newlines) break;
676 p++;
677 }
678
679 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
680 while (newlines >= 0) {
681 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
682 if (newlines == 0) break;
683 if (r < 0) {
684 newlines--;
685 continue;
686 }
687 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
688 if (read_size < 0) {
689 int e = errno;
690 free(buf);
691 rb_syserr_fail_path(e, fptr->pathv);
692 }
693 if (read_size == fptr->rbuf.len) {
694 lseek(fptr->fd, r, SEEK_SET);
695 break;
696 }
697 else {
698 newlines--;
699 }
700 }
701 free(buf);
702 end:
703 fptr->rbuf.off = 0;
704 fptr->rbuf.len = 0;
705 clear_codeconv(fptr);
706 return;
707}
708
709/*
710 * We use io_seek to back cursor position when changing mode from text to binary,
711 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
712 * conversion for working properly with mode change.
713 *
714 * Return previous translation mode.
715 */
716static inline int
717set_binary_mode_with_seek_cur(rb_io_t *fptr)
718{
719 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
720
721 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
722 return setmode(fptr->fd, O_BINARY);
723 }
724 flush_before_seek(fptr, false);
725 return setmode(fptr->fd, O_BINARY);
726}
727#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
728
729#else
730/* Unix */
731# define DEFAULT_TEXTMODE 0
732#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
733#define NEED_WRITECONV(fptr) ( \
734 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
735 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
736 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
737 0)
738#define SET_BINARY_MODE(fptr) (void)(fptr)
739#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
740#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
741#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
742#endif
743
744#if !defined HAVE_SHUTDOWN && !defined shutdown
745#define shutdown(a,b) 0
746#endif
747
748#if defined(_WIN32)
749#define is_socket(fd, path) rb_w32_is_socket(fd)
750#elif !defined(S_ISSOCK)
751#define is_socket(fd, path) 0
752#else
753static int
754is_socket(int fd, VALUE path)
755{
756 struct stat sbuf;
757 if (fstat(fd, &sbuf) < 0)
758 rb_sys_fail_path(path);
759 return S_ISSOCK(sbuf.st_mode);
760}
761#endif
762
763static const char closed_stream[] = "closed stream";
764
765static void
766io_fd_check_closed(int fd)
767{
768 if (fd < 0) {
769 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
770 rb_raise(rb_eIOError, closed_stream);
771 }
772}
773
774void
775rb_eof_error(void)
776{
777 rb_raise(rb_eEOFError, "end of file reached");
778}
779
780VALUE
782{
783 rb_check_frozen(io);
784 return io;
785}
786
787void
789{
790 if (!fptr) {
791 rb_raise(rb_eIOError, "uninitialized stream");
792 }
793}
794
795void
797{
799 io_fd_check_closed(fptr->fd);
800}
801
802static rb_io_t *
803rb_io_get_fptr(VALUE io)
804{
805 rb_io_t *fptr = RFILE(io)->fptr;
807 return fptr;
808}
809
810VALUE
812{
813 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
814}
815
816VALUE
818{
819 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
820}
821
822VALUE
824{
825 VALUE write_io;
826 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
827 if (write_io) {
828 return write_io;
829 }
830 return io;
831}
832
833VALUE
835{
836 VALUE write_io;
837 rb_io_t *fptr = rb_io_get_fptr(io);
838 if (!RTEST(w)) {
839 w = 0;
840 }
841 else {
842 GetWriteIO(w);
843 }
844 write_io = fptr->tied_io_for_writing;
845 fptr->tied_io_for_writing = w;
846 return write_io ? write_io : Qnil;
847}
848
849/*
850 * call-seq:
851 * timeout -> duration or nil
852 *
853 * Get the internal timeout duration or nil if it was not set.
854 *
855 */
856VALUE
858{
859 rb_io_t *fptr = rb_io_get_fptr(self);
860
861 return fptr->timeout;
862}
863
864/*
865 * call-seq:
866 * timeout = duration -> duration
867 * timeout = nil -> nil
868 *
869 * Sets the internal timeout to the specified duration or nil. The timeout
870 * applies to all blocking operations where possible.
871 *
872 * When the operation performs longer than the timeout set, IO::TimeoutError
873 * is raised.
874 *
875 * This affects the following methods (but is not limited to): #gets, #puts,
876 * #read, #write, #wait_readable and #wait_writable. This also affects
877 * blocking socket operations like Socket#accept and Socket#connect.
878 *
879 * Some operations like File#open and IO#close are not affected by the
880 * timeout. A timeout during a write operation may leave the IO in an
881 * inconsistent state, e.g. data was partially written. Generally speaking, a
882 * timeout is a last ditch effort to prevent an application from hanging on
883 * slow I/O operations, such as those that occur during a slowloris attack.
884 */
885VALUE
887{
888 // Validate it:
889 if (RTEST(timeout)) {
890 rb_time_interval(timeout);
891 }
892
893 rb_io_t *fptr = rb_io_get_fptr(self);
894
895 fptr->timeout = timeout;
896
897 return self;
898}
899
900/*
901 * call-seq:
902 * IO.try_convert(object) -> new_io or nil
903 *
904 * Attempts to convert +object+ into an \IO object via method +to_io+;
905 * returns the new \IO object if successful, or +nil+ otherwise:
906 *
907 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
908 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
909 * IO.try_convert('STDOUT') # => nil
910 *
911 */
912static VALUE
913rb_io_s_try_convert(VALUE dummy, VALUE io)
914{
915 return rb_io_check_io(io);
916}
917
918#if !RUBY_CRLF_ENVIRONMENT
919static void
920io_unread(rb_io_t *fptr, bool discard_rbuf)
921{
922 rb_off_t r;
923 rb_io_check_closed(fptr);
924 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
925 return;
926 /* xxx: target position may be negative if buffer is filled by ungetc */
927 errno = 0;
928 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
929 if (r < 0 && errno) {
930 if (errno == ESPIPE)
931 fptr->mode |= FMODE_DUPLEX;
932 if (!discard_rbuf) return;
933 }
934 fptr->rbuf.off = 0;
935 fptr->rbuf.len = 0;
936 clear_codeconv(fptr);
937 return;
938}
939#endif
940
941static rb_encoding *io_input_encoding(rb_io_t *fptr);
942
943static void
944io_ungetbyte(VALUE str, rb_io_t *fptr)
945{
946 long len = RSTRING_LEN(str);
947
948 if (fptr->rbuf.ptr == NULL) {
949 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
950 fptr->rbuf.off = 0;
951 fptr->rbuf.len = 0;
952#if SIZEOF_LONG > SIZEOF_INT
953 if (len > INT_MAX)
954 rb_raise(rb_eIOError, "ungetbyte failed");
955#endif
956 if (len > min_capa)
957 fptr->rbuf.capa = (int)len;
958 else
959 fptr->rbuf.capa = min_capa;
960 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
961 }
962 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
963 rb_raise(rb_eIOError, "ungetbyte failed");
964 }
965 if (fptr->rbuf.off < len) {
966 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
967 fptr->rbuf.ptr+fptr->rbuf.off,
968 char, fptr->rbuf.len);
969 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
970 }
971 fptr->rbuf.off-=(int)len;
972 fptr->rbuf.len+=(int)len;
973 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
974}
975
976static rb_io_t *
977flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
978{
979 if (io_fflush(fptr) < 0)
980 rb_sys_fail_on_write(fptr);
981 io_unread(fptr, discard_rbuf);
982 errno = 0;
983 return fptr;
984}
985
986#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
987#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
988
989#ifndef SEEK_CUR
990# define SEEK_SET 0
991# define SEEK_CUR 1
992# define SEEK_END 2
993#endif
994
995void
997{
998 rb_io_check_closed(fptr);
999 if (!(fptr->mode & FMODE_READABLE)) {
1000 rb_raise(rb_eIOError, "not opened for reading");
1001 }
1002 if (fptr->wbuf.len) {
1003 if (io_fflush(fptr) < 0)
1004 rb_sys_fail_on_write(fptr);
1005 }
1006 if (fptr->tied_io_for_writing) {
1007 rb_io_t *wfptr;
1008 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1009 if (io_fflush(wfptr) < 0)
1010 rb_sys_fail_on_write(wfptr);
1011 }
1012}
1013
1014void
1016{
1018 if (READ_CHAR_PENDING(fptr)) {
1019 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1020 }
1021}
1022
1023void
1028
1029static rb_encoding*
1030io_read_encoding(rb_io_t *fptr)
1031{
1032 if (fptr->encs.enc) {
1033 return fptr->encs.enc;
1034 }
1035 return rb_default_external_encoding();
1036}
1037
1038static rb_encoding*
1039io_input_encoding(rb_io_t *fptr)
1040{
1041 if (fptr->encs.enc2) {
1042 return fptr->encs.enc2;
1043 }
1044 return io_read_encoding(fptr);
1045}
1046
1047void
1049{
1050 rb_io_check_closed(fptr);
1051 if (!(fptr->mode & FMODE_WRITABLE)) {
1052 rb_raise(rb_eIOError, "not opened for writing");
1053 }
1054 if (fptr->rbuf.len) {
1055 io_unread(fptr, true);
1056 }
1057}
1058
1059int
1060rb_io_read_pending(rb_io_t *fptr)
1061{
1062 /* This function is used for bytes and chars. Confusing. */
1063 if (READ_CHAR_PENDING(fptr))
1064 return 1; /* should raise? */
1065 return READ_DATA_PENDING(fptr);
1066}
1067
1068void
1070{
1071 if (!READ_DATA_PENDING(fptr)) {
1072 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1073 }
1074 return;
1075}
1076
1077int
1078rb_gc_for_fd(int err)
1079{
1080 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1081 rb_gc();
1082 return 1;
1083 }
1084 return 0;
1085}
1086
1087/* try `expr` upto twice while it returns false and `errno`
1088 * is to GC. Each `errno`s are available as `first_errno` and
1089 * `retried_errno` respectively */
1090#define TRY_WITH_GC(expr) \
1091 for (int first_errno, retried_errno = 0, retried = 0; \
1092 (!retried && \
1093 !(expr) && \
1094 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1095 (retried_errno = errno, 1)); \
1096 (void)retried_errno, retried = 1)
1097
1098static int
1099ruby_dup(int orig)
1100{
1101 int fd = -1;
1102
1103 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1104 rb_syserr_fail(first_errno, 0);
1105 }
1106 rb_update_max_fd(fd);
1107 return fd;
1108}
1109
1110static VALUE
1111io_alloc(VALUE klass)
1112{
1113 NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
1114
1115 io->fptr = 0;
1116
1117 return (VALUE)io;
1118}
1119
1120#ifndef S_ISREG
1121# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1122#endif
1123
1125 VALUE th;
1126 rb_io_t *fptr;
1127 int nonblock;
1128 int fd;
1129
1130 void *buf;
1131 size_t capa;
1132 struct timeval *timeout;
1133};
1134
1136 VALUE th;
1137 rb_io_t *fptr;
1138 int nonblock;
1139 int fd;
1140
1141 const void *buf;
1142 size_t capa;
1143 struct timeval *timeout;
1144};
1145
1146#ifdef HAVE_WRITEV
1147struct io_internal_writev_struct {
1148 VALUE th;
1149 rb_io_t *fptr;
1150 int nonblock;
1151 int fd;
1152
1153 int iovcnt;
1154 const struct iovec *iov;
1155 struct timeval *timeout;
1156};
1157#endif
1158
1159static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1160
1166static inline int
1167io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1168{
1169 if (!timeout && rb_thread_mn_schedulable(thread)) {
1170 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1171 return -1;
1172 }
1173
1174 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1175
1176 if (ready > 0) {
1177 return ready;
1178 }
1179 else if (ready == 0) {
1180 errno = ETIMEDOUT;
1181 return -1;
1182 }
1183
1184 // If there was an error BEFORE we started waiting, return it:
1185 if (error) {
1186 errno = error;
1187 return -1;
1188 }
1189 else {
1190 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1191 return ready;
1192 }
1193}
1194
1195static VALUE
1196internal_read_func(void *ptr)
1197{
1198 struct io_internal_read_struct *iis = ptr;
1199 ssize_t result;
1200
1201 if (iis->timeout && !iis->nonblock) {
1202 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1203 return -1;
1204 }
1205 }
1206
1207 retry:
1208 result = read(iis->fd, iis->buf, iis->capa);
1209
1210 if (result < 0 && !iis->nonblock) {
1211 if (io_again_p(errno)) {
1212 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1213 return -1;
1214 }
1215 else {
1216 goto retry;
1217 }
1218 }
1219 }
1220
1221 return result;
1222}
1223
1224#if defined __APPLE__
1225# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1226#else
1227# define do_write_retry(code) result = code
1228#endif
1229
1230static VALUE
1231internal_write_func(void *ptr)
1232{
1233 struct io_internal_write_struct *iis = ptr;
1234 ssize_t result;
1235
1236 if (iis->timeout && !iis->nonblock) {
1237 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1238 return -1;
1239 }
1240 }
1241
1242 retry:
1243 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1244
1245 if (result < 0 && !iis->nonblock) {
1246 int e = errno;
1247 if (io_again_p(e)) {
1248 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1249 return -1;
1250 }
1251 else {
1252 goto retry;
1253 }
1254 }
1255 }
1256
1257 return result;
1258}
1259
1260#ifdef HAVE_WRITEV
1261static VALUE
1262internal_writev_func(void *ptr)
1263{
1264 struct io_internal_writev_struct *iis = ptr;
1265 ssize_t result;
1266
1267 if (iis->timeout && !iis->nonblock) {
1268 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1269 return -1;
1270 }
1271 }
1272
1273 retry:
1274 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1275
1276 if (result < 0 && !iis->nonblock) {
1277 if (io_again_p(errno)) {
1278 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1279 return -1;
1280 }
1281 else {
1282 goto retry;
1283 }
1284 }
1285 }
1286
1287 return result;
1288}
1289#endif
1290
1291static ssize_t
1292rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1293{
1294 VALUE scheduler = rb_fiber_scheduler_current();
1295 if (scheduler != Qnil) {
1296 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1297
1298 if (!UNDEF_P(result)) {
1300 }
1301 }
1302
1303 struct io_internal_read_struct iis = {
1304 .th = rb_thread_current(),
1305 .fptr = fptr,
1306 .nonblock = 0,
1307 .fd = fptr->fd,
1308
1309 .buf = buf,
1310 .capa = count,
1311 .timeout = NULL,
1312 };
1313
1314 struct timeval timeout_storage;
1315
1316 if (fptr->timeout != Qnil) {
1317 timeout_storage = rb_time_interval(fptr->timeout);
1318 iis.timeout = &timeout_storage;
1319 }
1320
1321 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1322}
1323
1324static ssize_t
1325rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1326{
1327 VALUE scheduler = rb_fiber_scheduler_current();
1328 if (scheduler != Qnil) {
1329 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1330
1331 if (!UNDEF_P(result)) {
1333 }
1334 }
1335
1336 struct io_internal_write_struct iis = {
1337 .th = rb_thread_current(),
1338 .fptr = fptr,
1339 .nonblock = 0,
1340 .fd = fptr->fd,
1341
1342 .buf = buf,
1343 .capa = count,
1344 .timeout = NULL
1345 };
1346
1347 struct timeval timeout_storage;
1348
1349 if (fptr->timeout != Qnil) {
1350 timeout_storage = rb_time_interval(fptr->timeout);
1351 iis.timeout = &timeout_storage;
1352 }
1353
1354 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1355}
1356
1357#ifdef HAVE_WRITEV
1358static ssize_t
1359rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1360{
1361 if (!iovcnt) return 0;
1362
1363 VALUE scheduler = rb_fiber_scheduler_current();
1364 if (scheduler != Qnil) {
1365 // This path assumes at least one `iov`:
1366 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1367
1368 if (!UNDEF_P(result)) {
1370 }
1371 }
1372
1373 struct io_internal_writev_struct iis = {
1374 .th = rb_thread_current(),
1375 .fptr = fptr,
1376 .nonblock = 0,
1377 .fd = fptr->fd,
1378
1379 .iov = iov,
1380 .iovcnt = iovcnt,
1381 .timeout = NULL
1382 };
1383
1384 struct timeval timeout_storage;
1385
1386 if (fptr->timeout != Qnil) {
1387 timeout_storage = rb_time_interval(fptr->timeout);
1388 iis.timeout = &timeout_storage;
1389 }
1390
1391 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1392}
1393#endif
1394
1395static VALUE
1396io_flush_buffer_sync(void *arg)
1397{
1398 rb_io_t *fptr = arg;
1399 long l = fptr->wbuf.len;
1400 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1401
1402 if (fptr->wbuf.len <= r) {
1403 fptr->wbuf.off = 0;
1404 fptr->wbuf.len = 0;
1405 return 0;
1406 }
1407
1408 if (0 <= r) {
1409 fptr->wbuf.off += (int)r;
1410 fptr->wbuf.len -= (int)r;
1411 errno = EAGAIN;
1412 }
1413
1414 return (VALUE)-1;
1415}
1416
1417static VALUE
1418io_flush_buffer_async(VALUE arg)
1419{
1420 rb_io_t *fptr = (rb_io_t *)arg;
1421 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1422}
1423
1424static inline int
1425io_flush_buffer(rb_io_t *fptr)
1426{
1427 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1428 return (int)io_flush_buffer_async((VALUE)fptr);
1429 }
1430 else {
1431 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1432 }
1433}
1434
1435static int
1436io_fflush(rb_io_t *fptr)
1437{
1438 rb_io_check_closed(fptr);
1439
1440 if (fptr->wbuf.len == 0)
1441 return 0;
1442
1443 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1444 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1445 return -1;
1446
1447 rb_io_check_closed(fptr);
1448 }
1449
1450 return 0;
1451}
1452
1453VALUE
1454rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1455{
1456 VALUE scheduler = rb_fiber_scheduler_current();
1457
1458 if (scheduler != Qnil) {
1459 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1460 }
1461
1462 rb_io_t * fptr = NULL;
1463 RB_IO_POINTER(io, fptr);
1464
1465 struct timeval tv_storage;
1466 struct timeval *tv = NULL;
1467
1468 if (NIL_OR_UNDEF_P(timeout)) {
1469 timeout = fptr->timeout;
1470 }
1471
1472 if (timeout != Qnil) {
1473 tv_storage = rb_time_interval(timeout);
1474 tv = &tv_storage;
1475 }
1476
1477 int ready = rb_thread_io_wait(fptr, RB_NUM2INT(events), tv);
1478
1479 if (ready < 0) {
1480 rb_sys_fail(0);
1481 }
1482
1483 // Not sure if this is necessary:
1484 rb_io_check_closed(fptr);
1485
1486 if (ready) {
1487 return RB_INT2NUM(ready);
1488 }
1489 else {
1490 return Qfalse;
1491 }
1492}
1493
1494static VALUE
1495io_from_fd(int fd)
1496{
1497 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1498}
1499
1500static int
1501io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1502{
1503 VALUE scheduler = rb_fiber_scheduler_current();
1504
1505 if (scheduler != Qnil) {
1506 return RTEST(
1507 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1508 );
1509 }
1510
1511 return rb_thread_wait_for_single_fd(fd, events, timeout);
1512}
1513
1514int
1516{
1517 io_fd_check_closed(f);
1518
1519 VALUE scheduler = rb_fiber_scheduler_current();
1520
1521 switch (errno) {
1522 case EINTR:
1523#if defined(ERESTART)
1524 case ERESTART:
1525#endif
1527 return TRUE;
1528
1529 case EAGAIN:
1530#if EWOULDBLOCK != EAGAIN
1531 case EWOULDBLOCK:
1532#endif
1533 if (scheduler != Qnil) {
1534 return RTEST(
1535 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1536 );
1537 }
1538 else {
1539 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1540 }
1541 return TRUE;
1542
1543 default:
1544 return FALSE;
1545 }
1546}
1547
1548int
1550{
1551 io_fd_check_closed(f);
1552
1553 VALUE scheduler = rb_fiber_scheduler_current();
1554
1555 switch (errno) {
1556 case EINTR:
1557#if defined(ERESTART)
1558 case ERESTART:
1559#endif
1560 /*
1561 * In old Linux, several special files under /proc and /sys don't handle
1562 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1563 * Otherwise, we face nasty hang up. Sigh.
1564 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1565 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1566 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1567 * Then rb_thread_check_ints() is enough.
1568 */
1570 return TRUE;
1571
1572 case EAGAIN:
1573#if EWOULDBLOCK != EAGAIN
1574 case EWOULDBLOCK:
1575#endif
1576 if (scheduler != Qnil) {
1577 return RTEST(
1578 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1579 );
1580 }
1581 else {
1582 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1583 }
1584 return TRUE;
1585
1586 default:
1587 return FALSE;
1588 }
1589}
1590
1591int
1592rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1593{
1594 return io_wait_for_single_fd(fd, events, timeout);
1595}
1596
1597int
1599{
1600 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1601}
1602
1603int
1605{
1606 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1607}
1608
1609VALUE
1610rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1611{
1612 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1613 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1614 // instead relies on `read(-1) -> -1` which causes this code path. We then
1615 // check here whether the IO was in fact closed. Probably it's better to
1616 // check that `fptr->fd != -1` before using it in syscall.
1617 rb_io_check_closed(RFILE(io)->fptr);
1618
1619 switch (error) {
1620 // In old Linux, several special files under /proc and /sys don't handle
1621 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1622 // Otherwise, we face nasty hang up. Sigh.
1623 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1624 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1625 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1626 // Then rb_thread_check_ints() is enough.
1627 case EINTR:
1628#if defined(ERESTART)
1629 case ERESTART:
1630#endif
1631 // We might have pending interrupts since the previous syscall was interrupted:
1633
1634 // The operation was interrupted, so retry it immediately:
1635 return events;
1636
1637 case EAGAIN:
1638#if EWOULDBLOCK != EAGAIN
1639 case EWOULDBLOCK:
1640#endif
1641 // The operation would block, so wait for the specified events:
1642 return rb_io_wait(io, events, timeout);
1643
1644 default:
1645 // Non-specific error, no event is ready:
1646 return Qnil;
1647 }
1648}
1649
1650int
1652{
1653 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1654
1655 if (RTEST(result)) {
1656 return RB_NUM2INT(result);
1657 }
1658 else if (result == RUBY_Qfalse) {
1659 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1660 }
1661
1662 return 0;
1663}
1664
1665int
1667{
1668 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1669
1670 if (RTEST(result)) {
1671 return RB_NUM2INT(result);
1672 }
1673 else if (result == RUBY_Qfalse) {
1674 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1675 }
1676
1677 return 0;
1678}
1679
1680static void
1681make_writeconv(rb_io_t *fptr)
1682{
1683 if (!fptr->writeconv_initialized) {
1684 const char *senc, *denc;
1685 rb_encoding *enc;
1686 int ecflags;
1687 VALUE ecopts;
1688
1689 fptr->writeconv_initialized = 1;
1690
1691 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1692 ecopts = fptr->encs.ecopts;
1693
1694 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1695 /* no encoding conversion */
1696 fptr->writeconv_pre_ecflags = 0;
1697 fptr->writeconv_pre_ecopts = Qnil;
1698 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1699 if (!fptr->writeconv)
1700 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1702 }
1703 else {
1704 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1705 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1706 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1707 /* single conversion */
1708 fptr->writeconv_pre_ecflags = ecflags;
1709 fptr->writeconv_pre_ecopts = ecopts;
1710 fptr->writeconv = NULL;
1712 }
1713 else {
1714 /* double conversion */
1715 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1716 fptr->writeconv_pre_ecopts = ecopts;
1717 if (senc) {
1718 denc = rb_enc_name(enc);
1719 fptr->writeconv_asciicompat = rb_str_new2(senc);
1720 }
1721 else {
1722 senc = denc = "";
1723 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1724 }
1726 ecopts = fptr->encs.ecopts;
1727 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1728 if (!fptr->writeconv)
1729 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1730 }
1731 }
1732 }
1733}
1734
1735/* writing functions */
1737 rb_io_t *fptr;
1738 const char *ptr;
1739 long length;
1740};
1741
1743 VALUE io;
1744 VALUE str;
1745 int nosync;
1746};
1747
1748#ifdef HAVE_WRITEV
1749static ssize_t
1750io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1751{
1752 if (fptr->wbuf.len) {
1753 struct iovec iov[2];
1754
1755 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1756 iov[0].iov_len = fptr->wbuf.len;
1757 iov[1].iov_base = (void*)ptr;
1758 iov[1].iov_len = length;
1759
1760 ssize_t result = rb_writev_internal(fptr, iov, 2);
1761
1762 if (result < 0)
1763 return result;
1764
1765 if (result >= fptr->wbuf.len) {
1766 // We wrote more than the internal buffer:
1767 result -= fptr->wbuf.len;
1768 fptr->wbuf.off = 0;
1769 fptr->wbuf.len = 0;
1770 }
1771 else {
1772 // We only wrote less data than the internal buffer:
1773 fptr->wbuf.off += (int)result;
1774 fptr->wbuf.len -= (int)result;
1775
1776 result = 0;
1777 }
1778
1779 return result;
1780 }
1781 else {
1782 return rb_io_write_memory(fptr, ptr, length);
1783 }
1784}
1785#else
1786static ssize_t
1787io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1788{
1789 long remaining = length;
1790
1791 if (fptr->wbuf.len) {
1792 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1793 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1794 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1795 fptr->wbuf.off = 0;
1796 }
1797
1798 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1799 fptr->wbuf.len += (int)length;
1800
1801 // We copied the entire incoming data to the internal buffer:
1802 remaining = 0;
1803 }
1804
1805 // Flush the internal buffer:
1806 if (io_fflush(fptr) < 0) {
1807 return -1;
1808 }
1809
1810 // If all the data was buffered, we are done:
1811 if (remaining == 0) {
1812 return length;
1813 }
1814 }
1815
1816 // Otherwise, we should write the data directly:
1817 return rb_io_write_memory(fptr, ptr, length);
1818}
1819#endif
1820
1821static VALUE
1822io_binwrite_string(VALUE arg)
1823{
1824 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1825
1826 const char *ptr = p->ptr;
1827 size_t remaining = p->length;
1828
1829 while (remaining) {
1830 // Write as much as possible:
1831 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1832
1833 if (result == 0) {
1834 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1835 // should try again immediately.
1836 }
1837 else if (result > 0) {
1838 if ((size_t)result == remaining) break;
1839 ptr += result;
1840 remaining -= result;
1841 }
1842 // Wait for it to become writable:
1843 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1844 rb_io_check_closed(p->fptr);
1845 }
1846 else {
1847 // The error was unrelated to waiting for it to become writable, so we fail:
1848 return -1;
1849 }
1850 }
1851
1852 return p->length;
1853}
1854
1855inline static void
1856io_allocate_write_buffer(rb_io_t *fptr, int sync)
1857{
1858 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1859 fptr->wbuf.off = 0;
1860 fptr->wbuf.len = 0;
1861 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1862 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1863 }
1864
1865 if (NIL_P(fptr->write_lock)) {
1866 fptr->write_lock = rb_mutex_new();
1867 rb_mutex_allow_trap(fptr->write_lock, 1);
1868 }
1869}
1870
1871static inline int
1872io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1873{
1874 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1875 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1876 return 1;
1877
1878 // If the amount of data we want to write exceeds the internal buffer:
1879 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1880 return 1;
1881
1882 // Otherwise, we can append to the internal buffer:
1883 return 0;
1884}
1885
1886static long
1887io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1888{
1889 if (len <= 0) return len;
1890
1891 // Don't write anything if current thread has a pending interrupt:
1893
1894 io_allocate_write_buffer(fptr, !nosync);
1895
1896 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1897 struct binwrite_arg arg;
1898
1899 arg.fptr = fptr;
1900 arg.ptr = ptr;
1901 arg.length = len;
1902
1903 if (!NIL_P(fptr->write_lock)) {
1904 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1905 }
1906 else {
1907 return io_binwrite_string((VALUE)&arg);
1908 }
1909 }
1910 else {
1911 if (fptr->wbuf.off) {
1912 if (fptr->wbuf.len)
1913 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1914 fptr->wbuf.off = 0;
1915 }
1916
1917 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1918 fptr->wbuf.len += (int)len;
1919
1920 return len;
1921 }
1922}
1923
1924# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1925 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1926
1927#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1928 MODE_BTMODE(d, e, f) : \
1929 MODE_BTMODE(a, b, c))
1930
1931static VALUE
1932do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1933{
1934 if (NEED_WRITECONV(fptr)) {
1935 VALUE common_encoding = Qnil;
1936 SET_BINARY_MODE(fptr);
1937
1938 make_writeconv(fptr);
1939
1940 if (fptr->writeconv) {
1941#define fmode (fptr->mode)
1942 if (!NIL_P(fptr->writeconv_asciicompat))
1943 common_encoding = fptr->writeconv_asciicompat;
1944 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1945 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1946 rb_enc_name(rb_enc_get(str)));
1947 }
1948#undef fmode
1949 }
1950 else {
1951 if (fptr->encs.enc2)
1952 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1953 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1954 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1955 }
1956
1957 if (!NIL_P(common_encoding)) {
1958 str = rb_str_encode(str, common_encoding,
1960 *converted = 1;
1961 }
1962
1963 if (fptr->writeconv) {
1965 *converted = 1;
1966 }
1967 }
1968#if RUBY_CRLF_ENVIRONMENT
1969#define fmode (fptr->mode)
1970 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1971 if ((fptr->mode & FMODE_READABLE) &&
1973 setmode(fptr->fd, O_BINARY);
1974 }
1975 else {
1976 setmode(fptr->fd, O_TEXT);
1977 }
1978 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1979 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1980 rb_enc_name(rb_enc_get(str)));
1981 }
1982 }
1983#undef fmode
1984#endif
1985 return str;
1986}
1987
1988static long
1989io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1990{
1991 int converted = 0;
1992 VALUE tmp;
1993 long n, len;
1994 const char *ptr;
1995
1996#ifdef _WIN32
1997 if (fptr->mode & FMODE_TTY) {
1998 long len = rb_w32_write_console(str, fptr->fd);
1999 if (len > 0) return len;
2000 }
2001#endif
2002
2003 str = do_writeconv(str, fptr, &converted);
2004 if (converted)
2005 OBJ_FREEZE(str);
2006
2007 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2008 RSTRING_GETMEM(tmp, ptr, len);
2009 n = io_binwrite(ptr, len, fptr, nosync);
2010 rb_str_tmp_frozen_release(str, tmp);
2011
2012 return n;
2013}
2014
2015ssize_t
2016rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2017{
2018 rb_io_t *fptr;
2019
2020 GetOpenFile(io, fptr);
2022 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2023}
2024
2025static VALUE
2026io_write(VALUE io, VALUE str, int nosync)
2027{
2028 rb_io_t *fptr;
2029 long n;
2030 VALUE tmp;
2031
2032 io = GetWriteIO(io);
2033 str = rb_obj_as_string(str);
2034 tmp = rb_io_check_io(io);
2035
2036 if (NIL_P(tmp)) {
2037 /* port is not IO, call write method for it. */
2038 return rb_funcall(io, id_write, 1, str);
2039 }
2040
2041 io = tmp;
2042 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2043
2044 GetOpenFile(io, fptr);
2046
2047 n = io_fwrite(str, fptr, nosync);
2048 if (n < 0L) rb_sys_fail_on_write(fptr);
2049
2050 return LONG2FIX(n);
2051}
2052
2053#ifdef HAVE_WRITEV
2054struct binwritev_arg {
2055 rb_io_t *fptr;
2056 struct iovec *iov;
2057 int iovcnt;
2058 size_t total;
2059};
2060
2061static VALUE
2062io_binwritev_internal(VALUE arg)
2063{
2064 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2065
2066 size_t remaining = p->total;
2067 size_t offset = 0;
2068
2069 rb_io_t *fptr = p->fptr;
2070 struct iovec *iov = p->iov;
2071 int iovcnt = p->iovcnt;
2072
2073 while (remaining) {
2074 long result = rb_writev_internal(fptr, iov, iovcnt);
2075
2076 if (result >= 0) {
2077 offset += result;
2078 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2079 if (offset < (size_t)fptr->wbuf.len) {
2080 fptr->wbuf.off += result;
2081 fptr->wbuf.len -= result;
2082 }
2083 else {
2084 offset -= (size_t)fptr->wbuf.len;
2085 fptr->wbuf.off = 0;
2086 fptr->wbuf.len = 0;
2087 }
2088 }
2089
2090 if (offset == p->total) {
2091 return p->total;
2092 }
2093
2094 while (result >= (ssize_t)iov->iov_len) {
2095 /* iovcnt > 0 */
2096 result -= iov->iov_len;
2097 iov->iov_len = 0;
2098 iov++;
2099
2100 if (!--iovcnt) {
2101 // I don't believe this code path can ever occur.
2102 return offset;
2103 }
2104 }
2105
2106 iov->iov_base = (char *)iov->iov_base + result;
2107 iov->iov_len -= result;
2108 }
2109 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2110 rb_io_check_closed(fptr);
2111 }
2112 else {
2113 return -1;
2114 }
2115 }
2116
2117 return offset;
2118}
2119
2120static long
2121io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2122{
2123 // Don't write anything if current thread has a pending interrupt:
2125
2126 if (iovcnt == 0) return 0;
2127
2128 size_t total = 0;
2129 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2130
2131 io_allocate_write_buffer(fptr, 1);
2132
2133 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2134 // The end of the buffered data:
2135 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2136
2137 if (offset + total <= (size_t)fptr->wbuf.capa) {
2138 for (int i = 1; i < iovcnt; i++) {
2139 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2140 offset += iov[i].iov_len;
2141 }
2142
2143 fptr->wbuf.len += total;
2144
2145 return total;
2146 }
2147 else {
2148 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2149 iov[0].iov_len = fptr->wbuf.len;
2150 }
2151 }
2152 else {
2153 // The first iov is reserved for the internal buffer, and it's empty.
2154 iov++;
2155
2156 if (!--iovcnt) {
2157 // If there are no other io vectors we are done.
2158 return 0;
2159 }
2160 }
2161
2162 struct binwritev_arg arg;
2163 arg.fptr = fptr;
2164 arg.iov = iov;
2165 arg.iovcnt = iovcnt;
2166 arg.total = total;
2167
2168 if (!NIL_P(fptr->write_lock)) {
2169 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2170 }
2171 else {
2172 return io_binwritev_internal((VALUE)&arg);
2173 }
2174}
2175
2176static long
2177io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2178{
2179 int i, converted, iovcnt = argc + 1;
2180 long n;
2181 VALUE v1, v2, str, tmp, *tmp_array;
2182 struct iovec *iov;
2183
2184 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2185 tmp_array = ALLOCV_N(VALUE, v2, argc);
2186
2187 for (i = 0; i < argc; i++) {
2188 str = rb_obj_as_string(argv[i]);
2189 converted = 0;
2190 str = do_writeconv(str, fptr, &converted);
2191
2192 if (converted)
2193 OBJ_FREEZE(str);
2194
2195 tmp = rb_str_tmp_frozen_acquire(str);
2196 tmp_array[i] = tmp;
2197
2198 /* iov[0] is reserved for buffer of fptr */
2199 iov[i+1].iov_base = RSTRING_PTR(tmp);
2200 iov[i+1].iov_len = RSTRING_LEN(tmp);
2201 }
2202
2203 n = io_binwritev(iov, iovcnt, fptr);
2204 if (v1) ALLOCV_END(v1);
2205
2206 for (i = 0; i < argc; i++) {
2207 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2208 }
2209
2210 if (v2) ALLOCV_END(v2);
2211
2212 return n;
2213}
2214
2215static int
2216iovcnt_ok(int iovcnt)
2217{
2218#ifdef IOV_MAX
2219 return iovcnt < IOV_MAX;
2220#else /* GNU/Hurd has writev, but no IOV_MAX */
2221 return 1;
2222#endif
2223}
2224#endif /* HAVE_WRITEV */
2225
2226static VALUE
2227io_writev(int argc, const VALUE *argv, VALUE io)
2228{
2229 rb_io_t *fptr;
2230 long n;
2231 VALUE tmp, total = INT2FIX(0);
2232 int i, cnt = 1;
2233
2234 io = GetWriteIO(io);
2235 tmp = rb_io_check_io(io);
2236
2237 if (NIL_P(tmp)) {
2238 /* port is not IO, call write method for it. */
2239 return rb_funcallv(io, id_write, argc, argv);
2240 }
2241
2242 io = tmp;
2243
2244 GetOpenFile(io, fptr);
2246
2247 for (i = 0; i < argc; i += cnt) {
2248#ifdef HAVE_WRITEV
2249 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2250 n = io_fwritev(cnt, &argv[i], fptr);
2251 }
2252 else
2253#endif
2254 {
2255 cnt = 1;
2256 /* sync at last item */
2257 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2258 }
2259
2260 if (n < 0L)
2261 rb_sys_fail_on_write(fptr);
2262
2263 total = rb_fix_plus(LONG2FIX(n), total);
2264 }
2265
2266 return total;
2267}
2268
2269/*
2270 * call-seq:
2271 * write(*objects) -> integer
2272 *
2273 * Writes each of the given +objects+ to +self+,
2274 * which must be opened for writing
2275 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2276 * returns the total number bytes written;
2277 * each of +objects+ that is not a string is converted via method +to_s+:
2278 *
2279 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2280 * $stdout.write('foo', :bar, 2, "\n") # => 8
2281 *
2282 * Output:
2283 *
2284 * Hello, World!
2285 * foobar2
2286 *
2287 * Related: IO#read.
2288 */
2289
2290static VALUE
2291io_write_m(int argc, VALUE *argv, VALUE io)
2292{
2293 if (argc != 1) {
2294 return io_writev(argc, argv, io);
2295 }
2296 else {
2297 VALUE str = argv[0];
2298 return io_write(io, str, 0);
2299 }
2300}
2301
2302VALUE
2303rb_io_write(VALUE io, VALUE str)
2304{
2305 return rb_funcallv(io, id_write, 1, &str);
2306}
2307
2308static VALUE
2309rb_io_writev(VALUE io, int argc, const VALUE *argv)
2310{
2311 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2312 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2313 VALUE klass = CLASS_OF(io);
2314 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2316 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2317 " which accepts just one argument",
2318 klass, sep
2319 );
2320 }
2321
2322 do rb_io_write(io, *argv++); while (--argc);
2323
2324 return Qnil;
2325 }
2326
2327 return rb_funcallv(io, id_write, argc, argv);
2328}
2329
2330/*
2331 * call-seq:
2332 * self << object -> self
2333 *
2334 * Writes the given +object+ to +self+,
2335 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2336 * returns +self+;
2337 * if +object+ is not a string, it is converted via method +to_s+:
2338 *
2339 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2340 * $stdout << 'foo' << :bar << 2 << "\n"
2341 *
2342 * Output:
2343 *
2344 * Hello, World!
2345 * foobar2
2346 *
2347 */
2348
2349
2350VALUE
2352{
2353 rb_io_write(io, str);
2354 return io;
2355}
2356
2357#ifdef HAVE_FSYNC
2358static VALUE
2359nogvl_fsync(void *ptr)
2360{
2361 rb_io_t *fptr = ptr;
2362
2363#ifdef _WIN32
2364 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2365 return 0;
2366#endif
2367 return (VALUE)fsync(fptr->fd);
2368}
2369#endif
2370
2371VALUE
2372rb_io_flush_raw(VALUE io, int sync)
2373{
2374 rb_io_t *fptr;
2375
2376 if (!RB_TYPE_P(io, T_FILE)) {
2377 return rb_funcall(io, id_flush, 0);
2378 }
2379
2380 io = GetWriteIO(io);
2381 GetOpenFile(io, fptr);
2382
2383 if (fptr->mode & FMODE_WRITABLE) {
2384 if (io_fflush(fptr) < 0)
2385 rb_sys_fail_on_write(fptr);
2386 }
2387 if (fptr->mode & FMODE_READABLE) {
2388 io_unread(fptr, true);
2389 }
2390
2391 return io;
2392}
2393
2394/*
2395 * call-seq:
2396 * flush -> self
2397 *
2398 * Flushes data buffered in +self+ to the operating system
2399 * (but does not necessarily flush data buffered in the operating system):
2400 *
2401 * $stdout.print 'no newline' # Not necessarily flushed.
2402 * $stdout.flush # Flushed.
2403 *
2404 */
2405
2406VALUE
2407rb_io_flush(VALUE io)
2408{
2409 return rb_io_flush_raw(io, 1);
2410}
2411
2412/*
2413 * call-seq:
2414 * tell -> integer
2415 *
2416 * Returns the current position (in bytes) in +self+
2417 * (see {Position}[rdoc-ref:IO@Position]):
2418 *
2419 * f = File.open('t.txt')
2420 * f.tell # => 0
2421 * f.gets # => "First line\n"
2422 * f.tell # => 12
2423 * f.close
2424 *
2425 * Related: IO#pos=, IO#seek.
2426 */
2427
2428static VALUE
2429rb_io_tell(VALUE io)
2430{
2431 rb_io_t *fptr;
2432 rb_off_t pos;
2433
2434 GetOpenFile(io, fptr);
2435 pos = io_tell(fptr);
2436 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2437 pos -= fptr->rbuf.len;
2438 return OFFT2NUM(pos);
2439}
2440
2441static VALUE
2442rb_io_seek(VALUE io, VALUE offset, int whence)
2443{
2444 rb_io_t *fptr;
2445 rb_off_t pos;
2446
2447 pos = NUM2OFFT(offset);
2448 GetOpenFile(io, fptr);
2449 pos = io_seek(fptr, pos, whence);
2450 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2451
2452 return INT2FIX(0);
2453}
2454
2455static int
2456interpret_seek_whence(VALUE vwhence)
2457{
2458 if (vwhence == sym_SET)
2459 return SEEK_SET;
2460 if (vwhence == sym_CUR)
2461 return SEEK_CUR;
2462 if (vwhence == sym_END)
2463 return SEEK_END;
2464#ifdef SEEK_DATA
2465 if (vwhence == sym_DATA)
2466 return SEEK_DATA;
2467#endif
2468#ifdef SEEK_HOLE
2469 if (vwhence == sym_HOLE)
2470 return SEEK_HOLE;
2471#endif
2472 return NUM2INT(vwhence);
2473}
2474
2475/*
2476 * call-seq:
2477 * seek(offset, whence = IO::SEEK_SET) -> 0
2478 *
2479 * Seeks to the position given by integer +offset+
2480 * (see {Position}[rdoc-ref:IO@Position])
2481 * and constant +whence+, which is one of:
2482 *
2483 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2484 * Repositions the stream to its current position plus the given +offset+:
2485 *
2486 * f = File.open('t.txt')
2487 * f.tell # => 0
2488 * f.seek(20, :CUR) # => 0
2489 * f.tell # => 20
2490 * f.seek(-10, :CUR) # => 0
2491 * f.tell # => 10
2492 * f.close
2493 *
2494 * - +:END+ or <tt>IO::SEEK_END</tt>:
2495 * Repositions the stream to its end plus the given +offset+:
2496 *
2497 * f = File.open('t.txt')
2498 * f.tell # => 0
2499 * f.seek(0, :END) # => 0 # Repositions to stream end.
2500 * f.tell # => 52
2501 * f.seek(-20, :END) # => 0
2502 * f.tell # => 32
2503 * f.seek(-40, :END) # => 0
2504 * f.tell # => 12
2505 * f.close
2506 *
2507 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2508 * Repositions the stream to the given +offset+:
2509 *
2510 * f = File.open('t.txt')
2511 * f.tell # => 0
2512 * f.seek(20, :SET) # => 0
2513 * f.tell # => 20
2514 * f.seek(40, :SET) # => 0
2515 * f.tell # => 40
2516 * f.close
2517 *
2518 * Related: IO#pos=, IO#tell.
2519 *
2520 */
2521
2522static VALUE
2523rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2524{
2525 VALUE offset, ptrname;
2526 int whence = SEEK_SET;
2527
2528 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2529 whence = interpret_seek_whence(ptrname);
2530 }
2531
2532 return rb_io_seek(io, offset, whence);
2533}
2534
2535/*
2536 * call-seq:
2537 * pos = new_position -> new_position
2538 *
2539 * Seeks to the given +new_position+ (in bytes);
2540 * see {Position}[rdoc-ref:IO@Position]:
2541 *
2542 * f = File.open('t.txt')
2543 * f.tell # => 0
2544 * f.pos = 20 # => 20
2545 * f.tell # => 20
2546 * f.close
2547 *
2548 * Related: IO#seek, IO#tell.
2549 *
2550 */
2551
2552static VALUE
2553rb_io_set_pos(VALUE io, VALUE offset)
2554{
2555 rb_io_t *fptr;
2556 rb_off_t pos;
2557
2558 pos = NUM2OFFT(offset);
2559 GetOpenFile(io, fptr);
2560 pos = io_seek(fptr, pos, SEEK_SET);
2561 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2562
2563 return OFFT2NUM(pos);
2564}
2565
2566static void clear_readconv(rb_io_t *fptr);
2567
2568/*
2569 * call-seq:
2570 * rewind -> 0
2571 *
2572 * Repositions the stream to its beginning,
2573 * setting both the position and the line number to zero;
2574 * see {Position}[rdoc-ref:IO@Position]
2575 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2576 *
2577 * f = File.open('t.txt')
2578 * f.tell # => 0
2579 * f.lineno # => 0
2580 * f.gets # => "First line\n"
2581 * f.tell # => 12
2582 * f.lineno # => 1
2583 * f.rewind # => 0
2584 * f.tell # => 0
2585 * f.lineno # => 0
2586 * f.close
2587 *
2588 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2589 *
2590 */
2591
2592static VALUE
2593rb_io_rewind(VALUE io)
2594{
2595 rb_io_t *fptr;
2596
2597 GetOpenFile(io, fptr);
2598 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2599 if (io == ARGF.current_file) {
2600 ARGF.lineno -= fptr->lineno;
2601 }
2602 fptr->lineno = 0;
2603 if (fptr->readconv) {
2604 clear_readconv(fptr);
2605 }
2606
2607 return INT2FIX(0);
2608}
2609
2610static int
2611fptr_wait_readable(rb_io_t *fptr)
2612{
2613 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2614
2615 if (result)
2616 rb_io_check_closed(fptr);
2617
2618 return result;
2619}
2620
2621static int
2622io_fillbuf(rb_io_t *fptr)
2623{
2624 ssize_t r;
2625
2626 if (fptr->rbuf.ptr == NULL) {
2627 fptr->rbuf.off = 0;
2628 fptr->rbuf.len = 0;
2629 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2630 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2631#ifdef _WIN32
2632 fptr->rbuf.capa--;
2633#endif
2634 }
2635 if (fptr->rbuf.len == 0) {
2636 retry:
2637 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2638
2639 if (r < 0) {
2640 if (fptr_wait_readable(fptr))
2641 goto retry;
2642
2643 int e = errno;
2644 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2645 if (!NIL_P(fptr->pathv)) {
2646 rb_str_append(path, fptr->pathv);
2647 }
2648
2649 rb_syserr_fail_path(e, path);
2650 }
2651 if (r > 0) rb_io_check_closed(fptr);
2652 fptr->rbuf.off = 0;
2653 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2654 if (r == 0)
2655 return -1; /* EOF */
2656 }
2657 return 0;
2658}
2659
2660/*
2661 * call-seq:
2662 * eof -> true or false
2663 *
2664 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2665 * see {Position}[rdoc-ref:IO@Position]:
2666 *
2667 * f = File.open('t.txt')
2668 * f.eof # => false
2669 * f.seek(0, :END) # => 0
2670 * f.eof # => true
2671 * f.close
2672 *
2673 * Raises an exception unless the stream is opened for reading;
2674 * see {Mode}[rdoc-ref:File@Access+Modes].
2675 *
2676 * If +self+ is a stream such as pipe or socket, this method
2677 * blocks until the other end sends some data or closes it:
2678 *
2679 * r, w = IO.pipe
2680 * Thread.new { sleep 1; w.close }
2681 * r.eof? # => true # After 1-second wait.
2682 *
2683 * r, w = IO.pipe
2684 * Thread.new { sleep 1; w.puts "a" }
2685 * r.eof? # => false # After 1-second wait.
2686 *
2687 * r, w = IO.pipe
2688 * r.eof? # blocks forever
2689 *
2690 * Note that this method reads data to the input byte buffer. So
2691 * IO#sysread may not behave as you intend with IO#eof?, unless you
2692 * call IO#rewind first (which is not available for some streams).
2693 */
2694
2695VALUE
2697{
2698 rb_io_t *fptr;
2699
2700 GetOpenFile(io, fptr);
2702
2703 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2704 if (READ_DATA_PENDING(fptr)) return Qfalse;
2705 READ_CHECK(fptr);
2706#if RUBY_CRLF_ENVIRONMENT
2707 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2708 return RBOOL(eof(fptr->fd));
2709 }
2710#endif
2711 return RBOOL(io_fillbuf(fptr) < 0);
2712}
2713
2714/*
2715 * call-seq:
2716 * sync -> true or false
2717 *
2718 * Returns the current sync mode of the stream.
2719 * When sync mode is true, all output is immediately flushed to the underlying
2720 * operating system and is not buffered by Ruby internally. See also #fsync.
2721 *
2722 * f = File.open('t.tmp', 'w')
2723 * f.sync # => false
2724 * f.sync = true
2725 * f.sync # => true
2726 * f.close
2727 *
2728 */
2729
2730static VALUE
2731rb_io_sync(VALUE io)
2732{
2733 rb_io_t *fptr;
2734
2735 io = GetWriteIO(io);
2736 GetOpenFile(io, fptr);
2737 return RBOOL(fptr->mode & FMODE_SYNC);
2738}
2739
2740#ifdef HAVE_FSYNC
2741
2742/*
2743 * call-seq:
2744 * sync = boolean -> boolean
2745 *
2746 * Sets the _sync_ _mode_ for the stream to the given value;
2747 * returns the given value.
2748 *
2749 * Values for the sync mode:
2750 *
2751 * - +true+: All output is immediately flushed to the
2752 * underlying operating system and is not buffered internally.
2753 * - +false+: Output may be buffered internally.
2754 *
2755 * Example;
2756 *
2757 * f = File.open('t.tmp', 'w')
2758 * f.sync # => false
2759 * f.sync = true
2760 * f.sync # => true
2761 * f.close
2762 *
2763 * Related: IO#fsync.
2764 *
2765 */
2766
2767static VALUE
2768rb_io_set_sync(VALUE io, VALUE sync)
2769{
2770 rb_io_t *fptr;
2771
2772 io = GetWriteIO(io);
2773 GetOpenFile(io, fptr);
2774 if (RTEST(sync)) {
2775 fptr->mode |= FMODE_SYNC;
2776 }
2777 else {
2778 fptr->mode &= ~FMODE_SYNC;
2779 }
2780 return sync;
2781}
2782
2783/*
2784 * call-seq:
2785 * fsync -> 0
2786 *
2787 * Immediately writes to disk all data buffered in the stream,
2788 * via the operating system's <tt>fsync(2)</tt>.
2789
2790 * Note this difference:
2791 *
2792 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2793 * but does not guarantee that the operating system actually writes the data to disk.
2794 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2795 * and that data is written to disk.
2796 *
2797 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2798 *
2799 */
2800
2801static VALUE
2802rb_io_fsync(VALUE io)
2803{
2804 rb_io_t *fptr;
2805
2806 io = GetWriteIO(io);
2807 GetOpenFile(io, fptr);
2808
2809 if (io_fflush(fptr) < 0)
2810 rb_sys_fail_on_write(fptr);
2811
2812 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2813 rb_sys_fail_path(fptr->pathv);
2814
2815 return INT2FIX(0);
2816}
2817#else
2818# define rb_io_fsync rb_f_notimplement
2819# define rb_io_sync rb_f_notimplement
2820static VALUE
2821rb_io_set_sync(VALUE io, VALUE sync)
2822{
2825}
2826#endif
2827
2828#ifdef HAVE_FDATASYNC
2829static VALUE
2830nogvl_fdatasync(void *ptr)
2831{
2832 rb_io_t *fptr = ptr;
2833
2834#ifdef _WIN32
2835 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2836 return 0;
2837#endif
2838 return (VALUE)fdatasync(fptr->fd);
2839}
2840
2841/*
2842 * call-seq:
2843 * fdatasync -> 0
2844 *
2845 * Immediately writes to disk all data buffered in the stream,
2846 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2847 * otherwise via <tt>fsync(2)</tt>, if supported;
2848 * otherwise raises an exception.
2849 *
2850 */
2851
2852static VALUE
2853rb_io_fdatasync(VALUE io)
2854{
2855 rb_io_t *fptr;
2856
2857 io = GetWriteIO(io);
2858 GetOpenFile(io, fptr);
2859
2860 if (io_fflush(fptr) < 0)
2861 rb_sys_fail_on_write(fptr);
2862
2863 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2864 return INT2FIX(0);
2865
2866 /* fall back */
2867 return rb_io_fsync(io);
2868}
2869#else
2870#define rb_io_fdatasync rb_io_fsync
2871#endif
2872
2873/*
2874 * call-seq:
2875 * fileno -> integer
2876 *
2877 * Returns the integer file descriptor for the stream:
2878 *
2879 * $stdin.fileno # => 0
2880 * $stdout.fileno # => 1
2881 * $stderr.fileno # => 2
2882 * File.open('t.txt').fileno # => 10
2883 * f.close
2884 *
2885 */
2886
2887static VALUE
2888rb_io_fileno(VALUE io)
2889{
2890 rb_io_t *fptr = RFILE(io)->fptr;
2891 int fd;
2892
2893 rb_io_check_closed(fptr);
2894 fd = fptr->fd;
2895 return INT2FIX(fd);
2896}
2897
2898int
2900{
2901 if (RB_TYPE_P(io, T_FILE)) {
2902 rb_io_t *fptr = RFILE(io)->fptr;
2903 rb_io_check_closed(fptr);
2904 return fptr->fd;
2905 }
2906 else {
2907 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2908 if (!UNDEF_P(fileno)) {
2909 return RB_NUM2INT(fileno);
2910 }
2911 }
2912
2913 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2914
2916}
2917
2918int
2919rb_io_mode(VALUE io)
2920{
2921 rb_io_t *fptr;
2922 GetOpenFile(io, fptr);
2923 return fptr->mode;
2924}
2925
2926/*
2927 * call-seq:
2928 * pid -> integer or nil
2929 *
2930 * Returns the process ID of a child process associated with the stream,
2931 * which will have been set by IO#popen, or +nil+ if the stream was not
2932 * created by IO#popen:
2933 *
2934 * pipe = IO.popen("-")
2935 * if pipe
2936 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2937 * else
2938 * $stderr.puts "In child, pid is #{$$}"
2939 * end
2940 *
2941 * Output:
2942 *
2943 * In child, pid is 26209
2944 * In parent, child pid is 26209
2945 *
2946 */
2947
2948static VALUE
2949rb_io_pid(VALUE io)
2950{
2951 rb_io_t *fptr;
2952
2953 GetOpenFile(io, fptr);
2954 if (!fptr->pid)
2955 return Qnil;
2956 return PIDT2NUM(fptr->pid);
2957}
2958
2959/*
2960 * call-seq:
2961 * path -> string or nil
2962 *
2963 * Returns the path associated with the IO, or +nil+ if there is no path
2964 * associated with the IO. It is not guaranteed that the path exists on
2965 * the filesystem.
2966 *
2967 * $stdin.path # => "<STDIN>"
2968 *
2969 * File.open("testfile") {|f| f.path} # => "testfile"
2970 */
2971
2972VALUE
2974{
2975 rb_io_t *fptr = RFILE(io)->fptr;
2976
2977 if (!fptr)
2978 return Qnil;
2979
2980 return rb_obj_dup(fptr->pathv);
2981}
2982
2983/*
2984 * call-seq:
2985 * inspect -> string
2986 *
2987 * Returns a string representation of +self+:
2988 *
2989 * f = File.open('t.txt')
2990 * f.inspect # => "#<File:t.txt>"
2991 * f.close
2992 *
2993 */
2994
2995static VALUE
2996rb_io_inspect(VALUE obj)
2997{
2998 rb_io_t *fptr;
2999 VALUE result;
3000 static const char closed[] = " (closed)";
3001
3002 fptr = RFILE(obj)->fptr;
3003 if (!fptr) return rb_any_to_s(obj);
3004 result = rb_str_new_cstr("#<");
3005 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3006 rb_str_cat2(result, ":");
3007 if (NIL_P(fptr->pathv)) {
3008 if (fptr->fd < 0) {
3009 rb_str_cat(result, closed+1, strlen(closed)-1);
3010 }
3011 else {
3012 rb_str_catf(result, "fd %d", fptr->fd);
3013 }
3014 }
3015 else {
3016 rb_str_append(result, fptr->pathv);
3017 if (fptr->fd < 0) {
3018 rb_str_cat(result, closed, strlen(closed));
3019 }
3020 }
3021 return rb_str_cat2(result, ">");
3022}
3023
3024/*
3025 * call-seq:
3026 * to_io -> self
3027 *
3028 * Returns +self+.
3029 *
3030 */
3031
3032static VALUE
3033rb_io_to_io(VALUE io)
3034{
3035 return io;
3036}
3037
3038/* reading functions */
3039static long
3040read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3041{
3042 int n;
3043
3044 n = READ_DATA_PENDING_COUNT(fptr);
3045 if (n <= 0) return 0;
3046 if (n > len) n = (int)len;
3047 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3048 fptr->rbuf.off += n;
3049 fptr->rbuf.len -= n;
3050 return n;
3051}
3052
3053static long
3054io_bufread(char *ptr, long len, rb_io_t *fptr)
3055{
3056 long offset = 0;
3057 long n = len;
3058 long c;
3059
3060 if (READ_DATA_PENDING(fptr) == 0) {
3061 while (n > 0) {
3062 again:
3063 rb_io_check_closed(fptr);
3064 c = rb_io_read_memory(fptr, ptr+offset, n);
3065 if (c == 0) break;
3066 if (c < 0) {
3067 if (fptr_wait_readable(fptr))
3068 goto again;
3069 return -1;
3070 }
3071 offset += c;
3072 if ((n -= c) <= 0) break;
3073 }
3074 return len - n;
3075 }
3076
3077 while (n > 0) {
3078 c = read_buffered_data(ptr+offset, n, fptr);
3079 if (c > 0) {
3080 offset += c;
3081 if ((n -= c) <= 0) break;
3082 }
3083 rb_io_check_closed(fptr);
3084 if (io_fillbuf(fptr) < 0) {
3085 break;
3086 }
3087 }
3088 return len - n;
3089}
3090
3091static int io_setstrbuf(VALUE *str, long len);
3092
3094 char *str_ptr;
3095 long len;
3096 rb_io_t *fptr;
3097};
3098
3099static VALUE
3100bufread_call(VALUE arg)
3101{
3102 struct bufread_arg *p = (struct bufread_arg *)arg;
3103 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3104 return Qundef;
3105}
3106
3107static long
3108io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3109{
3110 long len;
3111 struct bufread_arg arg;
3112
3113 io_setstrbuf(&str, offset + size);
3114 arg.str_ptr = RSTRING_PTR(str) + offset;
3115 arg.len = size;
3116 arg.fptr = fptr;
3117 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3118 len = arg.len;
3119 if (len < 0) rb_sys_fail_path(fptr->pathv);
3120 return len;
3121}
3122
3123static long
3124remain_size(rb_io_t *fptr)
3125{
3126 struct stat st;
3127 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3128 rb_off_t pos;
3129
3130 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3131#if defined(__HAIKU__)
3132 && (st.st_dev > 3)
3133#endif
3134 )
3135 {
3136 if (io_fflush(fptr) < 0)
3137 rb_sys_fail_on_write(fptr);
3138 pos = lseek(fptr->fd, 0, SEEK_CUR);
3139 if (st.st_size >= pos && pos >= 0) {
3140 siz += st.st_size - pos;
3141 if (siz > LONG_MAX) {
3142 rb_raise(rb_eIOError, "file too big for single read");
3143 }
3144 }
3145 }
3146 else {
3147 siz += BUFSIZ;
3148 }
3149 return (long)siz;
3150}
3151
3152static VALUE
3153io_enc_str(VALUE str, rb_io_t *fptr)
3154{
3155 rb_enc_associate(str, io_read_encoding(fptr));
3156 return str;
3157}
3158
3159static rb_encoding *io_read_encoding(rb_io_t *fptr);
3160
3161static void
3162make_readconv(rb_io_t *fptr, int size)
3163{
3164 if (!fptr->readconv) {
3165 int ecflags;
3166 VALUE ecopts;
3167 const char *sname, *dname;
3168 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3169 ecopts = fptr->encs.ecopts;
3170 if (fptr->encs.enc2) {
3171 sname = rb_enc_name(fptr->encs.enc2);
3172 dname = rb_enc_name(io_read_encoding(fptr));
3173 }
3174 else {
3175 sname = dname = "";
3176 }
3177 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3178 if (!fptr->readconv)
3179 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3180 fptr->cbuf.off = 0;
3181 fptr->cbuf.len = 0;
3182 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3183 fptr->cbuf.capa = size;
3184 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3185 }
3186}
3187
3188#define MORE_CHAR_SUSPENDED Qtrue
3189#define MORE_CHAR_FINISHED Qnil
3190static VALUE
3191fill_cbuf(rb_io_t *fptr, int ec_flags)
3192{
3193 const unsigned char *ss, *sp, *se;
3194 unsigned char *ds, *dp, *de;
3196 int putbackable;
3197 int cbuf_len0;
3198 VALUE exc;
3199
3200 ec_flags |= ECONV_PARTIAL_INPUT;
3201
3202 if (fptr->cbuf.len == fptr->cbuf.capa)
3203 return MORE_CHAR_SUSPENDED; /* cbuf full */
3204 if (fptr->cbuf.len == 0)
3205 fptr->cbuf.off = 0;
3206 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3207 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3208 fptr->cbuf.off = 0;
3209 }
3210
3211 cbuf_len0 = fptr->cbuf.len;
3212
3213 while (1) {
3214 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3215 se = sp + fptr->rbuf.len;
3216 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3217 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3218 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3219 fptr->rbuf.off += (int)(sp - ss);
3220 fptr->rbuf.len -= (int)(sp - ss);
3221 fptr->cbuf.len += (int)(dp - ds);
3222
3223 putbackable = rb_econv_putbackable(fptr->readconv);
3224 if (putbackable) {
3225 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3226 fptr->rbuf.off -= putbackable;
3227 fptr->rbuf.len += putbackable;
3228 }
3229
3230 exc = rb_econv_make_exception(fptr->readconv);
3231 if (!NIL_P(exc))
3232 return exc;
3233
3234 if (cbuf_len0 != fptr->cbuf.len)
3235 return MORE_CHAR_SUSPENDED;
3236
3237 if (res == econv_finished) {
3238 return MORE_CHAR_FINISHED;
3239 }
3240
3241 if (res == econv_source_buffer_empty) {
3242 if (fptr->rbuf.len == 0) {
3243 READ_CHECK(fptr);
3244 if (io_fillbuf(fptr) < 0) {
3245 if (!fptr->readconv) {
3246 return MORE_CHAR_FINISHED;
3247 }
3248 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3249 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3250 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3251 fptr->cbuf.len += (int)(dp - ds);
3253 break;
3254 }
3255 }
3256 }
3257 }
3258 if (cbuf_len0 != fptr->cbuf.len)
3259 return MORE_CHAR_SUSPENDED;
3260
3261 return MORE_CHAR_FINISHED;
3262}
3263
3264static VALUE
3265more_char(rb_io_t *fptr)
3266{
3267 VALUE v;
3268 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3269 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3270 rb_exc_raise(v);
3271 return v;
3272}
3273
3274static VALUE
3275io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3276{
3277 VALUE str = Qnil;
3278 if (strp) {
3279 str = *strp;
3280 if (NIL_P(str)) {
3281 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3282 }
3283 else {
3284 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3285 }
3286 rb_enc_associate(str, fptr->encs.enc);
3287 }
3288 fptr->cbuf.off += len;
3289 fptr->cbuf.len -= len;
3290 /* xxx: set coderange */
3291 if (fptr->cbuf.len == 0)
3292 fptr->cbuf.off = 0;
3293 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3294 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3295 fptr->cbuf.off = 0;
3296 }
3297 return str;
3298}
3299
3300static int
3301io_setstrbuf(VALUE *str, long len)
3302{
3303#ifdef _WIN32
3304 if (len > 0)
3305 len = (len + 1) & ~1L; /* round up for wide char */
3306#endif
3307 if (NIL_P(*str)) {
3308 *str = rb_str_new(0, len);
3309 return TRUE;
3310 }
3311 else {
3312 VALUE s = StringValue(*str);
3313 rb_str_modify(s);
3314
3315 long clen = RSTRING_LEN(s);
3316 if (clen >= len) {
3317 return FALSE;
3318 }
3319 len -= clen;
3320 }
3321 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3323 }
3324 return FALSE;
3325}
3326
3327#define MAX_REALLOC_GAP 4096
3328static void
3329io_shrink_read_string(VALUE str, long n)
3330{
3331 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3332 rb_str_resize(str, n);
3333 }
3334}
3335
3336static void
3337io_set_read_length(VALUE str, long n, int shrinkable)
3338{
3339 if (RSTRING_LEN(str) != n) {
3340 rb_str_modify(str);
3341 rb_str_set_len(str, n);
3342 if (shrinkable) io_shrink_read_string(str, n);
3343 }
3344}
3345
3346static VALUE
3347read_all(rb_io_t *fptr, long siz, VALUE str)
3348{
3349 long bytes;
3350 long n;
3351 long pos;
3352 rb_encoding *enc;
3353 int cr;
3354 int shrinkable;
3355
3356 if (NEED_READCONV(fptr)) {
3357 int first = !NIL_P(str);
3358 SET_BINARY_MODE(fptr);
3359 shrinkable = io_setstrbuf(&str,0);
3360 make_readconv(fptr, 0);
3361 while (1) {
3362 VALUE v;
3363 if (fptr->cbuf.len) {
3364 if (first) rb_str_set_len(str, first = 0);
3365 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3366 }
3367 v = fill_cbuf(fptr, 0);
3368 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3369 if (fptr->cbuf.len) {
3370 if (first) rb_str_set_len(str, first = 0);
3371 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3372 }
3373 rb_exc_raise(v);
3374 }
3375 if (v == MORE_CHAR_FINISHED) {
3376 clear_readconv(fptr);
3377 if (first) rb_str_set_len(str, first = 0);
3378 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3379 return io_enc_str(str, fptr);
3380 }
3381 }
3382 }
3383
3384 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3385 bytes = 0;
3386 pos = 0;
3387
3388 enc = io_read_encoding(fptr);
3389 cr = 0;
3390
3391 if (siz == 0) siz = BUFSIZ;
3392 shrinkable = io_setstrbuf(&str, siz);
3393 for (;;) {
3394 READ_CHECK(fptr);
3395 n = io_fread(str, bytes, siz - bytes, fptr);
3396 if (n == 0 && bytes == 0) {
3397 rb_str_set_len(str, 0);
3398 break;
3399 }
3400 bytes += n;
3401 rb_str_set_len(str, bytes);
3402 if (cr != ENC_CODERANGE_BROKEN)
3403 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3404 if (bytes < siz) break;
3405 siz += BUFSIZ;
3406
3407 size_t capa = rb_str_capacity(str);
3408 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3409 if (capa < BUFSIZ) {
3410 capa = BUFSIZ;
3411 }
3412 else if (capa > IO_MAX_BUFFER_GROWTH) {
3413 capa = IO_MAX_BUFFER_GROWTH;
3414 }
3416 }
3417 }
3418 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3419 str = io_enc_str(str, fptr);
3420 ENC_CODERANGE_SET(str, cr);
3421 return str;
3422}
3423
3424void
3426{
3427 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3428 rb_sys_fail_path(fptr->pathv);
3429 }
3430}
3431
3432static VALUE
3433io_read_memory_call(VALUE arg)
3434{
3435 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3436
3437 VALUE scheduler = rb_fiber_scheduler_current();
3438 if (scheduler != Qnil) {
3439 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3440
3441 if (!UNDEF_P(result)) {
3442 // This is actually returned as a pseudo-VALUE and later cast to a long:
3444 }
3445 }
3446
3447 if (iis->nonblock) {
3448 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3449 }
3450 else {
3451 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3452 }
3453}
3454
3455static long
3456io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3457{
3458 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3459}
3460
3461#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3462
3463static VALUE
3464io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3465{
3466 rb_io_t *fptr;
3467 VALUE length, str;
3468 long n, len;
3469 struct io_internal_read_struct iis;
3470 int shrinkable;
3471
3472 rb_scan_args(argc, argv, "11", &length, &str);
3473
3474 if ((len = NUM2LONG(length)) < 0) {
3475 rb_raise(rb_eArgError, "negative length %ld given", len);
3476 }
3477
3478 shrinkable = io_setstrbuf(&str, len);
3479
3480 GetOpenFile(io, fptr);
3482
3483 if (len == 0) {
3484 io_set_read_length(str, 0, shrinkable);
3485 return str;
3486 }
3487
3488 if (!nonblock)
3489 READ_CHECK(fptr);
3490 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3491 if (n <= 0) {
3492 again:
3493 if (nonblock) {
3494 rb_io_set_nonblock(fptr);
3495 }
3496 io_setstrbuf(&str, len);
3497 iis.th = rb_thread_current();
3498 iis.fptr = fptr;
3499 iis.nonblock = nonblock;
3500 iis.fd = fptr->fd;
3501 iis.buf = RSTRING_PTR(str);
3502 iis.capa = len;
3503 iis.timeout = NULL;
3504 n = io_read_memory_locktmp(str, &iis);
3505 if (n < 0) {
3506 int e = errno;
3507 if (!nonblock && fptr_wait_readable(fptr))
3508 goto again;
3509 if (nonblock && (io_again_p(e))) {
3510 if (no_exception)
3511 return sym_wait_readable;
3512 else
3513 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3514 e, "read would block");
3515 }
3516 rb_syserr_fail_path(e, fptr->pathv);
3517 }
3518 }
3519 io_set_read_length(str, n, shrinkable);
3520
3521 if (n == 0)
3522 return Qnil;
3523 else
3524 return str;
3525}
3526
3527/*
3528 * call-seq:
3529 * readpartial(maxlen) -> string
3530 * readpartial(maxlen, out_string) -> out_string
3531 *
3532 * Reads up to +maxlen+ bytes from the stream;
3533 * returns a string (either a new string or the given +out_string+).
3534 * Its encoding is:
3535 *
3536 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3537 * - ASCII-8BIT, otherwise.
3538 *
3539 * - Contains +maxlen+ bytes from the stream, if available.
3540 * - Otherwise contains all available bytes, if any available.
3541 * - Otherwise is an empty string.
3542 *
3543 * With the single non-negative integer argument +maxlen+ given,
3544 * returns a new string:
3545 *
3546 * f = File.new('t.txt')
3547 * f.readpartial(20) # => "First line\nSecond l"
3548 * f.readpartial(20) # => "ine\n\nFourth line\n"
3549 * f.readpartial(20) # => "Fifth line\n"
3550 * f.readpartial(20) # Raises EOFError.
3551 * f.close
3552 *
3553 * With both argument +maxlen+ and string argument +out_string+ given,
3554 * returns modified +out_string+:
3555 *
3556 * f = File.new('t.txt')
3557 * s = 'foo'
3558 * f.readpartial(20, s) # => "First line\nSecond l"
3559 * s = 'bar'
3560 * f.readpartial(0, s) # => ""
3561 * f.close
3562 *
3563 * This method is useful for a stream such as a pipe, a socket, or a tty.
3564 * It blocks only when no data is immediately available.
3565 * This means that it blocks only when _all_ of the following are true:
3566 *
3567 * - The byte buffer in the stream is empty.
3568 * - The content of the stream is empty.
3569 * - The stream is not at EOF.
3570 *
3571 * When blocked, the method waits for either more data or EOF on the stream:
3572 *
3573 * - If more data is read, the method returns the data.
3574 * - If EOF is reached, the method raises EOFError.
3575 *
3576 * When not blocked, the method responds immediately:
3577 *
3578 * - Returns data from the buffer if there is any.
3579 * - Otherwise returns data from the stream if there is any.
3580 * - Otherwise raises EOFError if the stream has reached EOF.
3581 *
3582 * Note that this method is similar to sysread. The differences are:
3583 *
3584 * - If the byte buffer is not empty, read from the byte buffer
3585 * instead of "sysread for buffered IO (IOError)".
3586 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3587 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3588 * readpartial retries the system call.
3589 *
3590 * The latter means that readpartial is non-blocking-flag insensitive.
3591 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3592 * if the fd is blocking mode.
3593 *
3594 * Examples:
3595 *
3596 * # # Returned Buffer Content Pipe Content
3597 * r, w = IO.pipe #
3598 * w << 'abc' # "" "abc".
3599 * r.readpartial(4096) # => "abc" "" ""
3600 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3601 *
3602 * # # Returned Buffer Content Pipe Content
3603 * r, w = IO.pipe #
3604 * w << 'abc' # "" "abc"
3605 * w.close # "" "abc" EOF
3606 * r.readpartial(4096) # => "abc" "" EOF
3607 * r.readpartial(4096) # raises EOFError
3608 *
3609 * # # Returned Buffer Content Pipe Content
3610 * r, w = IO.pipe #
3611 * w << "abc\ndef\n" # "" "abc\ndef\n"
3612 * r.gets # => "abc\n" "def\n" ""
3613 * w << "ghi\n" # "def\n" "ghi\n"
3614 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3615 * r.readpartial(4096) # => "ghi\n" "" ""
3616 *
3617 */
3618
3619static VALUE
3620io_readpartial(int argc, VALUE *argv, VALUE io)
3621{
3622 VALUE ret;
3623
3624 ret = io_getpartial(argc, argv, io, Qnil, 0);
3625 if (NIL_P(ret))
3626 rb_eof_error();
3627 return ret;
3628}
3629
3630static VALUE
3631io_nonblock_eof(int no_exception)
3632{
3633 if (!no_exception) {
3634 rb_eof_error();
3635 }
3636 return Qnil;
3637}
3638
3639/* :nodoc: */
3640static VALUE
3641io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3642{
3643 rb_io_t *fptr;
3644 long n, len;
3645 struct io_internal_read_struct iis;
3646 int shrinkable;
3647
3648 if ((len = NUM2LONG(length)) < 0) {
3649 rb_raise(rb_eArgError, "negative length %ld given", len);
3650 }
3651
3652 shrinkable = io_setstrbuf(&str, len);
3653 rb_bool_expected(ex, "exception", TRUE);
3654
3655 GetOpenFile(io, fptr);
3657
3658 if (len == 0) {
3659 io_set_read_length(str, 0, shrinkable);
3660 return str;
3661 }
3662
3663 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3664 if (n <= 0) {
3665 rb_fd_set_nonblock(fptr->fd);
3666 shrinkable |= io_setstrbuf(&str, len);
3667 iis.fptr = fptr;
3668 iis.nonblock = 1;
3669 iis.fd = fptr->fd;
3670 iis.buf = RSTRING_PTR(str);
3671 iis.capa = len;
3672 iis.timeout = NULL;
3673 n = io_read_memory_locktmp(str, &iis);
3674 if (n < 0) {
3675 int e = errno;
3676 if (io_again_p(e)) {
3677 if (!ex) return sym_wait_readable;
3678 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3679 e, "read would block");
3680 }
3681 rb_syserr_fail_path(e, fptr->pathv);
3682 }
3683 }
3684 io_set_read_length(str, n, shrinkable);
3685
3686 if (n == 0) {
3687 if (!ex) return Qnil;
3688 rb_eof_error();
3689 }
3690
3691 return str;
3692}
3693
3694/* :nodoc: */
3695static VALUE
3696io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3697{
3698 rb_io_t *fptr;
3699 long n;
3700
3701 if (!RB_TYPE_P(str, T_STRING))
3702 str = rb_obj_as_string(str);
3703 rb_bool_expected(ex, "exception", TRUE);
3704
3705 io = GetWriteIO(io);
3706 GetOpenFile(io, fptr);
3708
3709 if (io_fflush(fptr) < 0)
3710 rb_sys_fail_on_write(fptr);
3711
3712 rb_fd_set_nonblock(fptr->fd);
3713 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3714 RB_GC_GUARD(str);
3715
3716 if (n < 0) {
3717 int e = errno;
3718 if (io_again_p(e)) {
3719 if (!ex) {
3720 return sym_wait_writable;
3721 }
3722 else {
3723 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3724 }
3725 }
3726 rb_syserr_fail_path(e, fptr->pathv);
3727 }
3728
3729 return LONG2FIX(n);
3730}
3731
3732/*
3733 * call-seq:
3734 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3735 *
3736 * Reads bytes from the stream; the stream must be opened for reading
3737 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3738 *
3739 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3740 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3741 *
3742 * Returns a string (either a new string or the given +out_string+)
3743 * containing the bytes read.
3744 * The encoding of the string depends on both +maxLen+ and +out_string+:
3745 *
3746 * - +maxlen+ is +nil+: uses internal encoding of +self+
3747 * (regardless of whether +out_string+ was given).
3748 * - +maxlen+ not +nil+:
3749 *
3750 * - +out_string+ given: encoding of +out_string+ not modified.
3751 * - +out_string+ not given: ASCII-8BIT is used.
3752 *
3753 * <b>Without Argument +out_string+</b>
3754 *
3755 * When argument +out_string+ is omitted,
3756 * the returned value is a new string:
3757 *
3758 * f = File.new('t.txt')
3759 * f.read
3760 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3761 * f.rewind
3762 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3763 * f.read(30) # => "rth line\r\nFifth line\r\n"
3764 * f.read(30) # => nil
3765 * f.close
3766 *
3767 * If +maxlen+ is zero, returns an empty string.
3768 *
3769 * <b> With Argument +out_string+</b>
3770 *
3771 * When argument +out_string+ is given,
3772 * the returned value is +out_string+, whose content is replaced:
3773 *
3774 * f = File.new('t.txt')
3775 * s = 'foo' # => "foo"
3776 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3777 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3778 * f.rewind
3779 * s = 'bar'
3780 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3781 * s # => "First line\r\nSecond line\r\n\r\nFou"
3782 * s = 'baz'
3783 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3784 * s # => "rth line\r\nFifth line\r\n"
3785 * s = 'bat'
3786 * f.read(30, s) # => nil
3787 * s # => ""
3788 * f.close
3789 *
3790 * Note that this method behaves like the fread() function in C.
3791 * This means it retries to invoke read(2) system calls to read data
3792 * with the specified maxlen (or until EOF).
3793 *
3794 * This behavior is preserved even if the stream is in non-blocking mode.
3795 * (This method is non-blocking-flag insensitive as other methods.)
3796 *
3797 * If you need the behavior like a single read(2) system call,
3798 * consider #readpartial, #read_nonblock, and #sysread.
3799 *
3800 * Related: IO#write.
3801 */
3802
3803static VALUE
3804io_read(int argc, VALUE *argv, VALUE io)
3805{
3806 rb_io_t *fptr;
3807 long n, len;
3808 VALUE length, str;
3809 int shrinkable;
3810#if RUBY_CRLF_ENVIRONMENT
3811 int previous_mode;
3812#endif
3813
3814 rb_scan_args(argc, argv, "02", &length, &str);
3815
3816 if (NIL_P(length)) {
3817 GetOpenFile(io, fptr);
3819 return read_all(fptr, remain_size(fptr), str);
3820 }
3821 len = NUM2LONG(length);
3822 if (len < 0) {
3823 rb_raise(rb_eArgError, "negative length %ld given", len);
3824 }
3825
3826 shrinkable = io_setstrbuf(&str,len);
3827
3828 GetOpenFile(io, fptr);
3830 if (len == 0) {
3831 io_set_read_length(str, 0, shrinkable);
3832 return str;
3833 }
3834
3835 READ_CHECK(fptr);
3836#if RUBY_CRLF_ENVIRONMENT
3837 previous_mode = set_binary_mode_with_seek_cur(fptr);
3838#endif
3839 n = io_fread(str, 0, len, fptr);
3840 io_set_read_length(str, n, shrinkable);
3841#if RUBY_CRLF_ENVIRONMENT
3842 if (previous_mode == O_TEXT) {
3843 setmode(fptr->fd, O_TEXT);
3844 }
3845#endif
3846 if (n == 0) return Qnil;
3847
3848 return str;
3849}
3850
3851static void
3852rscheck(const char *rsptr, long rslen, VALUE rs)
3853{
3854 if (!rs) return;
3855 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3856 rb_raise(rb_eRuntimeError, "rs modified");
3857}
3858
3859static const char *
3860search_delim(const char *p, long len, int delim, rb_encoding *enc)
3861{
3862 if (rb_enc_mbminlen(enc) == 1) {
3863 p = memchr(p, delim, len);
3864 if (p) return p + 1;
3865 }
3866 else {
3867 const char *end = p + len;
3868 while (p < end) {
3869 int r = rb_enc_precise_mbclen(p, end, enc);
3870 if (!MBCLEN_CHARFOUND_P(r)) {
3871 p += rb_enc_mbminlen(enc);
3872 continue;
3873 }
3874 int n = MBCLEN_CHARFOUND_LEN(r);
3875 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3876 return p + n;
3877 }
3878 p += n;
3879 }
3880 }
3881 return NULL;
3882}
3883
3884static int
3885appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3886{
3887 VALUE str = *strp;
3888 long limit = *lp;
3889
3890 if (NEED_READCONV(fptr)) {
3891 SET_BINARY_MODE(fptr);
3892 make_readconv(fptr, 0);
3893 do {
3894 const char *p, *e;
3895 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3896 if (searchlen) {
3897 p = READ_CHAR_PENDING_PTR(fptr);
3898 if (0 < limit && limit < searchlen)
3899 searchlen = (int)limit;
3900 e = search_delim(p, searchlen, delim, enc);
3901 if (e) {
3902 int len = (int)(e-p);
3903 if (NIL_P(str))
3904 *strp = str = rb_str_new(p, len);
3905 else
3906 rb_str_buf_cat(str, p, len);
3907 fptr->cbuf.off += len;
3908 fptr->cbuf.len -= len;
3909 limit -= len;
3910 *lp = limit;
3911 return delim;
3912 }
3913
3914 if (NIL_P(str))
3915 *strp = str = rb_str_new(p, searchlen);
3916 else
3917 rb_str_buf_cat(str, p, searchlen);
3918 fptr->cbuf.off += searchlen;
3919 fptr->cbuf.len -= searchlen;
3920 limit -= searchlen;
3921
3922 if (limit == 0) {
3923 *lp = limit;
3924 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3925 }
3926 }
3927 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3928 clear_readconv(fptr);
3929 *lp = limit;
3930 return EOF;
3931 }
3932
3933 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3934 do {
3935 long pending = READ_DATA_PENDING_COUNT(fptr);
3936 if (pending > 0) {
3937 const char *p = READ_DATA_PENDING_PTR(fptr);
3938 const char *e;
3939 long last;
3940
3941 if (limit > 0 && pending > limit) pending = limit;
3942 e = search_delim(p, pending, delim, enc);
3943 if (e) pending = e - p;
3944 if (!NIL_P(str)) {
3945 last = RSTRING_LEN(str);
3946 rb_str_resize(str, last + pending);
3947 }
3948 else {
3949 last = 0;
3950 *strp = str = rb_str_buf_new(pending);
3951 rb_str_set_len(str, pending);
3952 }
3953 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3954 limit -= pending;
3955 *lp = limit;
3956 if (e) return delim;
3957 if (limit == 0)
3958 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3959 }
3960 READ_CHECK(fptr);
3961 } while (io_fillbuf(fptr) >= 0);
3962 *lp = limit;
3963 return EOF;
3964}
3965
3966static inline int
3967swallow(rb_io_t *fptr, int term)
3968{
3969 if (NEED_READCONV(fptr)) {
3970 rb_encoding *enc = io_read_encoding(fptr);
3971 int needconv = rb_enc_mbminlen(enc) != 1;
3972 SET_BINARY_MODE(fptr);
3973 make_readconv(fptr, 0);
3974 do {
3975 size_t cnt;
3976 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3977 const char *p = READ_CHAR_PENDING_PTR(fptr);
3978 int i;
3979 if (!needconv) {
3980 if (*p != term) return TRUE;
3981 i = (int)cnt;
3982 while (--i && *++p == term);
3983 }
3984 else {
3985 const char *e = p + cnt;
3986 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3987 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3988 i = (int)(e - p);
3989 }
3990 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3991 }
3992 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3993 return FALSE;
3994 }
3995
3996 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3997 do {
3998 size_t cnt;
3999 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4000 char buf[1024];
4001 const char *p = READ_DATA_PENDING_PTR(fptr);
4002 int i;
4003 if (cnt > sizeof buf) cnt = sizeof buf;
4004 if (*p != term) return TRUE;
4005 i = (int)cnt;
4006 while (--i && *++p == term);
4007 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4008 rb_sys_fail_path(fptr->pathv);
4009 }
4010 READ_CHECK(fptr);
4011 } while (io_fillbuf(fptr) == 0);
4012 return FALSE;
4013}
4014
4015static VALUE
4016rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4017{
4018 VALUE str = Qnil;
4019 int len = 0;
4020 long pos = 0;
4021 int cr = 0;
4022
4023 do {
4024 int pending = READ_DATA_PENDING_COUNT(fptr);
4025
4026 if (pending > 0) {
4027 const char *p = READ_DATA_PENDING_PTR(fptr);
4028 const char *e;
4029 int chomplen = 0;
4030
4031 e = memchr(p, '\n', pending);
4032 if (e) {
4033 pending = (int)(e - p + 1);
4034 if (chomp) {
4035 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4036 }
4037 }
4038 if (NIL_P(str)) {
4039 str = rb_str_new(p, pending - chomplen);
4040 fptr->rbuf.off += pending;
4041 fptr->rbuf.len -= pending;
4042 }
4043 else {
4044 rb_str_resize(str, len + pending - chomplen);
4045 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4046 fptr->rbuf.off += chomplen;
4047 fptr->rbuf.len -= chomplen;
4048 if (pending == 1 && chomplen == 1 && len > 0) {
4049 if (RSTRING_PTR(str)[len-1] == '\r') {
4050 rb_str_resize(str, --len);
4051 break;
4052 }
4053 }
4054 }
4055 len += pending - chomplen;
4056 if (cr != ENC_CODERANGE_BROKEN)
4057 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4058 if (e) break;
4059 }
4060 READ_CHECK(fptr);
4061 } while (io_fillbuf(fptr) >= 0);
4062 if (NIL_P(str)) return Qnil;
4063
4064 str = io_enc_str(str, fptr);
4065 ENC_CODERANGE_SET(str, cr);
4066 fptr->lineno++;
4067
4068 return str;
4069}
4070
4072 VALUE io;
4073 VALUE rs;
4074 long limit;
4075 unsigned int chomp: 1;
4076};
4077
4078static void
4079extract_getline_opts(VALUE opts, struct getline_arg *args)
4080{
4081 int chomp = FALSE;
4082 if (!NIL_P(opts)) {
4083 static ID kwds[1];
4084 VALUE vchomp;
4085 if (!kwds[0]) {
4086 kwds[0] = rb_intern_const("chomp");
4087 }
4088 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4089 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4090 }
4091 args->chomp = chomp;
4092}
4093
4094static void
4095extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4096{
4097 VALUE rs = rb_rs, lim = Qnil;
4098
4099 if (argc == 1) {
4100 VALUE tmp = Qnil;
4101
4102 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4103 rs = tmp;
4104 }
4105 else {
4106 lim = argv[0];
4107 }
4108 }
4109 else if (2 <= argc) {
4110 rs = argv[0], lim = argv[1];
4111 if (!NIL_P(rs))
4112 StringValue(rs);
4113 }
4114 args->rs = rs;
4115 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4116}
4117
4118static void
4119check_getline_args(VALUE *rsp, long *limit, VALUE io)
4120{
4121 rb_io_t *fptr;
4122 VALUE rs = *rsp;
4123
4124 if (!NIL_P(rs)) {
4125 rb_encoding *enc_rs, *enc_io;
4126
4127 GetOpenFile(io, fptr);
4128 enc_rs = rb_enc_get(rs);
4129 enc_io = io_read_encoding(fptr);
4130 if (enc_io != enc_rs &&
4131 (!is_ascii_string(rs) ||
4132 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4133 if (rs == rb_default_rs) {
4134 rs = rb_enc_str_new(0, 0, enc_io);
4135 rb_str_buf_cat_ascii(rs, "\n");
4136 *rsp = rs;
4137 }
4138 else {
4139 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4140 rb_enc_name(enc_io),
4141 rb_enc_name(enc_rs));
4142 }
4143 }
4144 }
4145}
4146
4147static void
4148prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4149{
4150 VALUE opts;
4151 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4152 extract_getline_args(argc, argv, args);
4153 extract_getline_opts(opts, args);
4154 check_getline_args(&args->rs, &args->limit, io);
4155}
4156
4157static VALUE
4158rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4159{
4160 VALUE str = Qnil;
4161 int nolimit = 0;
4162 rb_encoding *enc;
4163
4165 if (NIL_P(rs) && limit < 0) {
4166 str = read_all(fptr, 0, Qnil);
4167 if (RSTRING_LEN(str) == 0) return Qnil;
4168 }
4169 else if (limit == 0) {
4170 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4171 }
4172 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4173 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4174 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4175 return rb_io_getline_fast(fptr, enc, chomp);
4176 }
4177 else {
4178 int c, newline = -1;
4179 const char *rsptr = 0;
4180 long rslen = 0;
4181 int rspara = 0;
4182 int extra_limit = 16;
4183 int chomp_cr = chomp;
4184
4185 SET_BINARY_MODE(fptr);
4186 enc = io_read_encoding(fptr);
4187
4188 if (!NIL_P(rs)) {
4189 rslen = RSTRING_LEN(rs);
4190 if (rslen == 0) {
4191 rsptr = "\n\n";
4192 rslen = 2;
4193 rspara = 1;
4194 swallow(fptr, '\n');
4195 rs = 0;
4196 if (!rb_enc_asciicompat(enc)) {
4197 rs = rb_usascii_str_new(rsptr, rslen);
4198 rs = rb_str_conv_enc(rs, 0, enc);
4199 OBJ_FREEZE(rs);
4200 rsptr = RSTRING_PTR(rs);
4201 rslen = RSTRING_LEN(rs);
4202 }
4203 newline = '\n';
4204 }
4205 else if (rb_enc_mbminlen(enc) == 1) {
4206 rsptr = RSTRING_PTR(rs);
4207 newline = (unsigned char)rsptr[rslen - 1];
4208 }
4209 else {
4210 rs = rb_str_conv_enc(rs, 0, enc);
4211 rsptr = RSTRING_PTR(rs);
4212 const char *e = rsptr + rslen;
4213 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4214 int n;
4215 newline = rb_enc_codepoint_len(last, e, &n, enc);
4216 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4217 }
4218 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4219 }
4220
4221 /* MS - Optimization */
4222 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4223 const char *s, *p, *pp, *e;
4224
4225 if (c == newline) {
4226 if (RSTRING_LEN(str) < rslen) continue;
4227 s = RSTRING_PTR(str);
4228 e = RSTRING_END(str);
4229 p = e - rslen;
4230 if (!at_char_boundary(s, p, e, enc)) continue;
4231 if (!rspara) rscheck(rsptr, rslen, rs);
4232 if (memcmp(p, rsptr, rslen) == 0) {
4233 if (chomp) {
4234 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4235 rb_str_set_len(str, p - s);
4236 }
4237 break;
4238 }
4239 }
4240 if (limit == 0) {
4241 s = RSTRING_PTR(str);
4242 p = RSTRING_END(str);
4243 pp = rb_enc_prev_char(s, p, p, enc);
4244 if (extra_limit && pp &&
4245 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4246 /* relax the limit while incomplete character.
4247 * extra_limit limits the relax length */
4248 limit = 1;
4249 extra_limit--;
4250 }
4251 else {
4252 nolimit = 1;
4253 break;
4254 }
4255 }
4256 }
4257
4258 if (rspara && c != EOF)
4259 swallow(fptr, '\n');
4260 if (!NIL_P(str))
4261 str = io_enc_str(str, fptr);
4262 }
4263
4264 if (!NIL_P(str) && !nolimit) {
4265 fptr->lineno++;
4266 }
4267
4268 return str;
4269}
4270
4271static VALUE
4272rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4273{
4274 rb_io_t *fptr;
4275 int old_lineno, new_lineno;
4276 VALUE str;
4277
4278 GetOpenFile(io, fptr);
4279 old_lineno = fptr->lineno;
4280 str = rb_io_getline_0(rs, limit, chomp, fptr);
4281 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4282 if (io == ARGF.current_file) {
4283 ARGF.lineno += new_lineno - old_lineno;
4284 ARGF.last_lineno = ARGF.lineno;
4285 }
4286 else {
4287 ARGF.last_lineno = new_lineno;
4288 }
4289 }
4290
4291 return str;
4292}
4293
4294static VALUE
4295rb_io_getline(int argc, VALUE *argv, VALUE io)
4296{
4297 struct getline_arg args;
4298
4299 prepare_getline_args(argc, argv, &args, io);
4300 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4301}
4302
4303VALUE
4305{
4306 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4307}
4308
4309VALUE
4310rb_io_gets_internal(VALUE io)
4311{
4312 rb_io_t *fptr;
4313 GetOpenFile(io, fptr);
4314 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4315}
4316
4317/*
4318 * call-seq:
4319 * gets(sep = $/, chomp: false) -> string or nil
4320 * gets(limit, chomp: false) -> string or nil
4321 * gets(sep, limit, chomp: false) -> string or nil
4322 *
4323 * Reads and returns a line from the stream;
4324 * assigns the return value to <tt>$_</tt>.
4325 * See {Line IO}[rdoc-ref:IO@Line+IO].
4326 *
4327 * With no arguments given, returns the next line
4328 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4329 *
4330 * f = File.open('t.txt')
4331 * f.gets # => "First line\n"
4332 * $_ # => "First line\n"
4333 * f.gets # => "\n"
4334 * f.gets # => "Fourth line\n"
4335 * f.gets # => "Fifth line\n"
4336 * f.gets # => nil
4337 * f.close
4338 *
4339 * With only string argument +sep+ given,
4340 * returns the next line as determined by line separator +sep+,
4341 * or +nil+ if none;
4342 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4343 *
4344 * f = File.new('t.txt')
4345 * f.gets('l') # => "First l"
4346 * f.gets('li') # => "ine\nSecond li"
4347 * f.gets('lin') # => "ne\n\nFourth lin"
4348 * f.gets # => "e\n"
4349 * f.close
4350 *
4351 * The two special values for +sep+ are honored:
4352 *
4353 * f = File.new('t.txt')
4354 * # Get all.
4355 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4356 * f.rewind
4357 * # Get paragraph (up to two line separators).
4358 * f.gets('') # => "First line\nSecond line\n\n"
4359 * f.close
4360 *
4361 * With only integer argument +limit+ given,
4362 * limits the number of bytes in the line;
4363 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4364 *
4365 * # No more than one line.
4366 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4367 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4368 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4369 *
4370 * With arguments +sep+ and +limit+ given,
4371 * combines the two behaviors
4372 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4373 *
4374 * Optional keyword argument +chomp+ specifies whether line separators
4375 * are to be omitted:
4376 *
4377 * f = File.open('t.txt')
4378 * # Chomp the lines.
4379 * f.gets(chomp: true) # => "First line"
4380 * f.gets(chomp: true) # => "Second line"
4381 * f.gets(chomp: true) # => ""
4382 * f.gets(chomp: true) # => "Fourth line"
4383 * f.gets(chomp: true) # => "Fifth line"
4384 * f.gets(chomp: true) # => nil
4385 * f.close
4386 *
4387 */
4388
4389static VALUE
4390rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4391{
4392 VALUE str;
4393
4394 str = rb_io_getline(argc, argv, io);
4395 rb_lastline_set(str);
4396
4397 return str;
4398}
4399
4400/*
4401 * call-seq:
4402 * lineno -> integer
4403 *
4404 * Returns the current line number for the stream;
4405 * see {Line Number}[rdoc-ref:IO@Line+Number].
4406 *
4407 */
4408
4409static VALUE
4410rb_io_lineno(VALUE io)
4411{
4412 rb_io_t *fptr;
4413
4414 GetOpenFile(io, fptr);
4416 return INT2NUM(fptr->lineno);
4417}
4418
4419/*
4420 * call-seq:
4421 * lineno = integer -> integer
4422 *
4423 * Sets and returns the line number for the stream;
4424 * see {Line Number}[rdoc-ref:IO@Line+Number].
4425 *
4426 */
4427
4428static VALUE
4429rb_io_set_lineno(VALUE io, VALUE lineno)
4430{
4431 rb_io_t *fptr;
4432
4433 GetOpenFile(io, fptr);
4435 fptr->lineno = NUM2INT(lineno);
4436 return lineno;
4437}
4438
4439/* :nodoc: */
4440static VALUE
4441io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4442{
4443 long limit = -1;
4444 if (NIL_P(lim)) {
4445 VALUE tmp = Qnil;
4446 // If sep is specified, but it's not a string and not nil, then assume
4447 // it's the limit (it should be an integer)
4448 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4449 // If the user has specified a non-nil / non-string value
4450 // for the separator, we assume it's the limit and set the
4451 // separator to default: rb_rs.
4452 lim = sep;
4453 limit = NUM2LONG(lim);
4454 sep = rb_rs;
4455 }
4456 else {
4457 sep = tmp;
4458 }
4459 }
4460 else {
4461 if (!NIL_P(sep)) StringValue(sep);
4462 limit = NUM2LONG(lim);
4463 }
4464
4465 check_getline_args(&sep, &limit, io);
4466
4467 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4468 rb_lastline_set_up(line, 1);
4469
4470 if (NIL_P(line)) {
4471 rb_eof_error();
4472 }
4473 return line;
4474}
4475
4476static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4477
4478/*
4479 * call-seq:
4480 * readlines(sep = $/, chomp: false) -> array
4481 * readlines(limit, chomp: false) -> array
4482 * readlines(sep, limit, chomp: false) -> array
4483 *
4484 * Reads and returns all remaining line from the stream;
4485 * does not modify <tt>$_</tt>.
4486 * See {Line IO}[rdoc-ref:IO@Line+IO].
4487 *
4488 * With no arguments given, returns lines
4489 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4490 *
4491 * f = File.new('t.txt')
4492 * f.readlines
4493 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4494 * f.readlines # => []
4495 * f.close
4496 *
4497 * With only string argument +sep+ given,
4498 * returns lines as determined by line separator +sep+,
4499 * or +nil+ if none;
4500 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4501 *
4502 * f = File.new('t.txt')
4503 * f.readlines('li')
4504 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4505 * f.close
4506 *
4507 * The two special values for +sep+ are honored:
4508 *
4509 * f = File.new('t.txt')
4510 * # Get all into one string.
4511 * f.readlines(nil)
4512 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4513 * # Get paragraphs (up to two line separators).
4514 * f.rewind
4515 * f.readlines('')
4516 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4517 * f.close
4518 *
4519 * With only integer argument +limit+ given,
4520 * limits the number of bytes in each line;
4521 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4522 *
4523 * f = File.new('t.txt')
4524 * f.readlines(8)
4525 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4526 * f.close
4527 *
4528 * With arguments +sep+ and +limit+ given,
4529 * combines the two behaviors
4530 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4531 *
4532 * Optional keyword argument +chomp+ specifies whether line separators
4533 * are to be omitted:
4534 *
4535 * f = File.new('t.txt')
4536 * f.readlines(chomp: true)
4537 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4538 * f.close
4539 *
4540 */
4541
4542static VALUE
4543rb_io_readlines(int argc, VALUE *argv, VALUE io)
4544{
4545 struct getline_arg args;
4546
4547 prepare_getline_args(argc, argv, &args, io);
4548 return io_readlines(&args, io);
4549}
4550
4551static VALUE
4552io_readlines(const struct getline_arg *arg, VALUE io)
4553{
4554 VALUE line, ary;
4555
4556 if (arg->limit == 0)
4557 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4558 ary = rb_ary_new();
4559 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4560 rb_ary_push(ary, line);
4561 }
4562 return ary;
4563}
4564
4565/*
4566 * call-seq:
4567 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4568 * each_line(limit, chomp: false) {|line| ... } -> self
4569 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4570 * each_line -> enumerator
4571 *
4572 * Calls the block with each remaining line read from the stream;
4573 * returns +self+.
4574 * Does nothing if already at end-of-stream;
4575 * See {Line IO}[rdoc-ref:IO@Line+IO].
4576 *
4577 * With no arguments given, reads lines
4578 * as determined by line separator <tt>$/</tt>:
4579 *
4580 * f = File.new('t.txt')
4581 * f.each_line {|line| p line }
4582 * f.each_line {|line| fail 'Cannot happen' }
4583 * f.close
4584 *
4585 * Output:
4586 *
4587 * "First line\n"
4588 * "Second line\n"
4589 * "\n"
4590 * "Fourth line\n"
4591 * "Fifth line\n"
4592 *
4593 * With only string argument +sep+ given,
4594 * reads lines as determined by line separator +sep+;
4595 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4596 *
4597 * f = File.new('t.txt')
4598 * f.each_line('li') {|line| p line }
4599 * f.close
4600 *
4601 * Output:
4602 *
4603 * "First li"
4604 * "ne\nSecond li"
4605 * "ne\n\nFourth li"
4606 * "ne\nFifth li"
4607 * "ne\n"
4608 *
4609 * The two special values for +sep+ are honored:
4610 *
4611 * f = File.new('t.txt')
4612 * # Get all into one string.
4613 * f.each_line(nil) {|line| p line }
4614 * f.close
4615 *
4616 * Output:
4617 *
4618 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4619 *
4620 * f.rewind
4621 * # Get paragraphs (up to two line separators).
4622 * f.each_line('') {|line| p line }
4623 *
4624 * Output:
4625 *
4626 * "First line\nSecond line\n\n"
4627 * "Fourth line\nFifth line\n"
4628 *
4629 * With only integer argument +limit+ given,
4630 * limits the number of bytes in each line;
4631 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4632 *
4633 * f = File.new('t.txt')
4634 * f.each_line(8) {|line| p line }
4635 * f.close
4636 *
4637 * Output:
4638 *
4639 * "First li"
4640 * "ne\n"
4641 * "Second l"
4642 * "ine\n"
4643 * "\n"
4644 * "Fourth l"
4645 * "ine\n"
4646 * "Fifth li"
4647 * "ne\n"
4648 *
4649 * With arguments +sep+ and +limit+ given,
4650 * combines the two behaviors
4651 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4652 *
4653 * Optional keyword argument +chomp+ specifies whether line separators
4654 * are to be omitted:
4655 *
4656 * f = File.new('t.txt')
4657 * f.each_line(chomp: true) {|line| p line }
4658 * f.close
4659 *
4660 * Output:
4661 *
4662 * "First line"
4663 * "Second line"
4664 * ""
4665 * "Fourth line"
4666 * "Fifth line"
4667 *
4668 * Returns an Enumerator if no block is given.
4669 */
4670
4671static VALUE
4672rb_io_each_line(int argc, VALUE *argv, VALUE io)
4673{
4674 VALUE str;
4675 struct getline_arg args;
4676
4677 RETURN_ENUMERATOR(io, argc, argv);
4678 prepare_getline_args(argc, argv, &args, io);
4679 if (args.limit == 0)
4680 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4681 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4682 rb_yield(str);
4683 }
4684 return io;
4685}
4686
4687/*
4688 * call-seq:
4689 * each_byte {|byte| ... } -> self
4690 * each_byte -> enumerator
4691 *
4692 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4693 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4694 *
4695 * f = File.new('t.rus')
4696 * a = []
4697 * f.each_byte {|b| a << b }
4698 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4699 * f.close
4700 *
4701 * Returns an Enumerator if no block is given.
4702 *
4703 * Related: IO#each_char, IO#each_codepoint.
4704 *
4705 */
4706
4707static VALUE
4708rb_io_each_byte(VALUE io)
4709{
4710 rb_io_t *fptr;
4711
4712 RETURN_ENUMERATOR(io, 0, 0);
4713 GetOpenFile(io, fptr);
4714
4715 do {
4716 while (fptr->rbuf.len > 0) {
4717 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4718 fptr->rbuf.len--;
4719 rb_yield(INT2FIX(*p & 0xff));
4721 errno = 0;
4722 }
4723 READ_CHECK(fptr);
4724 } while (io_fillbuf(fptr) >= 0);
4725 return io;
4726}
4727
4728static VALUE
4729io_getc(rb_io_t *fptr, rb_encoding *enc)
4730{
4731 int r, n, cr = 0;
4732 VALUE str;
4733
4734 if (NEED_READCONV(fptr)) {
4735 rb_encoding *read_enc = io_read_encoding(fptr);
4736
4737 str = Qnil;
4738 SET_BINARY_MODE(fptr);
4739 make_readconv(fptr, 0);
4740
4741 while (1) {
4742 if (fptr->cbuf.len) {
4743 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4744 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4745 read_enc);
4746 if (!MBCLEN_NEEDMORE_P(r))
4747 break;
4748 if (fptr->cbuf.len == fptr->cbuf.capa) {
4749 rb_raise(rb_eIOError, "too long character");
4750 }
4751 }
4752
4753 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4754 if (fptr->cbuf.len == 0) {
4755 clear_readconv(fptr);
4756 return Qnil;
4757 }
4758 /* return an unit of an incomplete character just before EOF */
4759 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4760 fptr->cbuf.off += 1;
4761 fptr->cbuf.len -= 1;
4762 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4764 return str;
4765 }
4766 }
4767 if (MBCLEN_INVALID_P(r)) {
4768 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4769 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4770 read_enc);
4771 io_shift_cbuf(fptr, r, &str);
4773 }
4774 else {
4775 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4777 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4778 ISASCII(RSTRING_PTR(str)[0])) {
4779 cr = ENC_CODERANGE_7BIT;
4780 }
4781 }
4782 str = io_enc_str(str, fptr);
4783 ENC_CODERANGE_SET(str, cr);
4784 return str;
4785 }
4786
4787 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4788 if (io_fillbuf(fptr) < 0) {
4789 return Qnil;
4790 }
4791 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4792 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4793 fptr->rbuf.off += 1;
4794 fptr->rbuf.len -= 1;
4795 cr = ENC_CODERANGE_7BIT;
4796 }
4797 else {
4798 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4799 if (MBCLEN_CHARFOUND_P(r) &&
4800 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4801 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4802 fptr->rbuf.off += n;
4803 fptr->rbuf.len -= n;
4805 }
4806 else if (MBCLEN_NEEDMORE_P(r)) {
4807 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4808 fptr->rbuf.len = 0;
4809 getc_needmore:
4810 if (io_fillbuf(fptr) != -1) {
4811 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4812 fptr->rbuf.off++;
4813 fptr->rbuf.len--;
4814 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4815 if (MBCLEN_NEEDMORE_P(r)) {
4816 goto getc_needmore;
4817 }
4818 else if (MBCLEN_CHARFOUND_P(r)) {
4820 }
4821 }
4822 }
4823 else {
4824 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4825 fptr->rbuf.off++;
4826 fptr->rbuf.len--;
4827 }
4828 }
4829 if (!cr) cr = ENC_CODERANGE_BROKEN;
4830 str = io_enc_str(str, fptr);
4831 ENC_CODERANGE_SET(str, cr);
4832 return str;
4833}
4834
4835/*
4836 * call-seq:
4837 * each_char {|c| ... } -> self
4838 * each_char -> enumerator
4839 *
4840 * Calls the given block with each character in the stream; returns +self+.
4841 * See {Character IO}[rdoc-ref:IO@Character+IO].
4842 *
4843 * f = File.new('t.rus')
4844 * a = []
4845 * f.each_char {|c| a << c.ord }
4846 * a # => [1090, 1077, 1089, 1090]
4847 * f.close
4848 *
4849 * Returns an Enumerator if no block is given.
4850 *
4851 * Related: IO#each_byte, IO#each_codepoint.
4852 *
4853 */
4854
4855static VALUE
4856rb_io_each_char(VALUE io)
4857{
4858 rb_io_t *fptr;
4859 rb_encoding *enc;
4860 VALUE c;
4861
4862 RETURN_ENUMERATOR(io, 0, 0);
4863 GetOpenFile(io, fptr);
4865
4866 enc = io_input_encoding(fptr);
4867 READ_CHECK(fptr);
4868 while (!NIL_P(c = io_getc(fptr, enc))) {
4869 rb_yield(c);
4870 }
4871 return io;
4872}
4873
4874/*
4875 * call-seq:
4876 * each_codepoint {|c| ... } -> self
4877 * each_codepoint -> enumerator
4878 *
4879 * Calls the given block with each codepoint in the stream; returns +self+:
4880 *
4881 * f = File.new('t.rus')
4882 * a = []
4883 * f.each_codepoint {|c| a << c }
4884 * a # => [1090, 1077, 1089, 1090]
4885 * f.close
4886 *
4887 * Returns an Enumerator if no block is given.
4888 *
4889 * Related: IO#each_byte, IO#each_char.
4890 *
4891 */
4892
4893static VALUE
4894rb_io_each_codepoint(VALUE io)
4895{
4896 rb_io_t *fptr;
4897 rb_encoding *enc;
4898 unsigned int c;
4899 int r, n;
4900
4901 RETURN_ENUMERATOR(io, 0, 0);
4902 GetOpenFile(io, fptr);
4904
4905 READ_CHECK(fptr);
4906 if (NEED_READCONV(fptr)) {
4907 SET_BINARY_MODE(fptr);
4908 r = 1; /* no invalid char yet */
4909 for (;;) {
4910 make_readconv(fptr, 0);
4911 for (;;) {
4912 if (fptr->cbuf.len) {
4913 if (fptr->encs.enc)
4914 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4915 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4916 fptr->encs.enc);
4917 else
4918 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4919 if (!MBCLEN_NEEDMORE_P(r))
4920 break;
4921 if (fptr->cbuf.len == fptr->cbuf.capa) {
4922 rb_raise(rb_eIOError, "too long character");
4923 }
4924 }
4925 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4926 clear_readconv(fptr);
4927 if (!MBCLEN_CHARFOUND_P(r)) {
4928 enc = fptr->encs.enc;
4929 goto invalid;
4930 }
4931 return io;
4932 }
4933 }
4934 if (MBCLEN_INVALID_P(r)) {
4935 enc = fptr->encs.enc;
4936 goto invalid;
4937 }
4938 n = MBCLEN_CHARFOUND_LEN(r);
4939 if (fptr->encs.enc) {
4940 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4941 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4942 fptr->encs.enc);
4943 }
4944 else {
4945 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4946 }
4947 fptr->cbuf.off += n;
4948 fptr->cbuf.len -= n;
4949 rb_yield(UINT2NUM(c));
4951 }
4952 }
4953 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4954 enc = io_input_encoding(fptr);
4955 while (io_fillbuf(fptr) >= 0) {
4956 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4957 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4958 if (MBCLEN_CHARFOUND_P(r) &&
4959 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4960 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4961 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4962 fptr->rbuf.off += n;
4963 fptr->rbuf.len -= n;
4964 rb_yield(UINT2NUM(c));
4965 }
4966 else if (MBCLEN_INVALID_P(r)) {
4967 goto invalid;
4968 }
4969 else if (MBCLEN_NEEDMORE_P(r)) {
4970 char cbuf[8], *p = cbuf;
4971 int more = MBCLEN_NEEDMORE_LEN(r);
4972 if (more > numberof(cbuf)) goto invalid;
4973 more += n = fptr->rbuf.len;
4974 if (more > numberof(cbuf)) goto invalid;
4975 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4976 (p += n, (more -= n) > 0)) {
4977 if (io_fillbuf(fptr) < 0) goto invalid;
4978 if ((n = fptr->rbuf.len) > more) n = more;
4979 }
4980 r = rb_enc_precise_mbclen(cbuf, p, enc);
4981 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4982 c = rb_enc_codepoint(cbuf, p, enc);
4983 rb_yield(UINT2NUM(c));
4984 }
4985 else {
4986 continue;
4987 }
4989 }
4990 return io;
4991
4992 invalid:
4993 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4995}
4996
4997/*
4998 * call-seq:
4999 * getc -> character or nil
5000 *
5001 * Reads and returns the next 1-character string from the stream;
5002 * returns +nil+ if already at end-of-stream.
5003 * See {Character IO}[rdoc-ref:IO@Character+IO].
5004 *
5005 * f = File.open('t.txt')
5006 * f.getc # => "F"
5007 * f.close
5008 * f = File.open('t.rus')
5009 * f.getc.ord # => 1090
5010 * f.close
5011 *
5012 * Related: IO#readchar (may raise EOFError).
5013 *
5014 */
5015
5016static VALUE
5017rb_io_getc(VALUE io)
5018{
5019 rb_io_t *fptr;
5020 rb_encoding *enc;
5021
5022 GetOpenFile(io, fptr);
5024
5025 enc = io_input_encoding(fptr);
5026 READ_CHECK(fptr);
5027 return io_getc(fptr, enc);
5028}
5029
5030/*
5031 * call-seq:
5032 * readchar -> string
5033 *
5034 * Reads and returns the next 1-character string from the stream;
5035 * raises EOFError if already at end-of-stream.
5036 * See {Character IO}[rdoc-ref:IO@Character+IO].
5037 *
5038 * f = File.open('t.txt')
5039 * f.readchar # => "F"
5040 * f.close
5041 * f = File.open('t.rus')
5042 * f.readchar.ord # => 1090
5043 * f.close
5044 *
5045 * Related: IO#getc (will not raise EOFError).
5046 *
5047 */
5048
5049static VALUE
5050rb_io_readchar(VALUE io)
5051{
5052 VALUE c = rb_io_getc(io);
5053
5054 if (NIL_P(c)) {
5055 rb_eof_error();
5056 }
5057 return c;
5058}
5059
5060/*
5061 * call-seq:
5062 * getbyte -> integer or nil
5063 *
5064 * Reads and returns the next byte (in range 0..255) from the stream;
5065 * returns +nil+ if already at end-of-stream.
5066 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5067 *
5068 * f = File.open('t.txt')
5069 * f.getbyte # => 70
5070 * f.close
5071 * f = File.open('t.rus')
5072 * f.getbyte # => 209
5073 * f.close
5074 *
5075 * Related: IO#readbyte (may raise EOFError).
5076 */
5077
5078VALUE
5080{
5081 rb_io_t *fptr;
5082 int c;
5083
5084 GetOpenFile(io, fptr);
5086 READ_CHECK(fptr);
5087 VALUE r_stdout = rb_ractor_stdout();
5088 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5089 rb_io_t *ofp;
5090 GetOpenFile(r_stdout, ofp);
5091 if (ofp->mode & FMODE_TTY) {
5092 rb_io_flush(r_stdout);
5093 }
5094 }
5095 if (io_fillbuf(fptr) < 0) {
5096 return Qnil;
5097 }
5098 fptr->rbuf.off++;
5099 fptr->rbuf.len--;
5100 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5101 return INT2FIX(c & 0xff);
5102}
5103
5104/*
5105 * call-seq:
5106 * readbyte -> integer
5107 *
5108 * Reads and returns the next byte (in range 0..255) from the stream;
5109 * raises EOFError if already at end-of-stream.
5110 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5111 *
5112 * f = File.open('t.txt')
5113 * f.readbyte # => 70
5114 * f.close
5115 * f = File.open('t.rus')
5116 * f.readbyte # => 209
5117 * f.close
5118 *
5119 * Related: IO#getbyte (will not raise EOFError).
5120 *
5121 */
5122
5123static VALUE
5124rb_io_readbyte(VALUE io)
5125{
5126 VALUE c = rb_io_getbyte(io);
5127
5128 if (NIL_P(c)) {
5129 rb_eof_error();
5130 }
5131 return c;
5132}
5133
5134/*
5135 * call-seq:
5136 * ungetbyte(integer) -> nil
5137 * ungetbyte(string) -> nil
5138 *
5139 * Pushes back ("unshifts") the given data onto the stream's buffer,
5140 * placing the data so that it is next to be read; returns +nil+.
5141 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5142 *
5143 * Note that:
5144 *
5145 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5146 * - Calling #rewind on the stream discards the pushed-back data.
5147 *
5148 * When argument +integer+ is given, uses only its low-order byte:
5149 *
5150 * File.write('t.tmp', '012')
5151 * f = File.open('t.tmp')
5152 * f.ungetbyte(0x41) # => nil
5153 * f.read # => "A012"
5154 * f.rewind
5155 * f.ungetbyte(0x4243) # => nil
5156 * f.read # => "C012"
5157 * f.close
5158 *
5159 * When argument +string+ is given, uses all bytes:
5160 *
5161 * File.write('t.tmp', '012')
5162 * f = File.open('t.tmp')
5163 * f.ungetbyte('A') # => nil
5164 * f.read # => "A012"
5165 * f.rewind
5166 * f.ungetbyte('BCDE') # => nil
5167 * f.read # => "BCDE012"
5168 * f.close
5169 *
5170 */
5171
5172VALUE
5174{
5175 rb_io_t *fptr;
5176
5177 GetOpenFile(io, fptr);
5179 switch (TYPE(b)) {
5180 case T_NIL:
5181 return Qnil;
5182 case T_FIXNUM:
5183 case T_BIGNUM: ;
5184 VALUE v = rb_int_modulo(b, INT2FIX(256));
5185 unsigned char c = NUM2INT(v) & 0xFF;
5186 b = rb_str_new((const char *)&c, 1);
5187 break;
5188 default:
5189 StringValue(b);
5190 }
5191 io_ungetbyte(b, fptr);
5192 return Qnil;
5193}
5194
5195/*
5196 * call-seq:
5197 * ungetc(integer) -> nil
5198 * ungetc(string) -> nil
5199 *
5200 * Pushes back ("unshifts") the given data onto the stream's buffer,
5201 * placing the data so that it is next to be read; returns +nil+.
5202 * See {Character IO}[rdoc-ref:IO@Character+IO].
5203 *
5204 * Note that:
5205 *
5206 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5207 * - Calling #rewind on the stream discards the pushed-back data.
5208 *
5209 * When argument +integer+ is given, interprets the integer as a character:
5210 *
5211 * File.write('t.tmp', '012')
5212 * f = File.open('t.tmp')
5213 * f.ungetc(0x41) # => nil
5214 * f.read # => "A012"
5215 * f.rewind
5216 * f.ungetc(0x0442) # => nil
5217 * f.getc.ord # => 1090
5218 * f.close
5219 *
5220 * When argument +string+ is given, uses all characters:
5221 *
5222 * File.write('t.tmp', '012')
5223 * f = File.open('t.tmp')
5224 * f.ungetc('A') # => nil
5225 * f.read # => "A012"
5226 * f.rewind
5227 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5228 * f.getc.ord # => 1090
5229 * f.getc.ord # => 1077
5230 * f.getc.ord # => 1089
5231 * f.getc.ord # => 1090
5232 * f.close
5233 *
5234 */
5235
5236VALUE
5238{
5239 rb_io_t *fptr;
5240 long len;
5241
5242 GetOpenFile(io, fptr);
5244 if (FIXNUM_P(c)) {
5245 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5246 }
5247 else if (RB_BIGNUM_TYPE_P(c)) {
5248 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5249 }
5250 else {
5251 StringValue(c);
5252 }
5253 if (NEED_READCONV(fptr)) {
5254 SET_BINARY_MODE(fptr);
5255 len = RSTRING_LEN(c);
5256#if SIZEOF_LONG > SIZEOF_INT
5257 if (len > INT_MAX)
5258 rb_raise(rb_eIOError, "ungetc failed");
5259#endif
5260 make_readconv(fptr, (int)len);
5261 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5262 rb_raise(rb_eIOError, "ungetc failed");
5263 if (fptr->cbuf.off < len) {
5264 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5265 fptr->cbuf.ptr+fptr->cbuf.off,
5266 char, fptr->cbuf.len);
5267 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5268 }
5269 fptr->cbuf.off -= (int)len;
5270 fptr->cbuf.len += (int)len;
5271 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5272 }
5273 else {
5274 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5275 io_ungetbyte(c, fptr);
5276 }
5277 return Qnil;
5278}
5279
5280/*
5281 * call-seq:
5282 * isatty -> true or false
5283 *
5284 * Returns +true+ if the stream is associated with a terminal device (tty),
5285 * +false+ otherwise:
5286 *
5287 * f = File.new('t.txt').isatty #=> false
5288 * f.close
5289 * f = File.new('/dev/tty').isatty #=> true
5290 * f.close
5291 *
5292 */
5293
5294static VALUE
5295rb_io_isatty(VALUE io)
5296{
5297 rb_io_t *fptr;
5298
5299 GetOpenFile(io, fptr);
5300 return RBOOL(isatty(fptr->fd) != 0);
5301}
5302
5303#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5304/*
5305 * call-seq:
5306 * close_on_exec? -> true or false
5307 *
5308 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5309 *
5310 * f = File.open('t.txt')
5311 * f.close_on_exec? # => true
5312 * f.close_on_exec = false
5313 * f.close_on_exec? # => false
5314 * f.close
5315 *
5316 */
5317
5318static VALUE
5319rb_io_close_on_exec_p(VALUE io)
5320{
5321 rb_io_t *fptr;
5322 VALUE write_io;
5323 int fd, ret;
5324
5325 write_io = GetWriteIO(io);
5326 if (io != write_io) {
5327 GetOpenFile(write_io, fptr);
5328 if (fptr && 0 <= (fd = fptr->fd)) {
5329 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5330 if (!(ret & FD_CLOEXEC)) return Qfalse;
5331 }
5332 }
5333
5334 GetOpenFile(io, fptr);
5335 if (fptr && 0 <= (fd = fptr->fd)) {
5336 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5337 if (!(ret & FD_CLOEXEC)) return Qfalse;
5338 }
5339 return Qtrue;
5340}
5341#else
5342#define rb_io_close_on_exec_p rb_f_notimplement
5343#endif
5344
5345#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5346/*
5347 * call-seq:
5348 * self.close_on_exec = bool -> true or false
5349 *
5350 * Sets a close-on-exec flag.
5351 *
5352 * f = File.open(File::NULL)
5353 * f.close_on_exec = true
5354 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5355 * f.closed? #=> false
5356 *
5357 * Ruby sets close-on-exec flags of all file descriptors by default
5358 * since Ruby 2.0.0.
5359 * So you don't need to set by yourself.
5360 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5361 * if another thread use fork() and exec() (via system() method for example).
5362 * If you really needs file descriptor inheritance to child process,
5363 * use spawn()'s argument such as fd=>fd.
5364 */
5365
5366static VALUE
5367rb_io_set_close_on_exec(VALUE io, VALUE arg)
5368{
5369 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5370 rb_io_t *fptr;
5371 VALUE write_io;
5372 int fd, ret;
5373
5374 write_io = GetWriteIO(io);
5375 if (io != write_io) {
5376 GetOpenFile(write_io, fptr);
5377 if (fptr && 0 <= (fd = fptr->fd)) {
5378 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5379 if ((ret & FD_CLOEXEC) != flag) {
5380 ret = (ret & ~FD_CLOEXEC) | flag;
5381 ret = fcntl(fd, F_SETFD, ret);
5382 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5383 }
5384 }
5385
5386 }
5387
5388 GetOpenFile(io, fptr);
5389 if (fptr && 0 <= (fd = fptr->fd)) {
5390 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5391 if ((ret & FD_CLOEXEC) != flag) {
5392 ret = (ret & ~FD_CLOEXEC) | flag;
5393 ret = fcntl(fd, F_SETFD, ret);
5394 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5395 }
5396 }
5397 return Qnil;
5398}
5399#else
5400#define rb_io_set_close_on_exec rb_f_notimplement
5401#endif
5402
5403#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5404#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5405
5406static VALUE
5407finish_writeconv(rb_io_t *fptr, int noalloc)
5408{
5409 unsigned char *ds, *dp, *de;
5411
5412 if (!fptr->wbuf.ptr) {
5413 unsigned char buf[1024];
5414
5416 while (res == econv_destination_buffer_full) {
5417 ds = dp = buf;
5418 de = buf + sizeof(buf);
5419 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5420 while (dp-ds) {
5421 size_t remaining = dp-ds;
5422 long result = rb_io_write_memory(fptr, ds, remaining);
5423
5424 if (result > 0) {
5425 ds += result;
5426 if ((size_t)result == remaining) break;
5427 }
5428 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5429 if (fptr->fd < 0)
5430 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5431 }
5432 else {
5433 return noalloc ? Qtrue : INT2NUM(errno);
5434 }
5435 }
5436 if (res == econv_invalid_byte_sequence ||
5437 res == econv_incomplete_input ||
5439 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5440 }
5441 }
5442
5443 return Qnil;
5444 }
5445
5447 while (res == econv_destination_buffer_full) {
5448 if (fptr->wbuf.len == fptr->wbuf.capa) {
5449 if (io_fflush(fptr) < 0) {
5450 return noalloc ? Qtrue : INT2NUM(errno);
5451 }
5452 }
5453
5454 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5455 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5456 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5457 fptr->wbuf.len += (int)(dp - ds);
5458 if (res == econv_invalid_byte_sequence ||
5459 res == econv_incomplete_input ||
5461 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5462 }
5463 }
5464 return Qnil;
5465}
5466
5468 rb_io_t *fptr;
5469 int noalloc;
5470};
5471
5472static VALUE
5473finish_writeconv_sync(VALUE arg)
5474{
5475 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5476 return finish_writeconv(p->fptr, p->noalloc);
5477}
5478
5479static void*
5480nogvl_close(void *ptr)
5481{
5482 int *fd = ptr;
5483
5484 return (void*)(intptr_t)close(*fd);
5485}
5486
5487static int
5488maygvl_close(int fd, int keepgvl)
5489{
5490 if (keepgvl)
5491 return close(fd);
5492
5493 /*
5494 * close() may block for certain file types (NFS, SO_LINGER sockets,
5495 * inotify), so let other threads run.
5496 */
5497 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5498}
5499
5500static void*
5501nogvl_fclose(void *ptr)
5502{
5503 FILE *file = ptr;
5504
5505 return (void*)(intptr_t)fclose(file);
5506}
5507
5508static int
5509maygvl_fclose(FILE *file, int keepgvl)
5510{
5511 if (keepgvl)
5512 return fclose(file);
5513
5514 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5515}
5516
5517static void free_io_buffer(rb_io_buffer_t *buf);
5518
5519static void
5520fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5521{
5522 VALUE error = Qnil;
5523 int fd = fptr->fd;
5524 FILE *stdio_file = fptr->stdio_file;
5525 int mode = fptr->mode;
5526
5527 if (fptr->writeconv) {
5528 if (!NIL_P(fptr->write_lock) && !noraise) {
5529 struct finish_writeconv_arg arg;
5530 arg.fptr = fptr;
5531 arg.noalloc = noraise;
5532 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5533 }
5534 else {
5535 error = finish_writeconv(fptr, noraise);
5536 }
5537 }
5538 if (fptr->wbuf.len) {
5539 if (noraise) {
5540 io_flush_buffer_sync(fptr);
5541 }
5542 else {
5543 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5544 error = INT2NUM(errno);
5545 }
5546 }
5547 }
5548
5549 int done = 0;
5550
5551 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5552 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5553 done = 1;
5554 }
5555
5556 fptr->fd = -1;
5557 fptr->stdio_file = 0;
5559
5560 // wait for blocking operations to ensure they do not hit EBADF:
5561 rb_thread_io_close_wait(fptr);
5562
5563 // Disable for now.
5564 // if (!done && fd >= 0) {
5565 // VALUE scheduler = rb_fiber_scheduler_current();
5566 // if (scheduler != Qnil) {
5567 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5568 // if (!UNDEF_P(result)) done = 1;
5569 // }
5570 // }
5571
5572 if (!done && stdio_file) {
5573 // stdio_file is deallocated anyway even if fclose failed.
5574 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5575 if (!noraise) {
5576 error = INT2NUM(errno);
5577 }
5578 }
5579
5580 done = 1;
5581 }
5582
5583 if (!done && fd >= 0) {
5584 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5585 // We assumes it is closed.
5586
5587 keepgvl |= !(mode & FMODE_WRITABLE);
5588 keepgvl |= noraise;
5589 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5590 if (!noraise) {
5591 error = INT2NUM(errno);
5592 }
5593 }
5594
5595 done = 1;
5596 }
5597
5598 if (!NIL_P(error) && !noraise) {
5599 if (RB_INTEGER_TYPE_P(error))
5600 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5601 else
5602 rb_exc_raise(error);
5603 }
5604}
5605
5606static void
5607fptr_finalize(rb_io_t *fptr, int noraise)
5608{
5609 fptr_finalize_flush(fptr, noraise, FALSE);
5610 free_io_buffer(&fptr->rbuf);
5611 free_io_buffer(&fptr->wbuf);
5612 clear_codeconv(fptr);
5613}
5614
5615static void
5616rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5617{
5618 if (fptr->finalize) {
5619 (*fptr->finalize)(fptr, noraise);
5620 }
5621 else {
5622 fptr_finalize(fptr, noraise);
5623 }
5624}
5625
5626static void
5627free_io_buffer(rb_io_buffer_t *buf)
5628{
5629 if (buf->ptr) {
5630 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5631 buf->ptr = NULL;
5632 }
5633}
5634
5635static void
5636clear_readconv(rb_io_t *fptr)
5637{
5638 if (fptr->readconv) {
5639 rb_econv_close(fptr->readconv);
5640 fptr->readconv = NULL;
5641 }
5642 free_io_buffer(&fptr->cbuf);
5643}
5644
5645static void
5646clear_writeconv(rb_io_t *fptr)
5647{
5648 if (fptr->writeconv) {
5650 fptr->writeconv = NULL;
5651 }
5652 fptr->writeconv_initialized = 0;
5653}
5654
5655static void
5656clear_codeconv(rb_io_t *fptr)
5657{
5658 clear_readconv(fptr);
5659 clear_writeconv(fptr);
5660}
5661
5662static void
5663rb_io_fptr_cleanup_all(rb_io_t *fptr)
5664{
5665 fptr->pathv = Qnil;
5666 if (0 <= fptr->fd)
5667 rb_io_fptr_cleanup(fptr, TRUE);
5668 fptr->write_lock = Qnil;
5669 free_io_buffer(&fptr->rbuf);
5670 free_io_buffer(&fptr->wbuf);
5671 clear_codeconv(fptr);
5672}
5673
5674int
5676{
5677 if (!io) return 0;
5678 rb_io_fptr_cleanup_all(io);
5679 free(io);
5680
5681 return 1;
5682}
5683
5684size_t
5685rb_io_memsize(const rb_io_t *io)
5686{
5687 size_t size = sizeof(rb_io_t);
5688 size += io->rbuf.capa;
5689 size += io->wbuf.capa;
5690 size += io->cbuf.capa;
5691 if (io->readconv) size += rb_econv_memsize(io->readconv);
5692 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5693
5694 struct rb_io_blocking_operation *blocking_operation = 0;
5695
5696 // Validate the fork generation of the IO object. If the IO object fork generation is different, the list of blocking operations is not valid memory. See `rb_io_blocking_operations` for the exact semantics.
5697 rb_serial_t fork_generation = GET_VM()->fork_gen;
5698 if (io->fork_generation == fork_generation) {
5699 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5700 size += sizeof(struct rb_io_blocking_operation);
5701 }
5702 }
5703
5704 return size;
5705}
5706
5707#ifdef _WIN32
5708/* keep GVL while closing to prevent crash on Windows */
5709# define KEEPGVL TRUE
5710#else
5711# define KEEPGVL FALSE
5712#endif
5713
5714static rb_io_t *
5715io_close_fptr(VALUE io)
5716{
5717 rb_io_t *fptr;
5718 VALUE write_io;
5719 rb_io_t *write_fptr;
5720
5721 write_io = GetWriteIO(io);
5722 if (io != write_io) {
5723 write_fptr = RFILE(write_io)->fptr;
5724 if (write_fptr && 0 <= write_fptr->fd) {
5725 rb_io_fptr_cleanup(write_fptr, TRUE);
5726 }
5727 }
5728
5729 fptr = RFILE(io)->fptr;
5730 if (!fptr) return 0;
5731 if (fptr->fd < 0) return 0;
5732
5733 if (rb_thread_io_close_interrupt(fptr)) {
5734 /* calls close(fptr->fd): */
5735 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5736 }
5737 rb_io_fptr_cleanup(fptr, FALSE);
5738 return fptr;
5739}
5740
5741static void
5742fptr_waitpid(rb_io_t *fptr, int nohang)
5743{
5744 int status;
5745 if (fptr->pid) {
5746 rb_last_status_clear();
5747 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5748 fptr->pid = 0;
5749 }
5750}
5751
5752VALUE
5754{
5755 rb_io_t *fptr = io_close_fptr(io);
5756 if (fptr) fptr_waitpid(fptr, 0);
5757 return Qnil;
5758}
5759
5760/*
5761 * call-seq:
5762 * close -> nil
5763 *
5764 * Closes the stream for both reading and writing
5765 * if open for either or both; returns +nil+.
5766 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5767 *
5768 * If the stream is open for writing, flushes any buffered writes
5769 * to the operating system before closing.
5770 *
5771 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5772 * (child exit status).
5773 *
5774 * It is not an error to close an IO object that has already been closed.
5775 * It just returns nil.
5776 *
5777 * Example:
5778 *
5779 * IO.popen('ruby', 'r+') do |pipe|
5780 * puts pipe.closed?
5781 * pipe.close
5782 * puts $?
5783 * puts pipe.closed?
5784 * end
5785 *
5786 * Output:
5787 *
5788 * false
5789 * pid 13760 exit 0
5790 * true
5791 *
5792 * Related: IO#close_read, IO#close_write, IO#closed?.
5793 */
5794
5795static VALUE
5796rb_io_close_m(VALUE io)
5797{
5798 rb_io_t *fptr = rb_io_get_fptr(io);
5799 if (fptr->fd < 0) {
5800 return Qnil;
5801 }
5802 rb_io_close(io);
5803 return Qnil;
5804}
5805
5806static VALUE
5807io_call_close(VALUE io)
5808{
5809 rb_check_funcall(io, rb_intern("close"), 0, 0);
5810 return io;
5811}
5812
5813static VALUE
5814ignore_closed_stream(VALUE io, VALUE exc)
5815{
5816 enum {mesg_len = sizeof(closed_stream)-1};
5817 VALUE mesg = rb_attr_get(exc, idMesg);
5818 if (!RB_TYPE_P(mesg, T_STRING) ||
5819 RSTRING_LEN(mesg) != mesg_len ||
5820 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5821 rb_exc_raise(exc);
5822 }
5823 return io;
5824}
5825
5826static VALUE
5827io_close(VALUE io)
5828{
5829 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5830 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5831 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5832 rb_eIOError, (VALUE)0);
5833 return io;
5834}
5835
5836/*
5837 * call-seq:
5838 * closed? -> true or false
5839 *
5840 * Returns +true+ if the stream is closed for both reading and writing,
5841 * +false+ otherwise.
5842 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5843 *
5844 * IO.popen('ruby', 'r+') do |pipe|
5845 * puts pipe.closed?
5846 * pipe.close_read
5847 * puts pipe.closed?
5848 * pipe.close_write
5849 * puts pipe.closed?
5850 * end
5851 *
5852 * Output:
5853 *
5854 * false
5855 * false
5856 * true
5857 *
5858 * Related: IO#close_read, IO#close_write, IO#close.
5859 */
5860VALUE
5862{
5863 rb_io_t *fptr;
5864 VALUE write_io;
5865 rb_io_t *write_fptr;
5866
5867 write_io = GetWriteIO(io);
5868 if (io != write_io) {
5869 write_fptr = RFILE(write_io)->fptr;
5870 if (write_fptr && 0 <= write_fptr->fd) {
5871 return Qfalse;
5872 }
5873 }
5874
5875 fptr = rb_io_get_fptr(io);
5876 return RBOOL(0 > fptr->fd);
5877}
5878
5879/*
5880 * call-seq:
5881 * close_read -> nil
5882 *
5883 * Closes the stream for reading if open for reading;
5884 * returns +nil+.
5885 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5886 *
5887 * If the stream was opened by IO.popen and is also closed for writing,
5888 * sets global variable <tt>$?</tt> (child exit status).
5889 *
5890 * Example:
5891 *
5892 * IO.popen('ruby', 'r+') do |pipe|
5893 * puts pipe.closed?
5894 * pipe.close_write
5895 * puts pipe.closed?
5896 * pipe.close_read
5897 * puts $?
5898 * puts pipe.closed?
5899 * end
5900 *
5901 * Output:
5902 *
5903 * false
5904 * false
5905 * pid 14748 exit 0
5906 * true
5907 *
5908 * Related: IO#close, IO#close_write, IO#closed?.
5909 */
5910
5911static VALUE
5912rb_io_close_read(VALUE io)
5913{
5914 rb_io_t *fptr;
5915 VALUE write_io;
5916
5917 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5918 if (fptr->fd < 0) return Qnil;
5919 if (is_socket(fptr->fd, fptr->pathv)) {
5920#ifndef SHUT_RD
5921# define SHUT_RD 0
5922#endif
5923 if (shutdown(fptr->fd, SHUT_RD) < 0)
5924 rb_sys_fail_path(fptr->pathv);
5925 fptr->mode &= ~FMODE_READABLE;
5926 if (!(fptr->mode & FMODE_WRITABLE))
5927 return rb_io_close(io);
5928 return Qnil;
5929 }
5930
5931 write_io = GetWriteIO(io);
5932 if (io != write_io) {
5933 rb_io_t *wfptr;
5934 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5935 wfptr->pid = fptr->pid;
5936 fptr->pid = 0;
5937 RFILE(io)->fptr = wfptr;
5938 /* bind to write_io temporarily to get rid of memory/fd leak */
5939 fptr->tied_io_for_writing = 0;
5940 RFILE(write_io)->fptr = fptr;
5941 rb_io_fptr_cleanup(fptr, FALSE);
5942 /* should not finalize fptr because another thread may be reading it */
5943 return Qnil;
5944 }
5945
5946 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5947 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5948 }
5949 return rb_io_close(io);
5950}
5951
5952/*
5953 * call-seq:
5954 * close_write -> nil
5955 *
5956 * Closes the stream for writing if open for writing;
5957 * returns +nil+.
5958 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5959 *
5960 * Flushes any buffered writes to the operating system before closing.
5961 *
5962 * If the stream was opened by IO.popen and is also closed for reading,
5963 * sets global variable <tt>$?</tt> (child exit status).
5964 *
5965 * IO.popen('ruby', 'r+') do |pipe|
5966 * puts pipe.closed?
5967 * pipe.close_read
5968 * puts pipe.closed?
5969 * pipe.close_write
5970 * puts $?
5971 * puts pipe.closed?
5972 * end
5973 *
5974 * Output:
5975 *
5976 * false
5977 * false
5978 * pid 15044 exit 0
5979 * true
5980 *
5981 * Related: IO#close, IO#close_read, IO#closed?.
5982 */
5983
5984static VALUE
5985rb_io_close_write(VALUE io)
5986{
5987 rb_io_t *fptr;
5988 VALUE write_io;
5989
5990 write_io = GetWriteIO(io);
5991 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5992 if (fptr->fd < 0) return Qnil;
5993 if (is_socket(fptr->fd, fptr->pathv)) {
5994#ifndef SHUT_WR
5995# define SHUT_WR 1
5996#endif
5997 if (shutdown(fptr->fd, SHUT_WR) < 0)
5998 rb_sys_fail_path(fptr->pathv);
5999 fptr->mode &= ~FMODE_WRITABLE;
6000 if (!(fptr->mode & FMODE_READABLE))
6001 return rb_io_close(write_io);
6002 return Qnil;
6003 }
6004
6005 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6006 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6007 }
6008
6009 if (io != write_io) {
6010 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6011 fptr->tied_io_for_writing = 0;
6012 }
6013 rb_io_close(write_io);
6014 return Qnil;
6015}
6016
6017/*
6018 * call-seq:
6019 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6020 *
6021 * Behaves like IO#seek, except that it:
6022 *
6023 * - Uses low-level system functions.
6024 * - Returns the new position.
6025 *
6026 */
6027
6028static VALUE
6029rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6030{
6031 VALUE offset, ptrname;
6032 int whence = SEEK_SET;
6033 rb_io_t *fptr;
6034 rb_off_t pos;
6035
6036 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6037 whence = interpret_seek_whence(ptrname);
6038 }
6039 pos = NUM2OFFT(offset);
6040 GetOpenFile(io, fptr);
6041 if ((fptr->mode & FMODE_READABLE) &&
6042 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6043 rb_raise(rb_eIOError, "sysseek for buffered IO");
6044 }
6045 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6046 rb_warn("sysseek for buffered IO");
6047 }
6048 errno = 0;
6049 pos = lseek(fptr->fd, pos, whence);
6050 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6051
6052 return OFFT2NUM(pos);
6053}
6054
6055/*
6056 * call-seq:
6057 * syswrite(object) -> integer
6058 *
6059 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6060 * returns the number bytes written.
6061 * If +object+ is not a string is converted via method to_s:
6062 *
6063 * f = File.new('t.tmp', 'w')
6064 * f.syswrite('foo') # => 3
6065 * f.syswrite(30) # => 2
6066 * f.syswrite(:foo) # => 3
6067 * f.close
6068 *
6069 * This methods should not be used with other stream-writer methods.
6070 *
6071 */
6072
6073static VALUE
6074rb_io_syswrite(VALUE io, VALUE str)
6075{
6076 VALUE tmp;
6077 rb_io_t *fptr;
6078 long n, len;
6079 const char *ptr;
6080
6081 if (!RB_TYPE_P(str, T_STRING))
6082 str = rb_obj_as_string(str);
6083
6084 io = GetWriteIO(io);
6085 GetOpenFile(io, fptr);
6087
6088 if (fptr->wbuf.len) {
6089 rb_warn("syswrite for buffered IO");
6090 }
6091
6092 tmp = rb_str_tmp_frozen_acquire(str);
6093 RSTRING_GETMEM(tmp, ptr, len);
6094 n = rb_io_write_memory(fptr, ptr, len);
6095 if (n < 0) rb_sys_fail_path(fptr->pathv);
6096 rb_str_tmp_frozen_release(str, tmp);
6097
6098 return LONG2FIX(n);
6099}
6100
6101/*
6102 * call-seq:
6103 * sysread(maxlen) -> string
6104 * sysread(maxlen, out_string) -> string
6105 *
6106 * Behaves like IO#readpartial, except that it uses low-level system functions.
6107 *
6108 * This method should not be used with other stream-reader methods.
6109 *
6110 */
6111
6112static VALUE
6113rb_io_sysread(int argc, VALUE *argv, VALUE io)
6114{
6115 VALUE len, str;
6116 rb_io_t *fptr;
6117 long n, ilen;
6118 struct io_internal_read_struct iis;
6119 int shrinkable;
6120
6121 rb_scan_args(argc, argv, "11", &len, &str);
6122 ilen = NUM2LONG(len);
6123
6124 shrinkable = io_setstrbuf(&str, ilen);
6125 if (ilen == 0) return str;
6126
6127 GetOpenFile(io, fptr);
6129
6130 if (READ_DATA_BUFFERED(fptr)) {
6131 rb_raise(rb_eIOError, "sysread for buffered IO");
6132 }
6133
6134 rb_io_check_closed(fptr);
6135
6136 io_setstrbuf(&str, ilen);
6137 iis.th = rb_thread_current();
6138 iis.fptr = fptr;
6139 iis.nonblock = 0;
6140 iis.fd = fptr->fd;
6141 iis.buf = RSTRING_PTR(str);
6142 iis.capa = ilen;
6143 iis.timeout = NULL;
6144 n = io_read_memory_locktmp(str, &iis);
6145
6146 if (n < 0) {
6147 rb_sys_fail_path(fptr->pathv);
6148 }
6149
6150 io_set_read_length(str, n, shrinkable);
6151
6152 if (n == 0 && ilen > 0) {
6153 rb_eof_error();
6154 }
6155
6156 return str;
6157}
6158
6160 struct rb_io *io;
6161 int fd;
6162 void *buf;
6163 size_t count;
6164 rb_off_t offset;
6165};
6166
6167static VALUE
6168internal_pread_func(void *_arg)
6169{
6170 struct prdwr_internal_arg *arg = _arg;
6171
6172 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6173}
6174
6175static VALUE
6176pread_internal_call(VALUE _arg)
6177{
6178 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6179
6180 VALUE scheduler = rb_fiber_scheduler_current();
6181 if (scheduler != Qnil) {
6182 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6183
6184 if (!UNDEF_P(result)) {
6186 }
6187 }
6188
6189 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6190}
6191
6192/*
6193 * call-seq:
6194 * pread(maxlen, offset) -> string
6195 * pread(maxlen, offset, out_string) -> string
6196 *
6197 * Behaves like IO#readpartial, except that it:
6198 *
6199 * - Reads at the given +offset+ (in bytes).
6200 * - Disregards, and does not modify, the stream's position
6201 * (see {Position}[rdoc-ref:IO@Position]).
6202 * - Bypasses any user space buffering in the stream.
6203 *
6204 * Because this method does not disturb the stream's state
6205 * (its position, in particular), +pread+ allows multiple threads and processes
6206 * to use the same \IO object for reading at various offsets.
6207 *
6208 * f = File.open('t.txt')
6209 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6210 * f.pos # => 52
6211 * # Read 12 bytes at offset 0.
6212 * f.pread(12, 0) # => "First line\n"
6213 * # Read 9 bytes at offset 8.
6214 * f.pread(9, 8) # => "ne\nSecon"
6215 * f.close
6216 *
6217 * Not available on some platforms.
6218 *
6219 */
6220static VALUE
6221rb_io_pread(int argc, VALUE *argv, VALUE io)
6222{
6223 VALUE len, offset, str;
6224 rb_io_t *fptr;
6225 ssize_t n;
6226 struct prdwr_internal_arg arg;
6227 int shrinkable;
6228
6229 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6230 arg.count = NUM2SIZET(len);
6231 arg.offset = NUM2OFFT(offset);
6232
6233 shrinkable = io_setstrbuf(&str, (long)arg.count);
6234 if (arg.count == 0) return str;
6235 arg.buf = RSTRING_PTR(str);
6236
6237 GetOpenFile(io, fptr);
6239
6240 arg.io = fptr;
6241 arg.fd = fptr->fd;
6242 rb_io_check_closed(fptr);
6243
6244 rb_str_locktmp(str);
6245 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6246
6247 if (n < 0) {
6248 rb_sys_fail_path(fptr->pathv);
6249 }
6250 io_set_read_length(str, n, shrinkable);
6251 if (n == 0 && arg.count > 0) {
6252 rb_eof_error();
6253 }
6254
6255 return str;
6256}
6257
6258static VALUE
6259internal_pwrite_func(void *_arg)
6260{
6261 struct prdwr_internal_arg *arg = _arg;
6262
6263 VALUE scheduler = rb_fiber_scheduler_current();
6264 if (scheduler != Qnil) {
6265 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6266
6267 if (!UNDEF_P(result)) {
6269 }
6270 }
6271
6272
6273 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6274}
6275
6276/*
6277 * call-seq:
6278 * pwrite(object, offset) -> integer
6279 *
6280 * Behaves like IO#write, except that it:
6281 *
6282 * - Writes at the given +offset+ (in bytes).
6283 * - Disregards, and does not modify, the stream's position
6284 * (see {Position}[rdoc-ref:IO@Position]).
6285 * - Bypasses any user space buffering in the stream.
6286 *
6287 * Because this method does not disturb the stream's state
6288 * (its position, in particular), +pwrite+ allows multiple threads and processes
6289 * to use the same \IO object for writing at various offsets.
6290 *
6291 * f = File.open('t.tmp', 'w+')
6292 * # Write 6 bytes at offset 3.
6293 * f.pwrite('ABCDEF', 3) # => 6
6294 * f.rewind
6295 * f.read # => "\u0000\u0000\u0000ABCDEF"
6296 * f.close
6297 *
6298 * Not available on some platforms.
6299 *
6300 */
6301static VALUE
6302rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6303{
6304 rb_io_t *fptr;
6305 ssize_t n;
6306 struct prdwr_internal_arg arg;
6307 VALUE tmp;
6308
6309 if (!RB_TYPE_P(str, T_STRING))
6310 str = rb_obj_as_string(str);
6311
6312 arg.offset = NUM2OFFT(offset);
6313
6314 io = GetWriteIO(io);
6315 GetOpenFile(io, fptr);
6317
6318 arg.io = fptr;
6319 arg.fd = fptr->fd;
6320
6321 tmp = rb_str_tmp_frozen_acquire(str);
6322 arg.buf = RSTRING_PTR(tmp);
6323 arg.count = (size_t)RSTRING_LEN(tmp);
6324
6325 n = (ssize_t)rb_io_blocking_region_wait(fptr, internal_pwrite_func, &arg, RUBY_IO_WRITABLE);
6326 if (n < 0) rb_sys_fail_path(fptr->pathv);
6327 rb_str_tmp_frozen_release(str, tmp);
6328
6329 return SSIZET2NUM(n);
6330}
6331
6332VALUE
6334{
6335 rb_io_t *fptr;
6336
6337 GetOpenFile(io, fptr);
6338 if (fptr->readconv)
6340 if (fptr->writeconv)
6342 fptr->mode |= FMODE_BINMODE;
6343 fptr->mode &= ~FMODE_TEXTMODE;
6344 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6345#ifdef O_BINARY
6346 if (!fptr->readconv) {
6347 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6348 }
6349 else {
6350 setmode(fptr->fd, O_BINARY);
6351 }
6352#endif
6353 return io;
6354}
6355
6356static void
6357io_ascii8bit_binmode(rb_io_t *fptr)
6358{
6359 if (fptr->readconv) {
6360 rb_econv_close(fptr->readconv);
6361 fptr->readconv = NULL;
6362 }
6363 if (fptr->writeconv) {
6365 fptr->writeconv = NULL;
6366 }
6367 fptr->mode |= FMODE_BINMODE;
6368 fptr->mode &= ~FMODE_TEXTMODE;
6369 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6370
6371 fptr->encs.enc = rb_ascii8bit_encoding();
6372 fptr->encs.enc2 = NULL;
6373 fptr->encs.ecflags = 0;
6374 fptr->encs.ecopts = Qnil;
6375 clear_codeconv(fptr);
6376}
6377
6378VALUE
6380{
6381 rb_io_t *fptr;
6382
6383 GetOpenFile(io, fptr);
6384 io_ascii8bit_binmode(fptr);
6385
6386 return io;
6387}
6388
6389/*
6390 * call-seq:
6391 * binmode -> self
6392 *
6393 * Sets the stream's data mode as binary
6394 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6395 *
6396 * A stream's data mode may not be changed from binary to text.
6397 *
6398 */
6399
6400static VALUE
6401rb_io_binmode_m(VALUE io)
6402{
6403 VALUE write_io;
6404
6406
6407 write_io = GetWriteIO(io);
6408 if (write_io != io)
6409 rb_io_ascii8bit_binmode(write_io);
6410 return io;
6411}
6412
6413/*
6414 * call-seq:
6415 * binmode? -> true or false
6416 *
6417 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6418 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6419 *
6420 */
6421static VALUE
6422rb_io_binmode_p(VALUE io)
6423{
6424 rb_io_t *fptr;
6425 GetOpenFile(io, fptr);
6426 return RBOOL(fptr->mode & FMODE_BINMODE);
6427}
6428
6429static const char*
6430rb_io_fmode_modestr(enum rb_io_mode fmode)
6431{
6432 if (fmode & FMODE_APPEND) {
6433 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6434 return MODE_BTMODE("a+", "ab+", "at+");
6435 }
6436 return MODE_BTMODE("a", "ab", "at");
6437 }
6438 switch (fmode & FMODE_READWRITE) {
6439 default:
6440 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6441 case FMODE_READABLE:
6442 return MODE_BTMODE("r", "rb", "rt");
6443 case FMODE_WRITABLE:
6444 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6445 case FMODE_READWRITE:
6446 if (fmode & FMODE_CREATE) {
6447 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6448 }
6449 return MODE_BTMODE("r+", "rb+", "rt+");
6450 }
6451}
6452
6453static const char bom_prefix[] = "bom|";
6454static const char utf_prefix[] = "utf-";
6455enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6456enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6457
6458static int
6459io_encname_bom_p(const char *name, long len)
6460{
6461 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6462}
6463
6464enum rb_io_mode
6465rb_io_modestr_fmode(const char *modestr)
6466{
6467 enum rb_io_mode fmode = 0;
6468 const char *m = modestr, *p = NULL;
6469
6470 switch (*m++) {
6471 case 'r':
6472 fmode |= FMODE_READABLE;
6473 break;
6474 case 'w':
6476 break;
6477 case 'a':
6479 break;
6480 default:
6481 goto error;
6482 }
6483
6484 while (*m) {
6485 switch (*m++) {
6486 case 'b':
6487 fmode |= FMODE_BINMODE;
6488 break;
6489 case 't':
6490 fmode |= FMODE_TEXTMODE;
6491 break;
6492 case '+':
6493 fmode |= FMODE_READWRITE;
6494 break;
6495 case 'x':
6496 if (modestr[0] != 'w')
6497 goto error;
6498 fmode |= FMODE_EXCL;
6499 break;
6500 default:
6501 goto error;
6502 case ':':
6503 p = strchr(m, ':');
6504 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6505 fmode |= FMODE_SETENC_BY_BOM;
6506 goto finished;
6507 }
6508 }
6509
6510 finished:
6511 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6512 goto error;
6513
6514 return fmode;
6515
6516 error:
6517 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6519}
6520
6521int
6522rb_io_oflags_fmode(int oflags)
6523{
6524 enum rb_io_mode fmode = 0;
6525
6526 switch (oflags & O_ACCMODE) {
6527 case O_RDONLY:
6528 fmode = FMODE_READABLE;
6529 break;
6530 case O_WRONLY:
6531 fmode = FMODE_WRITABLE;
6532 break;
6533 case O_RDWR:
6534 fmode = FMODE_READWRITE;
6535 break;
6536 }
6537
6538 if (oflags & O_APPEND) {
6539 fmode |= FMODE_APPEND;
6540 }
6541 if (oflags & O_TRUNC) {
6542 fmode |= FMODE_TRUNC;
6543 }
6544 if (oflags & O_CREAT) {
6545 fmode |= FMODE_CREATE;
6546 }
6547 if (oflags & O_EXCL) {
6548 fmode |= FMODE_EXCL;
6549 }
6550#ifdef O_BINARY
6551 if (oflags & O_BINARY) {
6552 fmode |= FMODE_BINMODE;
6553 }
6554#endif
6555
6556 return fmode;
6557}
6558
6559static int
6560rb_io_fmode_oflags(enum rb_io_mode fmode)
6561{
6562 int oflags = 0;
6563
6564 switch (fmode & FMODE_READWRITE) {
6565 case FMODE_READABLE:
6566 oflags |= O_RDONLY;
6567 break;
6568 case FMODE_WRITABLE:
6569 oflags |= O_WRONLY;
6570 break;
6571 case FMODE_READWRITE:
6572 oflags |= O_RDWR;
6573 break;
6574 }
6575
6576 if (fmode & FMODE_APPEND) {
6577 oflags |= O_APPEND;
6578 }
6579 if (fmode & FMODE_TRUNC) {
6580 oflags |= O_TRUNC;
6581 }
6582 if (fmode & FMODE_CREATE) {
6583 oflags |= O_CREAT;
6584 }
6585 if (fmode & FMODE_EXCL) {
6586 oflags |= O_EXCL;
6587 }
6588#ifdef O_BINARY
6589 if (fmode & FMODE_BINMODE) {
6590 oflags |= O_BINARY;
6591 }
6592#endif
6593
6594 return oflags;
6595}
6596
6597int
6598rb_io_modestr_oflags(const char *modestr)
6599{
6600 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6601}
6602
6603static const char*
6604rb_io_oflags_modestr(int oflags)
6605{
6606#ifdef O_BINARY
6607# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6608#else
6609# define MODE_BINARY(a,b) (a)
6610#endif
6611 int accmode;
6612 if (oflags & O_EXCL) {
6613 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6614 }
6615 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6616 if (oflags & O_APPEND) {
6617 if (accmode == O_WRONLY) {
6618 return MODE_BINARY("a", "ab");
6619 }
6620 if (accmode == O_RDWR) {
6621 return MODE_BINARY("a+", "ab+");
6622 }
6623 }
6624 switch (accmode) {
6625 default:
6626 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6627 case O_RDONLY:
6628 return MODE_BINARY("r", "rb");
6629 case O_WRONLY:
6630 return MODE_BINARY("w", "wb");
6631 case O_RDWR:
6632 if (oflags & O_TRUNC) {
6633 return MODE_BINARY("w+", "wb+");
6634 }
6635 return MODE_BINARY("r+", "rb+");
6636 }
6637}
6638
6639/*
6640 * Convert external/internal encodings to enc/enc2
6641 * NULL => use default encoding
6642 * Qnil => no encoding specified (internal only)
6643 */
6644static void
6645rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6646{
6647 int default_ext = 0;
6648
6649 if (ext == NULL) {
6650 ext = rb_default_external_encoding();
6651 default_ext = 1;
6652 }
6653 if (rb_is_ascii8bit_enc(ext)) {
6654 /* If external is ASCII-8BIT, no transcoding */
6655 intern = NULL;
6656 }
6657 else if (intern == NULL) {
6658 intern = rb_default_internal_encoding();
6659 }
6660 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6661 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6662 /* No internal encoding => use external + no transcoding */
6663 *enc = (default_ext && intern != ext) ? NULL : ext;
6664 *enc2 = NULL;
6665 }
6666 else {
6667 *enc = intern;
6668 *enc2 = ext;
6669 }
6670}
6671
6672static void
6673unsupported_encoding(const char *name, rb_encoding *enc)
6674{
6675 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6676}
6677
6678static void
6679parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6680 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6681{
6682 const char *p;
6683 char encname[ENCODING_MAXNAMELEN+1];
6684 int idx, idx2;
6685 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6686 rb_encoding *ext_enc, *int_enc;
6687 long len;
6688
6689 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6690
6691 p = strrchr(estr, ':');
6692 len = p ? (p++ - estr) : (long)strlen(estr);
6693 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6694 estr += bom_prefix_len;
6695 len -= bom_prefix_len;
6696 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6697 fmode |= FMODE_SETENC_BY_BOM;
6698 }
6699 else {
6700 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6701 fmode &= ~FMODE_SETENC_BY_BOM;
6702 }
6703 }
6704 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6705 idx = -1;
6706 }
6707 else {
6708 if (p) {
6709 memcpy(encname, estr, len);
6710 encname[len] = '\0';
6711 estr = encname;
6712 }
6713 idx = rb_enc_find_index(estr);
6714 }
6715 if (fmode_p) *fmode_p = fmode;
6716
6717 if (idx >= 0)
6718 ext_enc = rb_enc_from_index(idx);
6719 else {
6720 if (idx != -2)
6721 unsupported_encoding(estr, estr_enc);
6722 ext_enc = NULL;
6723 }
6724
6725 int_enc = NULL;
6726 if (p) {
6727 if (*p == '-' && *(p+1) == '\0') {
6728 /* Special case - "-" => no transcoding */
6729 int_enc = (rb_encoding *)Qnil;
6730 }
6731 else {
6732 idx2 = rb_enc_find_index(p);
6733 if (idx2 < 0)
6734 unsupported_encoding(p, estr_enc);
6735 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6736 int_enc = (rb_encoding *)Qnil;
6737 }
6738 else
6739 int_enc = rb_enc_from_index(idx2);
6740 }
6741 }
6742
6743 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6744}
6745
6746int
6747rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6748{
6749 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6750 int extracted = 0;
6751 rb_encoding *extencoding = NULL;
6752 rb_encoding *intencoding = NULL;
6753
6754 if (!NIL_P(opt)) {
6755 VALUE v;
6756 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6757 if (v != Qnil) encoding = v;
6758 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6759 if (v != Qnil) extenc = v;
6760 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6761 if (!UNDEF_P(v)) intenc = v;
6762 }
6763 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6764 if (!NIL_P(ruby_verbose)) {
6765 int idx = rb_to_encoding_index(encoding);
6766 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6767 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6768 encoding, UNDEF_P(extenc) ? "internal" : "external");
6769 }
6770 encoding = Qnil;
6771 }
6772 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6773 extencoding = rb_to_encoding(extenc);
6774 }
6775 if (!UNDEF_P(intenc)) {
6776 if (NIL_P(intenc)) {
6777 /* internal_encoding: nil => no transcoding */
6778 intencoding = (rb_encoding *)Qnil;
6779 }
6780 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6781 char *p = StringValueCStr(tmp);
6782
6783 if (*p == '-' && *(p+1) == '\0') {
6784 /* Special case - "-" => no transcoding */
6785 intencoding = (rb_encoding *)Qnil;
6786 }
6787 else {
6788 intencoding = rb_to_encoding(intenc);
6789 }
6790 }
6791 else {
6792 intencoding = rb_to_encoding(intenc);
6793 }
6794 if (extencoding == intencoding) {
6795 intencoding = (rb_encoding *)Qnil;
6796 }
6797 }
6798 if (!NIL_P(encoding)) {
6799 extracted = 1;
6800 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6801 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6802 enc_p, enc2_p, fmode_p);
6803 }
6804 else {
6805 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6806 }
6807 }
6808 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6809 extracted = 1;
6810 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6811 }
6812 return extracted;
6813}
6814
6815static void
6816validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6817{
6818 enum rb_io_mode fmode = *fmode_p;
6819
6820 if ((fmode & FMODE_READABLE) &&
6821 !enc2 &&
6822 !(fmode & FMODE_BINMODE) &&
6823 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6824 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6825
6826 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6827 rb_raise(rb_eArgError, "newline decorator with binary mode");
6828 }
6829 if (!(fmode & FMODE_BINMODE) &&
6830 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6831 fmode |= FMODE_TEXTMODE;
6832 *fmode_p = fmode;
6833 }
6834#if !DEFAULT_TEXTMODE
6835 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6836 fmode &= ~FMODE_TEXTMODE;
6837 *fmode_p = fmode;
6838 }
6839#endif
6840}
6841
6842static void
6843extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
6844{
6845 if (!NIL_P(opthash)) {
6846 VALUE v;
6847 v = rb_hash_aref(opthash, sym_textmode);
6848 if (!NIL_P(v)) {
6849 if (*fmode & FMODE_TEXTMODE)
6850 rb_raise(rb_eArgError, "textmode specified twice");
6851 if (*fmode & FMODE_BINMODE)
6852 rb_raise(rb_eArgError, "both textmode and binmode specified");
6853 if (RTEST(v))
6854 *fmode |= FMODE_TEXTMODE;
6855 }
6856 v = rb_hash_aref(opthash, sym_binmode);
6857 if (!NIL_P(v)) {
6858 if (*fmode & FMODE_BINMODE)
6859 rb_raise(rb_eArgError, "binmode specified twice");
6860 if (*fmode & FMODE_TEXTMODE)
6861 rb_raise(rb_eArgError, "both textmode and binmode specified");
6862 if (RTEST(v))
6863 *fmode |= FMODE_BINMODE;
6864 }
6865
6866 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6867 rb_raise(rb_eArgError, "both textmode and binmode specified");
6868 }
6869}
6870
6871void
6872rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6873 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
6874{
6875 VALUE vmode;
6876 int oflags;
6877 enum rb_io_mode fmode;
6878 rb_encoding *enc, *enc2;
6879 int ecflags;
6880 VALUE ecopts;
6881 int has_enc = 0, has_vmode = 0;
6882 VALUE intmode;
6883
6884 vmode = *vmode_p;
6885
6886 /* Set to defaults */
6887 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6888
6889 vmode_handle:
6890 if (NIL_P(vmode)) {
6891 fmode = FMODE_READABLE;
6892 oflags = O_RDONLY;
6893 }
6894 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6895 vmode = intmode;
6896 oflags = NUM2INT(intmode);
6897 fmode = rb_io_oflags_fmode(oflags);
6898 }
6899 else {
6900 const char *p;
6901
6902 StringValue(vmode);
6903 p = StringValueCStr(vmode);
6904 fmode = rb_io_modestr_fmode(p);
6905 oflags = rb_io_fmode_oflags(fmode);
6906 p = strchr(p, ':');
6907 if (p) {
6908 has_enc = 1;
6909 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6910 }
6911 else {
6912 rb_encoding *e;
6913
6914 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6915 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6916 }
6917 }
6918
6919 if (NIL_P(opthash)) {
6920 ecflags = (fmode & FMODE_READABLE) ?
6923#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6924 ecflags |= (fmode & FMODE_WRITABLE) ?
6925 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6926 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6927#endif
6928 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6929 ecopts = Qnil;
6930 if (fmode & FMODE_BINMODE) {
6931#ifdef O_BINARY
6932 oflags |= O_BINARY;
6933#endif
6934 if (!has_enc)
6935 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6936 }
6937#if DEFAULT_TEXTMODE
6938 else if (NIL_P(vmode)) {
6939 fmode |= DEFAULT_TEXTMODE;
6940 }
6941#endif
6942 }
6943 else {
6944 VALUE v;
6945 if (!has_vmode) {
6946 v = rb_hash_aref(opthash, sym_mode);
6947 if (!NIL_P(v)) {
6948 if (!NIL_P(vmode)) {
6949 rb_raise(rb_eArgError, "mode specified twice");
6950 }
6951 has_vmode = 1;
6952 vmode = v;
6953 goto vmode_handle;
6954 }
6955 }
6956 v = rb_hash_aref(opthash, sym_flags);
6957 if (!NIL_P(v)) {
6958 v = rb_to_int(v);
6959 oflags |= NUM2INT(v);
6960 vmode = INT2NUM(oflags);
6961 fmode = rb_io_oflags_fmode(oflags);
6962 }
6963 extract_binmode(opthash, &fmode);
6964 if (fmode & FMODE_BINMODE) {
6965#ifdef O_BINARY
6966 oflags |= O_BINARY;
6967#endif
6968 if (!has_enc)
6969 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6970 }
6971#if DEFAULT_TEXTMODE
6972 else if (NIL_P(vmode)) {
6973 fmode |= DEFAULT_TEXTMODE;
6974 }
6975#endif
6976 v = rb_hash_aref(opthash, sym_perm);
6977 if (!NIL_P(v)) {
6978 if (vperm_p) {
6979 if (!NIL_P(*vperm_p)) {
6980 rb_raise(rb_eArgError, "perm specified twice");
6981 }
6982 *vperm_p = v;
6983 }
6984 else {
6985 /* perm no use, just ignore */
6986 }
6987 }
6988 ecflags = (fmode & FMODE_READABLE) ?
6991#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6992 ecflags |= (fmode & FMODE_WRITABLE) ?
6993 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6994 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6995#endif
6996
6997 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6998 if (has_enc) {
6999 rb_raise(rb_eArgError, "encoding specified twice");
7000 }
7001 }
7002 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7003 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7004 }
7005
7006 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7007
7008 *vmode_p = vmode;
7009
7010 *oflags_p = oflags;
7011 *fmode_p = fmode;
7012 convconfig_p->enc = enc;
7013 convconfig_p->enc2 = enc2;
7014 convconfig_p->ecflags = ecflags;
7015 convconfig_p->ecopts = ecopts;
7016}
7017
7019 VALUE fname;
7020 int oflags;
7021 mode_t perm;
7022};
7023
7024static void *
7025sysopen_func(void *ptr)
7026{
7027 const struct sysopen_struct *data = ptr;
7028 const char *fname = RSTRING_PTR(data->fname);
7029 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7030}
7031
7032static inline int
7033rb_sysopen_internal(struct sysopen_struct *data)
7034{
7035 int fd;
7036 do {
7037 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7038 } while (fd < 0 && errno == EINTR);
7039 if (0 <= fd)
7040 rb_update_max_fd(fd);
7041 return fd;
7042}
7043
7044static int
7045rb_sysopen(VALUE fname, int oflags, mode_t perm)
7046{
7047 int fd = -1;
7048 struct sysopen_struct data;
7049
7050 data.fname = rb_str_encode_ospath(fname);
7051 StringValueCStr(data.fname);
7052 data.oflags = oflags;
7053 data.perm = perm;
7054
7055 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7056 rb_syserr_fail_path(first_errno, fname);
7057 }
7058 return fd;
7059}
7060
7061static inline FILE *
7062fdopen_internal(int fd, const char *modestr)
7063{
7064 FILE *file;
7065
7066#if defined(__sun)
7067 errno = 0;
7068#endif
7069 file = fdopen(fd, modestr);
7070 if (!file) {
7071#ifdef _WIN32
7072 if (errno == 0) errno = EINVAL;
7073#elif defined(__sun)
7074 if (errno == 0) errno = EMFILE;
7075#endif
7076 }
7077 return file;
7078}
7079
7080FILE *
7081rb_fdopen(int fd, const char *modestr)
7082{
7083 FILE *file = 0;
7084
7085 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7086 rb_syserr_fail(first_errno, 0);
7087 }
7088
7089 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7090#ifdef USE_SETVBUF
7091 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7092 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7093#endif
7094 return file;
7095}
7096
7097static int
7098io_check_tty(rb_io_t *fptr)
7099{
7100 int t = isatty(fptr->fd);
7101 if (t)
7102 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7103 return t;
7104}
7105
7106static VALUE rb_io_internal_encoding(VALUE);
7107static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7108
7109static int
7110io_strip_bom(VALUE io)
7111{
7112 VALUE b1, b2, b3, b4;
7113 rb_io_t *fptr;
7114
7115 GetOpenFile(io, fptr);
7116 if (!(fptr->mode & FMODE_READABLE)) return 0;
7117 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7118 switch (b1) {
7119 case INT2FIX(0xEF):
7120 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7121 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7122 if (b3 == INT2FIX(0xBF)) {
7123 return rb_utf8_encindex();
7124 }
7125 rb_io_ungetbyte(io, b3);
7126 }
7127 rb_io_ungetbyte(io, b2);
7128 break;
7129
7130 case INT2FIX(0xFE):
7131 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7132 if (b2 == INT2FIX(0xFF)) {
7133 return ENCINDEX_UTF_16BE;
7134 }
7135 rb_io_ungetbyte(io, b2);
7136 break;
7137
7138 case INT2FIX(0xFF):
7139 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7140 if (b2 == INT2FIX(0xFE)) {
7141 b3 = rb_io_getbyte(io);
7142 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7143 if (b4 == INT2FIX(0)) {
7144 return ENCINDEX_UTF_32LE;
7145 }
7146 rb_io_ungetbyte(io, b4);
7147 }
7148 rb_io_ungetbyte(io, b3);
7149 return ENCINDEX_UTF_16LE;
7150 }
7151 rb_io_ungetbyte(io, b2);
7152 break;
7153
7154 case INT2FIX(0):
7155 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7156 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7157 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7158 if (b4 == INT2FIX(0xFF)) {
7159 return ENCINDEX_UTF_32BE;
7160 }
7161 rb_io_ungetbyte(io, b4);
7162 }
7163 rb_io_ungetbyte(io, b3);
7164 }
7165 rb_io_ungetbyte(io, b2);
7166 break;
7167 }
7168 rb_io_ungetbyte(io, b1);
7169 return 0;
7170}
7171
7172static rb_encoding *
7173io_set_encoding_by_bom(VALUE io)
7174{
7175 int idx = io_strip_bom(io);
7176 rb_io_t *fptr;
7177 rb_encoding *extenc = NULL;
7178
7179 GetOpenFile(io, fptr);
7180 if (idx) {
7181 extenc = rb_enc_from_index(idx);
7182 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7183 rb_io_internal_encoding(io), Qnil);
7184 }
7185 else {
7186 fptr->encs.enc2 = NULL;
7187 }
7188 return extenc;
7189}
7190
7191static VALUE
7192rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7193 const struct rb_io_encoding *convconfig, mode_t perm)
7194{
7195 VALUE pathv;
7196 rb_io_t *fptr;
7197 struct rb_io_encoding cc;
7198 if (!convconfig) {
7199 /* Set to default encodings */
7200 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7201 cc.ecflags = 0;
7202 cc.ecopts = Qnil;
7203 convconfig = &cc;
7204 }
7205 validate_enc_binmode(&fmode, convconfig->ecflags,
7206 convconfig->enc, convconfig->enc2);
7207
7208 MakeOpenFile(io, fptr);
7209 fptr->mode = fmode;
7210 fptr->encs = *convconfig;
7211 pathv = rb_str_new_frozen(filename);
7212#ifdef O_TMPFILE
7213 if (!(oflags & O_TMPFILE)) {
7214 fptr->pathv = pathv;
7215 }
7216#else
7217 fptr->pathv = pathv;
7218#endif
7219 fptr->fd = rb_sysopen(pathv, oflags, perm);
7220 io_check_tty(fptr);
7221 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7222
7223 return io;
7224}
7225
7226static VALUE
7227rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7228{
7229 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7230 const char *p = strchr(modestr, ':');
7231 struct rb_io_encoding convconfig;
7232
7233 if (p) {
7234 parse_mode_enc(p+1, rb_usascii_encoding(),
7235 &convconfig.enc, &convconfig.enc2, &fmode);
7236 }
7237 else {
7238 rb_encoding *e;
7239 /* Set to default encodings */
7240
7241 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7242 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7243 }
7244
7245 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7248#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7249 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7250 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7251 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7252#endif
7253 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7254 convconfig.ecopts = Qnil;
7255
7256 return rb_file_open_generic(io, filename,
7257 rb_io_fmode_oflags(fmode),
7258 fmode,
7259 &convconfig,
7260 0666);
7261}
7262
7263VALUE
7264rb_file_open_str(VALUE fname, const char *modestr)
7265{
7266 FilePathValue(fname);
7267 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7268}
7269
7270VALUE
7271rb_file_open(const char *fname, const char *modestr)
7272{
7273 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7274}
7275
7276#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7277static struct pipe_list {
7278 rb_io_t *fptr;
7279 struct pipe_list *next;
7280} *pipe_list;
7281
7282static void
7283pipe_add_fptr(rb_io_t *fptr)
7284{
7285 struct pipe_list *list;
7286
7287 list = ALLOC(struct pipe_list);
7288 list->fptr = fptr;
7289 list->next = pipe_list;
7290 pipe_list = list;
7291}
7292
7293static void
7294pipe_del_fptr(rb_io_t *fptr)
7295{
7296 struct pipe_list **prev = &pipe_list;
7297 struct pipe_list *tmp;
7298
7299 while ((tmp = *prev) != 0) {
7300 if (tmp->fptr == fptr) {
7301 *prev = tmp->next;
7302 free(tmp);
7303 return;
7304 }
7305 prev = &tmp->next;
7306 }
7307}
7308
7309#if defined (_WIN32) || defined(__CYGWIN__)
7310static void
7311pipe_atexit(void)
7312{
7313 struct pipe_list *list = pipe_list;
7314 struct pipe_list *tmp;
7315
7316 while (list) {
7317 tmp = list->next;
7318 rb_io_fptr_finalize(list->fptr);
7319 list = tmp;
7320 }
7321}
7322#endif
7323
7324static void
7325pipe_finalize(rb_io_t *fptr, int noraise)
7326{
7327#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7328 int status = 0;
7329 if (fptr->stdio_file) {
7330 status = pclose(fptr->stdio_file);
7331 }
7332 fptr->fd = -1;
7333 fptr->stdio_file = 0;
7334 rb_last_status_set(status, fptr->pid);
7335#else
7336 fptr_finalize(fptr, noraise);
7337#endif
7338 pipe_del_fptr(fptr);
7339}
7340#endif
7341
7342static void
7343fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7344{
7345#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7346 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7347
7348 if (old_finalize == orig->finalize) return;
7349#endif
7350
7351 fptr->finalize = orig->finalize;
7352
7353#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7354 if (old_finalize != pipe_finalize) {
7355 struct pipe_list *list;
7356 for (list = pipe_list; list; list = list->next) {
7357 if (list->fptr == fptr) break;
7358 }
7359 if (!list) pipe_add_fptr(fptr);
7360 }
7361 else {
7362 pipe_del_fptr(fptr);
7363 }
7364#endif
7365}
7366
7367void
7369{
7371 fptr->mode |= FMODE_SYNC;
7372}
7373
7374void
7375rb_io_unbuffered(rb_io_t *fptr)
7376{
7377 rb_io_synchronized(fptr);
7378}
7379
7380int
7381rb_pipe(int *pipes)
7382{
7383 int ret;
7384 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7385 if (ret == 0) {
7386 rb_update_max_fd(pipes[0]);
7387 rb_update_max_fd(pipes[1]);
7388 }
7389 return ret;
7390}
7391
7392#ifdef _WIN32
7393#define HAVE_SPAWNV 1
7394#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7395#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7396#endif
7397
7398#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7399struct popen_arg {
7400 VALUE execarg_obj;
7401 struct rb_execarg *eargp;
7402 int modef;
7403 int pair[2];
7404 int write_pair[2];
7405};
7406#endif
7407
7408#ifdef HAVE_WORKING_FORK
7409# ifndef __EMSCRIPTEN__
7410static void
7411popen_redirect(struct popen_arg *p)
7412{
7413 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7414 close(p->write_pair[1]);
7415 if (p->write_pair[0] != 0) {
7416 dup2(p->write_pair[0], 0);
7417 close(p->write_pair[0]);
7418 }
7419 close(p->pair[0]);
7420 if (p->pair[1] != 1) {
7421 dup2(p->pair[1], 1);
7422 close(p->pair[1]);
7423 }
7424 }
7425 else if (p->modef & FMODE_READABLE) {
7426 close(p->pair[0]);
7427 if (p->pair[1] != 1) {
7428 dup2(p->pair[1], 1);
7429 close(p->pair[1]);
7430 }
7431 }
7432 else {
7433 close(p->pair[1]);
7434 if (p->pair[0] != 0) {
7435 dup2(p->pair[0], 0);
7436 close(p->pair[0]);
7437 }
7438 }
7439}
7440# endif
7441
7442#if defined(__linux__)
7443/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7444 * Since /proc may not be available, linux_get_maxfd is just a hint.
7445 * This function, linux_get_maxfd, must be async-signal-safe.
7446 * I.e. opendir() is not usable.
7447 *
7448 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7449 * However they are easy to re-implement in async-signal-safe manner.
7450 * (Also note that there is missing/memcmp.c.)
7451 */
7452static int
7453linux_get_maxfd(void)
7454{
7455 int fd;
7456 char buf[4096], *p, *np, *e;
7457 ssize_t ss;
7458 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7459 if (fd < 0) return fd;
7460 ss = read(fd, buf, sizeof(buf));
7461 if (ss < 0) goto err;
7462 p = buf;
7463 e = buf + ss;
7464 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7465 (np = memchr(p, '\n', e-p)) != NULL) {
7466 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7467 int fdsize;
7468 p += sizeof("FDSize:")-1;
7469 *np = '\0';
7470 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7471 close(fd);
7472 return fdsize;
7473 }
7474 p = np+1;
7475 }
7476 /* fall through */
7477
7478 err:
7479 close(fd);
7480 return (int)ss;
7481}
7482#endif
7483
7484/* This function should be async-signal-safe. */
7485void
7486rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7487{
7488#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7489 int fd, ret;
7490 int max = (int)max_file_descriptor;
7491# ifdef F_MAXFD
7492 /* F_MAXFD is available since NetBSD 2.0. */
7493 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7494 if (ret != -1)
7495 maxhint = max = ret;
7496# elif defined(__linux__)
7497 ret = linux_get_maxfd();
7498 if (maxhint < ret)
7499 maxhint = ret;
7500 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7501# endif
7502 if (max < maxhint)
7503 max = maxhint;
7504 for (fd = lowfd; fd <= max; fd++) {
7505 if (!NIL_P(noclose_fds) &&
7506 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7507 continue;
7508 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7509 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7510 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7511 }
7512# define CONTIGUOUS_CLOSED_FDS 20
7513 if (ret != -1) {
7514 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7515 max = fd + CONTIGUOUS_CLOSED_FDS;
7516 }
7517 }
7518#endif
7519}
7520
7521# ifndef __EMSCRIPTEN__
7522static int
7523popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7524{
7525 struct popen_arg *p = (struct popen_arg*)pp;
7526
7527 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7528}
7529# endif
7530#endif
7531
7532#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7533static VALUE
7534rb_execarg_fixup_v(VALUE execarg_obj)
7535{
7536 rb_execarg_parent_start(execarg_obj);
7537 return Qnil;
7538}
7539#else
7540char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7541#endif
7542
7543#ifndef __EMSCRIPTEN__
7544static VALUE
7545pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7546 const struct rb_io_encoding *convconfig)
7547{
7548 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7549 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7550 rb_pid_t pid = 0;
7551 rb_io_t *fptr;
7552 VALUE port;
7553 rb_io_t *write_fptr;
7554 VALUE write_port;
7555#if defined(HAVE_WORKING_FORK)
7556 int status;
7557 char errmsg[80] = { '\0' };
7558#endif
7559#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7560 int state;
7561 struct popen_arg arg;
7562#endif
7563 int e = 0;
7564#if defined(HAVE_SPAWNV)
7565# if defined(HAVE_SPAWNVE)
7566# define DO_SPAWN(cmd, args, envp) ((args) ? \
7567 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7568 spawne(P_NOWAIT, (cmd), (envp)))
7569# else
7570# define DO_SPAWN(cmd, args, envp) ((args) ? \
7571 spawnv(P_NOWAIT, (cmd), (args)) : \
7572 spawn(P_NOWAIT, (cmd)))
7573# endif
7574# if !defined(HAVE_WORKING_FORK)
7575 char **args = NULL;
7576# if defined(HAVE_SPAWNVE)
7577 char **envp = NULL;
7578# endif
7579# endif
7580#endif
7581#if !defined(HAVE_WORKING_FORK)
7582 struct rb_execarg sarg, *sargp = &sarg;
7583#endif
7584 FILE *fp = 0;
7585 int fd = -1;
7586 int write_fd = -1;
7587#if !defined(HAVE_WORKING_FORK)
7588 const char *cmd = 0;
7589
7590 if (prog)
7591 cmd = StringValueCStr(prog);
7592#endif
7593
7594#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7595 arg.execarg_obj = execarg_obj;
7596 arg.eargp = eargp;
7597 arg.modef = fmode;
7598 arg.pair[0] = arg.pair[1] = -1;
7599 arg.write_pair[0] = arg.write_pair[1] = -1;
7600# if !defined(HAVE_WORKING_FORK)
7601 if (eargp && !eargp->use_shell) {
7602 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7603 }
7604# endif
7605 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7607 if (rb_pipe(arg.write_pair) < 0)
7608 rb_sys_fail_str(prog);
7609 if (rb_pipe(arg.pair) < 0) {
7610 e = errno;
7611 close(arg.write_pair[0]);
7612 close(arg.write_pair[1]);
7613 rb_syserr_fail_str(e, prog);
7614 }
7615 if (eargp) {
7616 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7617 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7618 }
7619 break;
7620 case FMODE_READABLE:
7621 if (rb_pipe(arg.pair) < 0)
7622 rb_sys_fail_str(prog);
7623 if (eargp)
7624 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7625 break;
7626 case FMODE_WRITABLE:
7627 if (rb_pipe(arg.pair) < 0)
7628 rb_sys_fail_str(prog);
7629 if (eargp)
7630 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7631 break;
7632 default:
7633 rb_sys_fail_str(prog);
7634 }
7635 if (!NIL_P(execarg_obj)) {
7636 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7637 if (state) {
7638 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7639 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7640 if (0 <= arg.pair[0]) close(arg.pair[0]);
7641 if (0 <= arg.pair[1]) close(arg.pair[1]);
7642 rb_execarg_parent_end(execarg_obj);
7643 rb_jump_tag(state);
7644 }
7645
7646# if defined(HAVE_WORKING_FORK)
7647 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7648# else
7649 rb_execarg_run_options(eargp, sargp, NULL, 0);
7650# if defined(HAVE_SPAWNVE)
7651 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7652# endif
7653 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7654 /* exec failed */
7655 switch (e = errno) {
7656 case EAGAIN:
7657# if EWOULDBLOCK != EAGAIN
7658 case EWOULDBLOCK:
7659# endif
7660 rb_thread_sleep(1);
7661 continue;
7662 }
7663 break;
7664 }
7665 if (eargp)
7666 rb_execarg_run_options(sargp, NULL, NULL, 0);
7667# endif
7668 rb_execarg_parent_end(execarg_obj);
7669 }
7670 else {
7671# if defined(HAVE_WORKING_FORK)
7672 pid = rb_call_proc__fork();
7673 if (pid == 0) { /* child */
7674 popen_redirect(&arg);
7675 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7676 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7677 return Qnil;
7678 }
7679# else
7681# endif
7682 }
7683
7684 /* parent */
7685 if (pid < 0) {
7686# if defined(HAVE_WORKING_FORK)
7687 e = errno;
7688# endif
7689 close(arg.pair[0]);
7690 close(arg.pair[1]);
7692 close(arg.write_pair[0]);
7693 close(arg.write_pair[1]);
7694 }
7695# if defined(HAVE_WORKING_FORK)
7696 if (errmsg[0])
7697 rb_syserr_fail(e, errmsg);
7698# endif
7699 rb_syserr_fail_str(e, prog);
7700 }
7701 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7702 close(arg.pair[1]);
7703 fd = arg.pair[0];
7704 close(arg.write_pair[0]);
7705 write_fd = arg.write_pair[1];
7706 }
7707 else if (fmode & FMODE_READABLE) {
7708 close(arg.pair[1]);
7709 fd = arg.pair[0];
7710 }
7711 else {
7712 close(arg.pair[0]);
7713 fd = arg.pair[1];
7714 }
7715#else
7716 cmd = rb_execarg_commandline(eargp, &prog);
7717 if (!NIL_P(execarg_obj)) {
7718 rb_execarg_parent_start(execarg_obj);
7719 rb_execarg_run_options(eargp, sargp, NULL, 0);
7720 }
7721 fp = popen(cmd, modestr);
7722 e = errno;
7723 if (eargp) {
7724 rb_execarg_parent_end(execarg_obj);
7725 rb_execarg_run_options(sargp, NULL, NULL, 0);
7726 }
7727 if (!fp) rb_syserr_fail_path(e, prog);
7728 fd = fileno(fp);
7729#endif
7730
7731 port = io_alloc(rb_cIO);
7732 MakeOpenFile(port, fptr);
7733 fptr->fd = fd;
7734 fptr->stdio_file = fp;
7735 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7736 if (convconfig) {
7737 fptr->encs = *convconfig;
7738#if RUBY_CRLF_ENVIRONMENT
7741 }
7742#endif
7743 }
7744 else {
7745 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7747 }
7748#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7749 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7750 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7751 }
7752#endif
7753 }
7754 fptr->pid = pid;
7755
7756 if (0 <= write_fd) {
7757 write_port = io_alloc(rb_cIO);
7758 MakeOpenFile(write_port, write_fptr);
7759 write_fptr->fd = write_fd;
7760 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7761 fptr->mode &= ~FMODE_WRITABLE;
7762 fptr->tied_io_for_writing = write_port;
7763 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7764 }
7765
7766#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7767 fptr->finalize = pipe_finalize;
7768 pipe_add_fptr(fptr);
7769#endif
7770 return port;
7771}
7772#else
7773static VALUE
7774pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7775 const struct rb_io_encoding *convconfig)
7776{
7777 rb_raise(rb_eNotImpError, "popen() is not available");
7778}
7779#endif
7780
7781static int
7782is_popen_fork(VALUE prog)
7783{
7784 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7785#if !defined(HAVE_WORKING_FORK)
7786 rb_raise(rb_eNotImpError,
7787 "fork() function is unimplemented on this machine");
7788#else
7789 return TRUE;
7790#endif
7791 }
7792 return FALSE;
7793}
7794
7795static VALUE
7796pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
7797 const struct rb_io_encoding *convconfig)
7798{
7799 int argc = 1;
7800 VALUE *argv = &prog;
7801 VALUE execarg_obj = Qnil;
7802
7803 if (!is_popen_fork(prog))
7804 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7805 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7806}
7807
7808static VALUE
7809pipe_close(VALUE io)
7810{
7811 rb_io_t *fptr = io_close_fptr(io);
7812 if (fptr) {
7813 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7814 }
7815 return Qnil;
7816}
7817
7818static VALUE popen_finish(VALUE port, VALUE klass);
7819
7820/*
7821 * call-seq:
7822 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7823 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7824 *
7825 * Executes the given command +cmd+ as a subprocess
7826 * whose $stdin and $stdout are connected to a new stream +io+.
7827 *
7828 * This method has potential security vulnerabilities if called with untrusted input;
7829 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
7830 *
7831 * If no block is given, returns the new stream,
7832 * which depending on given +mode+ may be open for reading, writing, or both.
7833 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7834 *
7835 * If a block is given, the stream is passed to the block
7836 * (again, open for reading, writing, or both);
7837 * when the block exits, the stream is closed,
7838 * and the block's value is assigned to global variable <tt>$?</tt> and returned.
7839 *
7840 * Optional argument +mode+ may be any valid \IO mode.
7841 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7842 *
7843 * Required argument +cmd+ determines which of the following occurs:
7844 *
7845 * - The process forks.
7846 * - A specified program runs in a shell.
7847 * - A specified program runs with specified arguments.
7848 * - A specified program runs with specified arguments and a specified +argv0+.
7849 *
7850 * Each of these is detailed below.
7851 *
7852 * The optional hash argument +env+ specifies name/value pairs that are to be added
7853 * to the environment variables for the subprocess:
7854 *
7855 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7856 * pipe.puts 'puts ENV["FOO"]'
7857 * pipe.close_write
7858 * pipe.gets
7859 * end => "bar\n"
7860 *
7861 * Optional keyword arguments +opts+ specify:
7862 *
7863 * - {Open options}[rdoc-ref:IO@Open+Options].
7864 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7865 * - Options for Kernel#spawn.
7866 *
7867 * <b>Forked Process</b>
7868 *
7869 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7870 * IO.popen('-') do |pipe|
7871 * if pipe
7872 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7873 * else
7874 * $stderr.puts "In child, pid is #{$$}\n"
7875 * end
7876 * end
7877 *
7878 * Output:
7879 *
7880 * In parent, child pid is 26253
7881 * In child, pid is 26253
7882 *
7883 * Note that this is not supported on all platforms.
7884 *
7885 * <b>Shell Subprocess</b>
7886 *
7887 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7888 * the program named +cmd+ is run as a shell command:
7889 *
7890 * IO.popen('uname') do |pipe|
7891 * pipe.readlines
7892 * end
7893 *
7894 * Output:
7895 *
7896 * ["Linux\n"]
7897 *
7898 * Another example:
7899 *
7900 * IO.popen('/bin/sh', 'r+') do |pipe|
7901 * pipe.puts('ls')
7902 * pipe.close_write
7903 * $stderr.puts pipe.readlines.size
7904 * end
7905 *
7906 * Output:
7907 *
7908 * 213
7909 *
7910 * <b>Program Subprocess</b>
7911 *
7912 * When argument +cmd+ is an array of strings,
7913 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7914 *
7915 * IO.popen(['du', '..', '.']) do |pipe|
7916 * $stderr.puts pipe.readlines.size
7917 * end
7918 *
7919 * Output:
7920 *
7921 * 1111
7922 *
7923 * <b>Program Subprocess with <tt>argv0</tt></b>
7924 *
7925 * When argument +cmd+ is an array whose first element is a 2-element string array
7926 * and whose remaining elements (if any) are strings:
7927 *
7928 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7929 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7930 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7931 *
7932 * Example (sets <tt>$0</tt> to 'foo'):
7933 *
7934 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7935 *
7936 * <b>Some Special Examples</b>
7937 *
7938 * # Set IO encoding.
7939 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7940 * euc_jp_string = nkf_io.read
7941 * }
7942 *
7943 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7944 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7945 * ls_result_with_error = io.read
7946 * end
7947 *
7948 * # Use mixture of spawn options and IO options.
7949 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7950 * ls_result_with_error = io.read
7951 * end
7952 *
7953 * f = IO.popen("uname")
7954 * p f.readlines
7955 * f.close
7956 * puts "Parent is #{Process.pid}"
7957 * IO.popen("date") {|f| puts f.gets }
7958 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7959 * p $?
7960 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7961 * f.puts "bar"; f.close_write; puts f.gets
7962 * }
7963 *
7964 * Output (from last section):
7965 *
7966 * ["Linux\n"]
7967 * Parent is 21346
7968 * Thu Jan 15 22:41:19 JST 2009
7969 * 21346 is here, f is #<IO:fd 3>
7970 * 21352 is here, f is nil
7971 * #<Process::Status: pid 21352 exit 0>
7972 * <foo>bar;zot;
7973 *
7974 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7975 *
7976 */
7977
7978static VALUE
7979rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7980{
7981 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7982
7983 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7984 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7985 switch (argc) {
7986 case 2:
7987 pmode = argv[1];
7988 case 1:
7989 pname = argv[0];
7990 break;
7991 default:
7992 {
7993 int ex = !NIL_P(opt);
7994 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7995 }
7996 }
7997 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7998}
7999
8000VALUE
8001rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8002{
8003 const char *modestr;
8004 VALUE tmp, execarg_obj = Qnil;
8005 int oflags;
8006 enum rb_io_mode fmode;
8007 struct rb_io_encoding convconfig;
8008
8009 tmp = rb_check_array_type(pname);
8010 if (!NIL_P(tmp)) {
8011 long len = RARRAY_LEN(tmp);
8012#if SIZEOF_LONG > SIZEOF_INT
8013 if (len > INT_MAX) {
8014 rb_raise(rb_eArgError, "too many arguments");
8015 }
8016#endif
8017 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8018 RB_GC_GUARD(tmp);
8019 }
8020 else {
8021 StringValue(pname);
8022 execarg_obj = Qnil;
8023 if (!is_popen_fork(pname))
8024 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8025 }
8026 if (!NIL_P(execarg_obj)) {
8027 if (!NIL_P(opt))
8028 opt = rb_execarg_extract_options(execarg_obj, opt);
8029 if (!NIL_P(env))
8030 rb_execarg_setenv(execarg_obj, env);
8031 }
8032 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8033 modestr = rb_io_oflags_modestr(oflags);
8034
8035 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8036}
8037
8038static VALUE
8039popen_finish(VALUE port, VALUE klass)
8040{
8041 if (NIL_P(port)) {
8042 /* child */
8043 if (rb_block_given_p()) {
8044 rb_protect(rb_yield, Qnil, NULL);
8045 rb_io_flush(rb_ractor_stdout());
8046 rb_io_flush(rb_ractor_stderr());
8047 _exit(0);
8048 }
8049 return Qnil;
8050 }
8051 RBASIC_SET_CLASS(port, klass);
8052 if (rb_block_given_p()) {
8053 return rb_ensure(rb_yield, port, pipe_close, port);
8054 }
8055 return port;
8056}
8057
8058#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8059struct popen_writer_arg {
8060 char *const *argv;
8061 struct popen_arg popen;
8062};
8063
8064static int
8065exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8066{
8067 struct popen_writer_arg *pw = arg;
8068 pw->popen.modef = FMODE_WRITABLE;
8069 popen_redirect(&pw->popen);
8070 execv(pw->argv[0], pw->argv);
8071 strlcpy(errmsg, strerror(errno), buflen);
8072 return -1;
8073}
8074#endif
8075
8076FILE *
8077ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8078{
8079#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8080# ifdef HAVE_WORKING_FORK
8081 struct popen_writer_arg pw;
8082 int *const write_pair = pw.popen.pair;
8083# else
8084 int write_pair[2];
8085# endif
8086
8087 int result = rb_cloexec_pipe(write_pair);
8088 *pid = -1;
8089 if (result == 0) {
8090# ifdef HAVE_WORKING_FORK
8091 pw.argv = argv;
8092 int status;
8093 char errmsg[80] = {'\0'};
8094 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8095# else
8096 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8097 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8098# endif
8099 close(write_pair[0]);
8100 if (*pid < 0) {
8101 close(write_pair[1]);
8102 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8103 }
8104 else {
8105 return fdopen(write_pair[1], "w");
8106 }
8107 }
8108#endif
8109 return NULL;
8110}
8111
8112static VALUE
8113rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8114{
8115 int oflags;
8116 enum rb_io_mode fmode;
8117 struct rb_io_encoding convconfig;
8118 mode_t perm;
8119
8120 FilePathValue(fname);
8121
8122 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8123 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8124
8125 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8126
8127 return io;
8128}
8129
8130/*
8131 * Document-method: File::open
8132 *
8133 * call-seq:
8134 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8135 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8136 *
8137 * Creates a new File object, via File.new with the given arguments.
8138 *
8139 * With no block given, returns the File object.
8140 *
8141 * With a block given, calls the block with the File object
8142 * and returns the block's value.
8143 *
8144 */
8145
8146/*
8147 * Document-method: IO::open
8148 *
8149 * call-seq:
8150 * IO.open(fd, mode = 'r', **opts) -> io
8151 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8152 *
8153 * Creates a new \IO object, via IO.new with the given arguments.
8154 *
8155 * With no block given, returns the \IO object.
8156 *
8157 * With a block given, calls the block with the \IO object
8158 * and returns the block's value.
8159 *
8160 */
8161
8162static VALUE
8163rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8164{
8166
8167 if (rb_block_given_p()) {
8168 return rb_ensure(rb_yield, io, io_close, io);
8169 }
8170
8171 return io;
8172}
8173
8174/*
8175 * call-seq:
8176 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8177 *
8178 * Opens the file at the given path with the given mode and permissions;
8179 * returns the integer file descriptor.
8180 *
8181 * If the file is to be readable, it must exist;
8182 * if the file is to be writable and does not exist,
8183 * it is created with the given permissions:
8184 *
8185 * File.write('t.tmp', '') # => 0
8186 * IO.sysopen('t.tmp') # => 8
8187 * IO.sysopen('t.tmp', 'w') # => 9
8188 *
8189 *
8190 */
8191
8192static VALUE
8193rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8194{
8195 VALUE fname, vmode, vperm;
8196 VALUE intmode;
8197 int oflags, fd;
8198 mode_t perm;
8199
8200 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8201 FilePathValue(fname);
8202
8203 if (NIL_P(vmode))
8204 oflags = O_RDONLY;
8205 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8206 oflags = NUM2INT(intmode);
8207 else {
8208 StringValue(vmode);
8209 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8210 }
8211 if (NIL_P(vperm)) perm = 0666;
8212 else perm = NUM2MODET(vperm);
8213
8214 RB_GC_GUARD(fname) = rb_str_new4(fname);
8215 fd = rb_sysopen(fname, oflags, perm);
8216 return INT2NUM(fd);
8217}
8218
8219static VALUE
8220check_pipe_command(VALUE filename_or_command)
8221{
8222 char *s = RSTRING_PTR(filename_or_command);
8223 long l = RSTRING_LEN(filename_or_command);
8224 char *e = s + l;
8225 int chlen;
8226
8227 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8228 VALUE cmd = rb_str_new(s+chlen, l-chlen);
8229 return cmd;
8230 }
8231 return Qnil;
8232}
8233
8234/*
8235 * call-seq:
8236 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8237 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8238 *
8239 * Creates an IO object connected to the given file.
8240 *
8241 * This method has potential security vulnerabilities if called with untrusted input;
8242 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
8243 *
8244 * With no block given, file stream is returned:
8245 *
8246 * open('t.txt') # => #<File:t.txt>
8247 *
8248 * With a block given, calls the block with the open file stream,
8249 * then closes the stream:
8250 *
8251 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8252 *
8253 * Output:
8254 *
8255 * #<File:t.txt>
8256 *
8257 * See File.open for details.
8258 *
8259 */
8260
8261static VALUE
8262rb_f_open(int argc, VALUE *argv, VALUE _)
8263{
8264 ID to_open = 0;
8265 int redirect = FALSE;
8266
8267 if (argc >= 1) {
8268 CONST_ID(to_open, "to_open");
8269 if (rb_respond_to(argv[0], to_open)) {
8270 redirect = TRUE;
8271 }
8272 else {
8273 VALUE tmp = argv[0];
8274 FilePathValue(tmp);
8275 if (NIL_P(tmp)) {
8276 redirect = TRUE;
8277 }
8278 else {
8279 VALUE cmd = check_pipe_command(tmp);
8280 if (!NIL_P(cmd)) {
8281 // TODO: when removed in 4.0, update command_injection.rdoc
8282 rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen");
8283 argv[0] = cmd;
8284 return rb_io_s_popen(argc, argv, rb_cIO);
8285 }
8286 }
8287 }
8288 }
8289 if (redirect) {
8290 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8291
8292 if (rb_block_given_p()) {
8293 return rb_ensure(rb_yield, io, io_close, io);
8294 }
8295 return io;
8296 }
8297 return rb_io_s_open(argc, argv, rb_cFile);
8298}
8299
8300static VALUE
8301rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8302 const struct rb_io_encoding *convconfig, mode_t perm)
8303{
8304 VALUE cmd;
8305 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8306 // TODO: when removed in 4.0, update command_injection.rdoc
8307 rb_warn_deprecated_to_remove_at(4.0, "IO process creation with a leading '|'", "IO.popen");
8308 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8309 }
8310 else {
8311 return rb_file_open_generic(io_alloc(klass), filename,
8312 oflags, fmode, convconfig, perm);
8313 }
8314}
8315
8316static VALUE
8317rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8318{
8319 int oflags;
8320 enum rb_io_mode fmode;
8321 struct rb_io_encoding convconfig;
8322 mode_t perm;
8323
8324 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8325 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8326 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8327}
8328
8329static VALUE
8330io_reopen(VALUE io, VALUE nfile)
8331{
8332 rb_io_t *fptr, *orig;
8333 int fd, fd2;
8334 rb_off_t pos = 0;
8335
8336 nfile = rb_io_get_io(nfile);
8337 GetOpenFile(io, fptr);
8338 GetOpenFile(nfile, orig);
8339
8340 if (fptr == orig) return io;
8341 if (RUBY_IO_EXTERNAL_P(fptr)) {
8342 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8343 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8344 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8345 rb_raise(rb_eArgError,
8346 "%s can't change access mode from \"%s\" to \"%s\"",
8347 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8348 rb_io_fmode_modestr(orig->mode));
8349 }
8350 }
8351 if (fptr->mode & FMODE_WRITABLE) {
8352 if (io_fflush(fptr) < 0)
8353 rb_sys_fail_on_write(fptr);
8354 }
8355 else {
8356 flush_before_seek(fptr, true);
8357 }
8358 if (orig->mode & FMODE_READABLE) {
8359 pos = io_tell(orig);
8360 }
8361 if (orig->mode & FMODE_WRITABLE) {
8362 if (io_fflush(orig) < 0)
8363 rb_sys_fail_on_write(fptr);
8364 }
8365
8366 /* copy rb_io_t structure */
8367 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8368 fptr->encs = orig->encs;
8369 fptr->pid = orig->pid;
8370 fptr->lineno = orig->lineno;
8371 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8372 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8373 fptr_copy_finalizer(fptr, orig);
8374
8375 fd = fptr->fd;
8376 fd2 = orig->fd;
8377 if (fd != fd2) {
8378 // Interrupt all usage of the old file descriptor:
8379 rb_thread_io_close_interrupt(fptr);
8380 rb_thread_io_close_wait(fptr);
8381
8382 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8383 /* need to keep FILE objects of stdin, stdout and stderr */
8384 if (rb_cloexec_dup2(fd2, fd) < 0)
8385 rb_sys_fail_path(orig->pathv);
8386 rb_update_max_fd(fd);
8387 }
8388 else {
8389 fclose(fptr->stdio_file);
8390 fptr->stdio_file = 0;
8391 fptr->fd = -1;
8392 if (rb_cloexec_dup2(fd2, fd) < 0)
8393 rb_sys_fail_path(orig->pathv);
8394 rb_update_max_fd(fd);
8395 fptr->fd = fd;
8396 }
8397
8398 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8399 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8400 rb_sys_fail_path(fptr->pathv);
8401 }
8402 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8403 rb_sys_fail_path(orig->pathv);
8404 }
8405 }
8406 }
8407
8408 if (fptr->mode & FMODE_BINMODE) {
8409 rb_io_binmode(io);
8410 }
8411
8412 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8413 return io;
8414}
8415
8416#ifdef _WIN32
8417int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8418#else
8419static int
8420rb_freopen(VALUE fname, const char *mode, FILE *fp)
8421{
8422 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8423 RB_GC_GUARD(fname);
8424 return errno;
8425 }
8426 return 0;
8427}
8428#endif
8429
8430/*
8431 * call-seq:
8432 * reopen(other_io) -> self
8433 * reopen(path, mode = 'r', **opts) -> self
8434 *
8435 * Reassociates the stream with another stream,
8436 * which may be of a different class.
8437 * This method may be used to redirect an existing stream
8438 * to a new destination.
8439 *
8440 * With argument +other_io+ given, reassociates with that stream:
8441 *
8442 * # Redirect $stdin from a file.
8443 * f = File.open('t.txt')
8444 * $stdin.reopen(f)
8445 * f.close
8446 *
8447 * # Redirect $stdout to a file.
8448 * f = File.open('t.tmp', 'w')
8449 * $stdout.reopen(f)
8450 * f.close
8451 *
8452 * With argument +path+ given, reassociates with a new stream to that file path:
8453 *
8454 * $stdin.reopen('t.txt')
8455 * $stdout.reopen('t.tmp', 'w')
8456 *
8457 * Optional keyword arguments +opts+ specify:
8458 *
8459 * - {Open Options}[rdoc-ref:IO@Open+Options].
8460 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8461 *
8462 */
8463
8464static VALUE
8465rb_io_reopen(int argc, VALUE *argv, VALUE file)
8466{
8467 VALUE fname, nmode, opt;
8468 int oflags;
8469 rb_io_t *fptr;
8470
8471 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8472 VALUE tmp = rb_io_check_io(fname);
8473 if (!NIL_P(tmp)) {
8474 return io_reopen(file, tmp);
8475 }
8476 }
8477
8478 FilePathValue(fname);
8479 rb_io_taint_check(file);
8480 fptr = RFILE(file)->fptr;
8481 if (!fptr) {
8482 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8483 }
8484
8485 if (!NIL_P(nmode) || !NIL_P(opt)) {
8486 enum rb_io_mode fmode;
8487 struct rb_io_encoding convconfig;
8488
8489 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8490 if (RUBY_IO_EXTERNAL_P(fptr) &&
8491 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8492 (fptr->mode & FMODE_READWRITE)) {
8493 rb_raise(rb_eArgError,
8494 "%s can't change access mode from \"%s\" to \"%s\"",
8495 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8496 rb_io_fmode_modestr(fmode));
8497 }
8498 fptr->mode = fmode;
8499 fptr->encs = convconfig;
8500 }
8501 else {
8502 oflags = rb_io_fmode_oflags(fptr->mode);
8503 }
8504
8505 fptr->pathv = fname;
8506 if (fptr->fd < 0) {
8507 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8508 fptr->stdio_file = 0;
8509 return file;
8510 }
8511
8512 if (fptr->mode & FMODE_WRITABLE) {
8513 if (io_fflush(fptr) < 0)
8514 rb_sys_fail_on_write(fptr);
8515 }
8516 fptr->rbuf.off = fptr->rbuf.len = 0;
8517
8518 if (fptr->stdio_file) {
8519 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8520 rb_io_oflags_modestr(oflags),
8521 fptr->stdio_file);
8522 if (e) rb_syserr_fail_path(e, fptr->pathv);
8523 fptr->fd = fileno(fptr->stdio_file);
8524 rb_fd_fix_cloexec(fptr->fd);
8525#ifdef USE_SETVBUF
8526 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8527 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8528#endif
8529 if (fptr->stdio_file == stderr) {
8530 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8531 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8532 }
8533 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8534 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8535 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8536 }
8537 }
8538 else {
8539 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8540 int err = 0;
8541 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8542 err = errno;
8543 (void)close(tmpfd);
8544 if (err) {
8545 rb_syserr_fail_path(err, fptr->pathv);
8546 }
8547 }
8548
8549 return file;
8550}
8551
8552/* :nodoc: */
8553static VALUE
8554rb_io_init_copy(VALUE dest, VALUE io)
8555{
8556 rb_io_t *fptr, *orig;
8557 int fd;
8558 VALUE write_io;
8559 rb_off_t pos;
8560
8561 io = rb_io_get_io(io);
8562 if (!OBJ_INIT_COPY(dest, io)) return dest;
8563 GetOpenFile(io, orig);
8564 MakeOpenFile(dest, fptr);
8565
8566 rb_io_flush(io);
8567
8568 /* copy rb_io_t structure */
8569 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8570 fptr->encs = orig->encs;
8571 fptr->pid = orig->pid;
8572 fptr->lineno = orig->lineno;
8573 fptr->timeout = orig->timeout;
8574
8575 ccan_list_head_init(&fptr->blocking_operations);
8576 fptr->closing_ec = NULL;
8577 fptr->wakeup_mutex = Qnil;
8578 fptr->fork_generation = GET_VM()->fork_gen;
8579
8580 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8581 fptr_copy_finalizer(fptr, orig);
8582
8583 fd = ruby_dup(orig->fd);
8584 fptr->fd = fd;
8585 pos = io_tell(orig);
8586 if (0 <= pos)
8587 io_seek(fptr, pos, SEEK_SET);
8588 if (fptr->mode & FMODE_BINMODE) {
8589 rb_io_binmode(dest);
8590 }
8591
8592 write_io = GetWriteIO(io);
8593 if (io != write_io) {
8594 write_io = rb_obj_dup(write_io);
8595 fptr->tied_io_for_writing = write_io;
8596 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8597 }
8598
8599 return dest;
8600}
8601
8602/*
8603 * call-seq:
8604 * printf(format_string, *objects) -> nil
8605 *
8606 * Formats and writes +objects+ to the stream.
8607 *
8608 * For details on +format_string+, see
8609 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8610 *
8611 */
8612
8613VALUE
8614rb_io_printf(int argc, const VALUE *argv, VALUE out)
8615{
8616 rb_io_write(out, rb_f_sprintf(argc, argv));
8617 return Qnil;
8618}
8619
8620/*
8621 * call-seq:
8622 * printf(format_string, *objects) -> nil
8623 * printf(io, format_string, *objects) -> nil
8624 *
8625 * Equivalent to:
8626 *
8627 * io.write(sprintf(format_string, *objects))
8628 *
8629 * For details on +format_string+, see
8630 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8631 *
8632 * With the single argument +format_string+, formats +objects+ into the string,
8633 * then writes the formatted string to $stdout:
8634 *
8635 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8636 *
8637 * Output (on $stdout):
8638 *
8639 * 0024 24 24.00#
8640 *
8641 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8642 * then writes the formatted string to +io+:
8643 *
8644 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8645 *
8646 * Output (on $stderr):
8647 *
8648 * 0024 24 24.00# => nil
8649 *
8650 * With no arguments, does nothing.
8651 *
8652 */
8653
8654static VALUE
8655rb_f_printf(int argc, VALUE *argv, VALUE _)
8656{
8657 VALUE out;
8658
8659 if (argc == 0) return Qnil;
8660 if (RB_TYPE_P(argv[0], T_STRING)) {
8661 out = rb_ractor_stdout();
8662 }
8663 else {
8664 out = argv[0];
8665 argv++;
8666 argc--;
8667 }
8668 rb_io_write(out, rb_f_sprintf(argc, argv));
8669
8670 return Qnil;
8671}
8672
8673static void
8674deprecated_str_setter(VALUE val, ID id, VALUE *var)
8675{
8676 rb_str_setter(val, id, &val);
8677 if (!NIL_P(val)) {
8678 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8679 }
8680 *var = val;
8681}
8682
8683static void
8684deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8685{
8686 if (!NIL_P(val)) {
8687 if (!RB_TYPE_P(val, T_STRING)) {
8688 rb_raise(rb_eTypeError, "value of %"PRIsVALUE" must be String", rb_id2str(id));
8689 }
8690 if (rb_str_equal(val, rb_default_rs)) {
8691 val = rb_default_rs;
8692 }
8693 else {
8694 val = rb_str_frozen_bare_string(val);
8695 }
8697 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8698 }
8699 *var = val;
8700}
8701
8702/*
8703 * call-seq:
8704 * print(*objects) -> nil
8705 *
8706 * Writes the given objects to the stream; returns +nil+.
8707 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8708 * (<tt>$\</tt>), if it is not +nil+.
8709 * See {Line IO}[rdoc-ref:IO@Line+IO].
8710 *
8711 * With argument +objects+ given, for each object:
8712 *
8713 * - Converts via its method +to_s+ if not a string.
8714 * - Writes to the stream.
8715 * - If not the last object, writes the output field separator
8716 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8717 *
8718 * With default separators:
8719 *
8720 * f = File.open('t.tmp', 'w+')
8721 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8722 * p $OUTPUT_RECORD_SEPARATOR
8723 * p $OUTPUT_FIELD_SEPARATOR
8724 * f.print(*objects)
8725 * f.rewind
8726 * p f.read
8727 * f.close
8728 *
8729 * Output:
8730 *
8731 * nil
8732 * nil
8733 * "00.00/10+0izerozero"
8734 *
8735 * With specified separators:
8736 *
8737 * $\ = "\n"
8738 * $, = ','
8739 * f.rewind
8740 * f.print(*objects)
8741 * f.rewind
8742 * p f.read
8743 *
8744 * Output:
8745 *
8746 * "0,0.0,0/1,0+0i,zero,zero\n"
8747 *
8748 * With no argument given, writes the content of <tt>$_</tt>
8749 * (which is usually the most recent user input):
8750 *
8751 * f = File.open('t.tmp', 'w+')
8752 * gets # Sets $_ to the most recent user input.
8753 * f.print
8754 * f.close
8755 *
8756 */
8757
8758VALUE
8759rb_io_print(int argc, const VALUE *argv, VALUE out)
8760{
8761 int i;
8762 VALUE line;
8763
8764 /* if no argument given, print `$_' */
8765 if (argc == 0) {
8766 argc = 1;
8767 line = rb_lastline_get();
8768 argv = &line;
8769 }
8770 if (argc > 1 && !NIL_P(rb_output_fs)) {
8771 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8772 }
8773 for (i=0; i<argc; i++) {
8774 if (!NIL_P(rb_output_fs) && i>0) {
8775 rb_io_write(out, rb_output_fs);
8776 }
8777 rb_io_write(out, argv[i]);
8778 }
8779 if (argc > 0 && !NIL_P(rb_output_rs)) {
8780 rb_io_write(out, rb_output_rs);
8781 }
8782
8783 return Qnil;
8784}
8785
8786/*
8787 * call-seq:
8788 * print(*objects) -> nil
8789 *
8790 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8791 * this method is the straightforward way to write to <tt>$stdout</tt>.
8792 *
8793 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8794 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8795 * <tt>$\</tt>), if it is not +nil+.
8796 *
8797 * With argument +objects+ given, for each object:
8798 *
8799 * - Converts via its method +to_s+ if not a string.
8800 * - Writes to <tt>stdout</tt>.
8801 * - If not the last object, writes the output field separator
8802 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8803 *
8804 * With default separators:
8805 *
8806 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8807 * $OUTPUT_RECORD_SEPARATOR
8808 * $OUTPUT_FIELD_SEPARATOR
8809 * print(*objects)
8810 *
8811 * Output:
8812 *
8813 * nil
8814 * nil
8815 * 00.00/10+0izerozero
8816 *
8817 * With specified separators:
8818 *
8819 * $OUTPUT_RECORD_SEPARATOR = "\n"
8820 * $OUTPUT_FIELD_SEPARATOR = ','
8821 * print(*objects)
8822 *
8823 * Output:
8824 *
8825 * 0,0.0,0/1,0+0i,zero,zero
8826 *
8827 * With no argument given, writes the content of <tt>$_</tt>
8828 * (which is usually the most recent user input):
8829 *
8830 * gets # Sets $_ to the most recent user input.
8831 * print # Prints $_.
8832 *
8833 */
8834
8835static VALUE
8836rb_f_print(int argc, const VALUE *argv, VALUE _)
8837{
8838 rb_io_print(argc, argv, rb_ractor_stdout());
8839 return Qnil;
8840}
8841
8842/*
8843 * call-seq:
8844 * putc(object) -> object
8845 *
8846 * Writes a character to the stream.
8847 * See {Character IO}[rdoc-ref:IO@Character+IO].
8848 *
8849 * If +object+ is numeric, converts to integer if necessary,
8850 * then writes the character whose code is the
8851 * least significant byte;
8852 * if +object+ is a string, writes the first character:
8853 *
8854 * $stdout.putc "A"
8855 * $stdout.putc 65
8856 *
8857 * Output:
8858 *
8859 * AA
8860 *
8861 */
8862
8863static VALUE
8864rb_io_putc(VALUE io, VALUE ch)
8865{
8866 VALUE str;
8867 if (RB_TYPE_P(ch, T_STRING)) {
8868 str = rb_str_substr(ch, 0, 1);
8869 }
8870 else {
8871 char c = NUM2CHR(ch);
8872 str = rb_str_new(&c, 1);
8873 }
8874 rb_io_write(io, str);
8875 return ch;
8876}
8877
8878#define forward(obj, id, argc, argv) \
8879 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8880#define forward_public(obj, id, argc, argv) \
8881 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8882#define forward_current(id, argc, argv) \
8883 forward_public(ARGF.current_file, id, argc, argv)
8884
8885/*
8886 * call-seq:
8887 * putc(int) -> int
8888 *
8889 * Equivalent to:
8890 *
8891 * $stdout.putc(int)
8892 *
8893 * See IO#putc for important information regarding multi-byte characters.
8894 *
8895 */
8896
8897static VALUE
8898rb_f_putc(VALUE recv, VALUE ch)
8899{
8900 VALUE r_stdout = rb_ractor_stdout();
8901 if (recv == r_stdout) {
8902 return rb_io_putc(recv, ch);
8903 }
8904 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8905}
8906
8907
8908int
8909rb_str_end_with_asciichar(VALUE str, int c)
8910{
8911 long len = RSTRING_LEN(str);
8912 const char *ptr = RSTRING_PTR(str);
8913 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8914 int n;
8915
8916 if (len == 0) return 0;
8917 if ((n = rb_enc_mbminlen(enc)) == 1) {
8918 return ptr[len - 1] == c;
8919 }
8920 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8921}
8922
8923static VALUE
8924io_puts_ary(VALUE ary, VALUE out, int recur)
8925{
8926 VALUE tmp;
8927 long i;
8928
8929 if (recur) {
8930 tmp = rb_str_new2("[...]");
8931 rb_io_puts(1, &tmp, out);
8932 return Qtrue;
8933 }
8934 ary = rb_check_array_type(ary);
8935 if (NIL_P(ary)) return Qfalse;
8936 for (i=0; i<RARRAY_LEN(ary); i++) {
8937 tmp = RARRAY_AREF(ary, i);
8938 rb_io_puts(1, &tmp, out);
8939 }
8940 return Qtrue;
8941}
8942
8943/*
8944 * call-seq:
8945 * puts(*objects) -> nil
8946 *
8947 * Writes the given +objects+ to the stream, which must be open for writing;
8948 * returns +nil+.\
8949 * Writes a newline after each that does not already end with a newline sequence.
8950 * If called without arguments, writes a newline.
8951 * See {Line IO}[rdoc-ref:IO@Line+IO].
8952 *
8953 * Note that each added newline is the character <tt>"\n"<//tt>,
8954 * not the output record separator (<tt>$\</tt>).
8955 *
8956 * Treatment for each object:
8957 *
8958 * - String: writes the string.
8959 * - Neither string nor array: writes <tt>object.to_s</tt>.
8960 * - Array: writes each element of the array; arrays may be nested.
8961 *
8962 * To keep these examples brief, we define this helper method:
8963 *
8964 * def show(*objects)
8965 * # Puts objects to file.
8966 * f = File.new('t.tmp', 'w+')
8967 * f.puts(objects)
8968 * # Return file content.
8969 * f.rewind
8970 * p f.read
8971 * f.close
8972 * end
8973 *
8974 * # Strings without newlines.
8975 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8976 * # Strings, some with newlines.
8977 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8978 *
8979 * # Neither strings nor arrays:
8980 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8981 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8982 *
8983 * # Array of strings.
8984 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8985 * # Nested arrays.
8986 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8987 *
8988 */
8989
8990VALUE
8991rb_io_puts(int argc, const VALUE *argv, VALUE out)
8992{
8993 VALUE line, args[2];
8994
8995 /* if no argument given, print newline. */
8996 if (argc == 0) {
8997 rb_io_write(out, rb_default_rs);
8998 return Qnil;
8999 }
9000 for (int i = 0; i < argc; i++) {
9001 // Convert the argument to a string:
9002 if (RB_TYPE_P(argv[i], T_STRING)) {
9003 line = argv[i];
9004 }
9005 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9006 continue;
9007 }
9008 else {
9009 line = rb_obj_as_string(argv[i]);
9010 }
9011
9012 // Write the line:
9013 int n = 0;
9014 if (RSTRING_LEN(line) == 0) {
9015 args[n++] = rb_default_rs;
9016 }
9017 else {
9018 args[n++] = line;
9019 if (!rb_str_end_with_asciichar(line, '\n')) {
9020 args[n++] = rb_default_rs;
9021 }
9022 }
9023
9024 rb_io_writev(out, n, args);
9025 }
9026
9027 return Qnil;
9028}
9029
9030/*
9031 * call-seq:
9032 * puts(*objects) -> nil
9033 *
9034 * Equivalent to
9035 *
9036 * $stdout.puts(objects)
9037 */
9038
9039static VALUE
9040rb_f_puts(int argc, VALUE *argv, VALUE recv)
9041{
9042 VALUE r_stdout = rb_ractor_stdout();
9043 if (recv == r_stdout) {
9044 return rb_io_puts(argc, argv, recv);
9045 }
9046 return forward(r_stdout, rb_intern("puts"), argc, argv);
9047}
9048
9049static VALUE
9050rb_p_write(VALUE str)
9051{
9052 VALUE args[2];
9053 args[0] = str;
9054 args[1] = rb_default_rs;
9055 VALUE r_stdout = rb_ractor_stdout();
9056 if (RB_TYPE_P(r_stdout, T_FILE) &&
9057 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9058 io_writev(2, args, r_stdout);
9059 }
9060 else {
9061 rb_io_writev(r_stdout, 2, args);
9062 }
9063 return Qnil;
9064}
9065
9066void
9067rb_p(VALUE obj) /* for debug print within C code */
9068{
9069 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9070}
9071
9072static VALUE
9073rb_p_result(int argc, const VALUE *argv)
9074{
9075 VALUE ret = Qnil;
9076
9077 if (argc == 1) {
9078 ret = argv[0];
9079 }
9080 else if (argc > 1) {
9081 ret = rb_ary_new4(argc, argv);
9082 }
9083 VALUE r_stdout = rb_ractor_stdout();
9084 if (RB_TYPE_P(r_stdout, T_FILE)) {
9085 rb_uninterruptible(rb_io_flush, r_stdout);
9086 }
9087 return ret;
9088}
9089
9090/*
9091 * call-seq:
9092 * p(object) -> obj
9093 * p(*objects) -> array of objects
9094 * p -> nil
9095 *
9096 * For each object +obj+, executes:
9097 *
9098 * $stdout.write(obj.inspect, "\n")
9099 *
9100 * With one object given, returns the object;
9101 * with multiple objects given, returns an array containing the objects;
9102 * with no object given, returns +nil+.
9103 *
9104 * Examples:
9105 *
9106 * r = Range.new(0, 4)
9107 * p r # => 0..4
9108 * p [r, r, r] # => [0..4, 0..4, 0..4]
9109 * p # => nil
9110 *
9111 * Output:
9112 *
9113 * 0..4
9114 * [0..4, 0..4, 0..4]
9115 *
9116 * Kernel#p is designed for debugging purposes.
9117 * Ruby implementations may define Kernel#p to be uninterruptible
9118 * in whole or in part.
9119 * On CRuby, Kernel#p's writing of data is uninterruptible.
9120 */
9121
9122static VALUE
9123rb_f_p(int argc, VALUE *argv, VALUE self)
9124{
9125 int i;
9126 for (i=0; i<argc; i++) {
9127 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9128 rb_uninterruptible(rb_p_write, inspected);
9129 }
9130 return rb_p_result(argc, argv);
9131}
9132
9133/*
9134 * call-seq:
9135 * display(port = $>) -> nil
9136 *
9137 * Writes +self+ on the given port:
9138 *
9139 * 1.display
9140 * "cat".display
9141 * [ 4, 5, 6 ].display
9142 * puts
9143 *
9144 * Output:
9145 *
9146 * 1cat[4, 5, 6]
9147 *
9148 */
9149
9150static VALUE
9151rb_obj_display(int argc, VALUE *argv, VALUE self)
9152{
9153 VALUE out;
9154
9155 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9156 rb_io_write(out, self);
9157
9158 return Qnil;
9159}
9160
9161static int
9162rb_stderr_to_original_p(VALUE err)
9163{
9164 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9165}
9166
9167void
9168rb_write_error2(const char *mesg, long len)
9169{
9170 VALUE out = rb_ractor_stderr();
9171 if (rb_stderr_to_original_p(out)) {
9172#ifdef _WIN32
9173 if (isatty(fileno(stderr))) {
9174 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9175 }
9176#endif
9177 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9178 /* failed to write to stderr, what can we do? */
9179 return;
9180 }
9181 }
9182 else {
9183 rb_io_write(out, rb_str_new(mesg, len));
9184 }
9185}
9186
9187void
9188rb_write_error(const char *mesg)
9189{
9190 rb_write_error2(mesg, strlen(mesg));
9191}
9192
9193void
9194rb_write_error_str(VALUE mesg)
9195{
9196 VALUE out = rb_ractor_stderr();
9197 /* a stopgap measure for the time being */
9198 if (rb_stderr_to_original_p(out)) {
9199 size_t len = (size_t)RSTRING_LEN(mesg);
9200#ifdef _WIN32
9201 if (isatty(fileno(stderr))) {
9202 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9203 }
9204#endif
9205 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9206 RB_GC_GUARD(mesg);
9207 return;
9208 }
9209 }
9210 else {
9211 /* may unlock GVL, and */
9212 rb_io_write(out, mesg);
9213 }
9214}
9215
9216int
9217rb_stderr_tty_p(void)
9218{
9219 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9220 return isatty(fileno(stderr));
9221 return 0;
9222}
9223
9224static void
9225must_respond_to(ID mid, VALUE val, ID id)
9226{
9227 if (!rb_respond_to(val, mid)) {
9228 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9229 rb_id2str(id), rb_id2str(mid),
9230 rb_obj_class(val));
9231 }
9232}
9233
9234static void
9235stdin_setter(VALUE val, ID id, VALUE *ptr)
9236{
9238}
9239
9240static VALUE
9241stdin_getter(ID id, VALUE *ptr)
9242{
9243 return rb_ractor_stdin();
9244}
9245
9246static void
9247stdout_setter(VALUE val, ID id, VALUE *ptr)
9248{
9249 must_respond_to(id_write, val, id);
9251}
9252
9253static VALUE
9254stdout_getter(ID id, VALUE *ptr)
9255{
9256 return rb_ractor_stdout();
9257}
9258
9259static void
9260stderr_setter(VALUE val, ID id, VALUE *ptr)
9261{
9262 must_respond_to(id_write, val, id);
9264}
9265
9266static VALUE
9267stderr_getter(ID id, VALUE *ptr)
9268{
9269 return rb_ractor_stderr();
9270}
9271
9272static VALUE
9273allocate_and_open_new_file(VALUE klass)
9274{
9275 VALUE self = io_alloc(klass);
9276 rb_io_make_open_file(self);
9277 return self;
9278}
9279
9280VALUE
9281rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9282{
9283 int state;
9284 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9285 if (state) {
9286 /* if we raised an exception allocating an IO object, but the caller
9287 intended to transfer ownership of this FD to us, close the fd before
9288 raising the exception. Otherwise, we would leak a FD - the caller
9289 expects GC to close the file, but we never got around to assigning
9290 it to a rb_io. */
9291 if (!(mode & FMODE_EXTERNAL)) {
9292 maygvl_close(descriptor, 0);
9293 }
9294 rb_jump_tag(state);
9295 }
9296
9297
9298 rb_io_t *io = RFILE(self)->fptr;
9299 io->self = self;
9300 io->fd = descriptor;
9301 io->mode = mode;
9302
9303 /* At this point, Ruby fully owns the descriptor, and will close it when
9304 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9305 in the rest of this method. */
9306
9307 if (NIL_P(path)) {
9308 io->pathv = Qnil;
9309 }
9310 else {
9311 StringValue(path);
9312 io->pathv = rb_str_new_frozen(path);
9313 }
9314
9315 io->timeout = timeout;
9316
9317 ccan_list_head_init(&io->blocking_operations);
9318 io->closing_ec = NULL;
9319 io->wakeup_mutex = Qnil;
9320 io->fork_generation = GET_VM()->fork_gen;
9321
9322 if (encoding) {
9323 io->encs = *encoding;
9324 }
9325
9326 rb_update_max_fd(descriptor);
9327
9328 return self;
9329}
9330
9331static VALUE
9332prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9333{
9334 VALUE path_value = Qnil;
9335 rb_encoding *e;
9336 struct rb_io_encoding convconfig;
9337
9338 if (path) {
9339 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9340 }
9341
9342 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9343 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9344 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9347#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9348 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9349 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9350 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9351#endif
9352 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9353 convconfig.ecopts = Qnil;
9354
9355 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9356 rb_io_t*io = RFILE(self)->fptr;
9357
9358 if (!io_check_tty(io)) {
9359#ifdef __CYGWIN__
9360 io->mode |= FMODE_BINMODE;
9361 setmode(fd, O_BINARY);
9362#endif
9363 }
9364
9365 return self;
9366}
9367
9368VALUE
9369rb_io_fdopen(int fd, int oflags, const char *path)
9370{
9371 VALUE klass = rb_cIO;
9372
9373 if (path && strcmp(path, "-")) klass = rb_cFile;
9374 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9375}
9376
9377static VALUE
9378prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9379{
9380 rb_io_t *fptr;
9381 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9382
9383 GetOpenFile(io, fptr);
9385#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9386 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9387 if (fmode & FMODE_READABLE) {
9389 }
9390#endif
9391 fptr->stdio_file = f;
9392
9393 return io;
9394}
9395
9396VALUE
9397rb_io_prep_stdin(void)
9398{
9399 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9400}
9401
9402VALUE
9403rb_io_prep_stdout(void)
9404{
9405 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9406}
9407
9408VALUE
9409rb_io_prep_stderr(void)
9410{
9411 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9412}
9413
9414FILE *
9416{
9417 if (!fptr->stdio_file) {
9418 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9419 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9420 }
9421 return fptr->stdio_file;
9422}
9423
9424static inline void
9425rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9426{
9427 buf->ptr = NULL;
9428 buf->off = 0;
9429 buf->len = 0;
9430 buf->capa = 0;
9431}
9432
9433static inline rb_io_t *
9434rb_io_fptr_new(void)
9435{
9436 rb_io_t *fp = ALLOC(rb_io_t);
9437 fp->self = Qnil;
9438 fp->fd = -1;
9439 fp->stdio_file = NULL;
9440 fp->mode = 0;
9441 fp->pid = 0;
9442 fp->lineno = 0;
9443 fp->pathv = Qnil;
9444 fp->finalize = 0;
9445 rb_io_buffer_init(&fp->wbuf);
9446 rb_io_buffer_init(&fp->rbuf);
9447 rb_io_buffer_init(&fp->cbuf);
9448 fp->readconv = NULL;
9449 fp->writeconv = NULL;
9451 fp->writeconv_pre_ecflags = 0;
9453 fp->writeconv_initialized = 0;
9454 fp->tied_io_for_writing = 0;
9455 fp->encs.enc = NULL;
9456 fp->encs.enc2 = NULL;
9457 fp->encs.ecflags = 0;
9458 fp->encs.ecopts = Qnil;
9459 fp->write_lock = Qnil;
9460 fp->timeout = Qnil;
9461 ccan_list_head_init(&fp->blocking_operations);
9462 fp->closing_ec = NULL;
9463 fp->wakeup_mutex = Qnil;
9464 fp->fork_generation = GET_VM()->fork_gen;
9465 return fp;
9466}
9467
9468rb_io_t *
9469rb_io_make_open_file(VALUE obj)
9470{
9471 rb_io_t *fp = 0;
9472
9473 Check_Type(obj, T_FILE);
9474 if (RFILE(obj)->fptr) {
9475 rb_io_close(obj);
9476 rb_io_fptr_finalize(RFILE(obj)->fptr);
9477 RFILE(obj)->fptr = 0;
9478 }
9479 fp = rb_io_fptr_new();
9480 fp->self = obj;
9481 RFILE(obj)->fptr = fp;
9482 return fp;
9483}
9484
9485static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9486
9487/*
9488 * call-seq:
9489 * IO.new(fd, mode = 'r', **opts) -> io
9490 *
9491 * Creates and returns a new \IO object (file stream) from a file descriptor.
9492 *
9493 * \IO.new may be useful for interaction with low-level libraries.
9494 * For higher-level interactions, it may be simpler to create
9495 * the file stream using File.open.
9496 *
9497 * Argument +fd+ must be a valid file descriptor (integer):
9498 *
9499 * path = 't.tmp'
9500 * fd = IO.sysopen(path) # => 3
9501 * IO.new(fd) # => #<IO:fd 3>
9502 *
9503 * The new \IO object does not inherit encoding
9504 * (because the integer file descriptor does not have an encoding):
9505 *
9506 * fd = IO.sysopen('t.rus', 'rb')
9507 * io = IO.new(fd)
9508 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9509 *
9510 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9511 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9512 *
9513 * IO.new(fd, 'w') # => #<IO:fd 3>
9514 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9515 *
9516 * Optional keyword arguments +opts+ specify:
9517 *
9518 * - {Open Options}[rdoc-ref:IO@Open+Options].
9519 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9520 *
9521 * Examples:
9522 *
9523 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9524 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9525 *
9526 */
9527
9528static VALUE
9529rb_io_initialize(int argc, VALUE *argv, VALUE io)
9530{
9531 VALUE fnum, vmode;
9532 VALUE opt;
9533
9534 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9535 return io_initialize(io, fnum, vmode, opt);
9536}
9537
9538static VALUE
9539io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9540{
9541 rb_io_t *fp;
9542 int fd, oflags = O_RDONLY;
9543 enum rb_io_mode fmode;
9544 struct rb_io_encoding convconfig;
9545#if defined(HAVE_FCNTL) && defined(F_GETFL)
9546 int ofmode;
9547#else
9548 struct stat st;
9549#endif
9550
9551 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9552
9553 fd = NUM2INT(fnum);
9554 if (rb_reserved_fd_p(fd)) {
9555 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9556 }
9557#if defined(HAVE_FCNTL) && defined(F_GETFL)
9558 oflags = fcntl(fd, F_GETFL);
9559 if (oflags == -1) rb_sys_fail(0);
9560#else
9561 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9562#endif
9563 rb_update_max_fd(fd);
9564#if defined(HAVE_FCNTL) && defined(F_GETFL)
9565 ofmode = rb_io_oflags_fmode(oflags);
9566 if (NIL_P(vmode)) {
9567 fmode = ofmode;
9568 }
9569 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9570 VALUE error = INT2FIX(EINVAL);
9572 }
9573#endif
9574 VALUE path = Qnil;
9575
9576 if (!NIL_P(opt)) {
9577 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9578 fmode |= FMODE_EXTERNAL;
9579 }
9580
9581 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9582 if (!NIL_P(path)) {
9583 StringValue(path);
9584 path = rb_str_new_frozen(path);
9585 }
9586 }
9587
9588 MakeOpenFile(io, fp);
9589 fp->self = io;
9590 fp->fd = fd;
9591 fp->mode = fmode;
9592 fp->encs = convconfig;
9593 fp->pathv = path;
9594 fp->timeout = Qnil;
9595 ccan_list_head_init(&fp->blocking_operations);
9596 fp->closing_ec = NULL;
9597 fp->wakeup_mutex = Qnil;
9598 fp->fork_generation = GET_VM()->fork_gen;
9599 clear_codeconv(fp);
9600 io_check_tty(fp);
9601 if (fileno(stdin) == fd)
9602 fp->stdio_file = stdin;
9603 else if (fileno(stdout) == fd)
9604 fp->stdio_file = stdout;
9605 else if (fileno(stderr) == fd)
9606 fp->stdio_file = stderr;
9607
9608 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9609 return io;
9610}
9611
9612/*
9613 * call-seq:
9614 * set_encoding_by_bom -> encoding or nil
9615 *
9616 * If the stream begins with a BOM
9617 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9618 * consumes the BOM and sets the external encoding accordingly;
9619 * returns the result encoding if found, or +nil+ otherwise:
9620 *
9621 * File.write('t.tmp', "\u{FEFF}abc")
9622 * io = File.open('t.tmp', 'rb')
9623 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9624 * io.close
9625 *
9626 * File.write('t.tmp', 'abc')
9627 * io = File.open('t.tmp', 'rb')
9628 * io.set_encoding_by_bom # => nil
9629 * io.close
9630 *
9631 * Raises an exception if the stream is not binmode
9632 * or its encoding has already been set.
9633 *
9634 */
9635
9636static VALUE
9637rb_io_set_encoding_by_bom(VALUE io)
9638{
9639 rb_io_t *fptr;
9640
9641 GetOpenFile(io, fptr);
9642 if (!(fptr->mode & FMODE_BINMODE)) {
9643 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9644 }
9645 if (fptr->encs.enc2) {
9646 rb_raise(rb_eArgError, "encoding conversion is set");
9647 }
9648 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9649 rb_raise(rb_eArgError, "encoding is set to %s already",
9650 rb_enc_name(fptr->encs.enc));
9651 }
9652 if (!io_set_encoding_by_bom(io)) return Qnil;
9653 return rb_enc_from_encoding(fptr->encs.enc);
9654}
9655
9656/*
9657 * call-seq:
9658 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9659 *
9660 * Opens the file at the given +path+ according to the given +mode+;
9661 * creates and returns a new File object for that file.
9662 *
9663 * The new File object is buffered mode (or non-sync mode), unless
9664 * +filename+ is a tty.
9665 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9666 *
9667 * Argument +path+ must be a valid file path:
9668 *
9669 * f = File.new('/etc/fstab')
9670 * f.close
9671 * f = File.new('t.txt')
9672 * f.close
9673 *
9674 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9675 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9676 *
9677 * f = File.new('t.tmp', 'w')
9678 * f.close
9679 * f = File.new('t.tmp', File::RDONLY)
9680 * f.close
9681 *
9682 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9683 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9684 *
9685 * f = File.new('t.tmp', File::CREAT, 0644)
9686 * f.close
9687 * f = File.new('t.tmp', File::CREAT, 0444)
9688 * f.close
9689 *
9690 * Optional keyword arguments +opts+ specify:
9691 *
9692 * - {Open Options}[rdoc-ref:IO@Open+Options].
9693 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9694 *
9695 */
9696
9697static VALUE
9698rb_file_initialize(int argc, VALUE *argv, VALUE io)
9699{
9700 if (RFILE(io)->fptr) {
9701 rb_raise(rb_eRuntimeError, "reinitializing File");
9702 }
9703 VALUE fname, vmode, vperm, opt;
9704 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9705 if (posargc < 3) { /* perm is File only */
9706 VALUE fd = rb_check_to_int(fname);
9707
9708 if (!NIL_P(fd)) {
9709 return io_initialize(io, fd, vmode, opt);
9710 }
9711 }
9712 return rb_open_file(io, fname, vmode, vperm, opt);
9713}
9714
9715/* :nodoc: */
9716static VALUE
9717rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9718{
9719 if (rb_block_given_p()) {
9720 VALUE cname = rb_obj_as_string(klass);
9721
9722 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9723 cname, cname);
9724 }
9725 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9726}
9727
9728
9729/*
9730 * call-seq:
9731 * IO.for_fd(fd, mode = 'r', **opts) -> io
9732 *
9733 * Synonym for IO.new.
9734 *
9735 */
9736
9737static VALUE
9738rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9739{
9740 VALUE io = rb_obj_alloc(klass);
9741 rb_io_initialize(argc, argv, io);
9742 return io;
9743}
9744
9745/*
9746 * call-seq:
9747 * ios.autoclose? -> true or false
9748 *
9749 * Returns +true+ if the underlying file descriptor of _ios_ will be
9750 * closed at its finalization or at calling #close, otherwise +false+.
9751 */
9752
9753static VALUE
9754rb_io_autoclose_p(VALUE io)
9755{
9756 rb_io_t *fptr = RFILE(io)->fptr;
9757 rb_io_check_closed(fptr);
9758 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9759}
9760
9761/*
9762 * call-seq:
9763 * io.autoclose = bool -> true or false
9764 *
9765 * Sets auto-close flag.
9766 *
9767 * f = File.open(File::NULL)
9768 * IO.for_fd(f.fileno).close
9769 * f.gets # raises Errno::EBADF
9770 *
9771 * f = File.open(File::NULL)
9772 * g = IO.for_fd(f.fileno)
9773 * g.autoclose = false
9774 * g.close
9775 * f.gets # won't cause Errno::EBADF
9776 */
9777
9778static VALUE
9779rb_io_set_autoclose(VALUE io, VALUE autoclose)
9780{
9781 rb_io_t *fptr;
9782 GetOpenFile(io, fptr);
9783 if (!RTEST(autoclose))
9784 fptr->mode |= FMODE_EXTERNAL;
9785 else
9786 fptr->mode &= ~FMODE_EXTERNAL;
9787 return autoclose;
9788}
9789
9790static VALUE
9791io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9792{
9793 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9794
9795 if (!RB_TEST(result)) {
9796 return Qnil;
9797 }
9798
9799 int mask = RB_NUM2INT(result);
9800
9801 if (mask & event) {
9802 if (return_io)
9803 return io;
9804 else
9805 return result;
9806 }
9807 else {
9808 return Qfalse;
9809 }
9810}
9811
9812/*
9813 * call-seq:
9814 * io.wait_readable -> truthy or falsy
9815 * io.wait_readable(timeout) -> truthy or falsy
9816 *
9817 * Waits until IO is readable and returns a truthy value, or a falsy
9818 * value when times out. Returns a truthy value immediately when
9819 * buffered data is available.
9820 */
9821
9822static VALUE
9823io_wait_readable(int argc, VALUE *argv, VALUE io)
9824{
9825 rb_io_t *fptr;
9826
9827 RB_IO_POINTER(io, fptr);
9829
9830 if (rb_io_read_pending(fptr)) return Qtrue;
9831
9832 rb_check_arity(argc, 0, 1);
9833 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9834
9835 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9836}
9837
9838/*
9839 * call-seq:
9840 * io.wait_writable -> truthy or falsy
9841 * io.wait_writable(timeout) -> truthy or falsy
9842 *
9843 * Waits until IO is writable and returns a truthy value or a falsy
9844 * value when times out.
9845 */
9846static VALUE
9847io_wait_writable(int argc, VALUE *argv, VALUE io)
9848{
9849 rb_io_t *fptr;
9850
9851 RB_IO_POINTER(io, fptr);
9853
9854 rb_check_arity(argc, 0, 1);
9855 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9856
9857 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9858}
9859
9860/*
9861 * call-seq:
9862 * io.wait_priority -> truthy or falsy
9863 * io.wait_priority(timeout) -> truthy or falsy
9864 *
9865 * Waits until IO is priority and returns a truthy value or a falsy
9866 * value when times out. Priority data is sent and received using
9867 * the Socket::MSG_OOB flag and is typically limited to streams.
9868 */
9869static VALUE
9870io_wait_priority(int argc, VALUE *argv, VALUE io)
9871{
9872 rb_io_t *fptr = NULL;
9873
9874 RB_IO_POINTER(io, fptr);
9876
9877 if (rb_io_read_pending(fptr)) return Qtrue;
9878
9879 rb_check_arity(argc, 0, 1);
9880 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9881
9882 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9883}
9884
9885static int
9886wait_mode_sym(VALUE mode)
9887{
9888 if (mode == ID2SYM(rb_intern("r"))) {
9889 return RB_WAITFD_IN;
9890 }
9891 if (mode == ID2SYM(rb_intern("read"))) {
9892 return RB_WAITFD_IN;
9893 }
9894 if (mode == ID2SYM(rb_intern("readable"))) {
9895 return RB_WAITFD_IN;
9896 }
9897 if (mode == ID2SYM(rb_intern("w"))) {
9898 return RB_WAITFD_OUT;
9899 }
9900 if (mode == ID2SYM(rb_intern("write"))) {
9901 return RB_WAITFD_OUT;
9902 }
9903 if (mode == ID2SYM(rb_intern("writable"))) {
9904 return RB_WAITFD_OUT;
9905 }
9906 if (mode == ID2SYM(rb_intern("rw"))) {
9907 return RB_WAITFD_IN|RB_WAITFD_OUT;
9908 }
9909 if (mode == ID2SYM(rb_intern("read_write"))) {
9910 return RB_WAITFD_IN|RB_WAITFD_OUT;
9911 }
9912 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9913 return RB_WAITFD_IN|RB_WAITFD_OUT;
9914 }
9915
9916 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9917}
9918
9919static inline enum rb_io_event
9920io_event_from_value(VALUE value)
9921{
9922 int events = RB_NUM2INT(value);
9923
9924 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9925
9926 return events;
9927}
9928
9929/*
9930 * call-seq:
9931 * io.wait(events, timeout) -> event mask, false or nil
9932 * io.wait(timeout = nil, mode = :read) -> self, true, or false
9933 *
9934 * Waits until the IO becomes ready for the specified events and returns the
9935 * subset of events that become ready, or a falsy value when times out.
9936 *
9937 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9938 * +IO::PRIORITY+.
9939 *
9940 * Returns an event mask (truthy value) immediately when buffered data is available.
9941 *
9942 * Optional parameter +mode+ is one of +:read+, +:write+, or
9943 * +:read_write+.
9944 */
9945
9946static VALUE
9947io_wait(int argc, VALUE *argv, VALUE io)
9948{
9949 VALUE timeout = Qundef;
9950 enum rb_io_event events = 0;
9951 int return_io = 0;
9952
9953 // The documented signature for this method is actually incorrect.
9954 // A single timeout is allowed in any position, and multiple symbols can be given.
9955 // Whether this is intentional or not, I don't know, and as such I consider this to
9956 // be a legacy/slow path.
9957 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9958 // We'd prefer to return the actual mask, but this form would return the io itself:
9959 return_io = 1;
9960
9961 // Slow/messy path:
9962 for (int i = 0; i < argc; i += 1) {
9963 if (RB_SYMBOL_P(argv[i])) {
9964 events |= wait_mode_sym(argv[i]);
9965 }
9966 else if (UNDEF_P(timeout)) {
9967 rb_time_interval(timeout = argv[i]);
9968 }
9969 else {
9970 rb_raise(rb_eArgError, "timeout given more than once");
9971 }
9972 }
9973
9974 if (UNDEF_P(timeout)) timeout = Qnil;
9975
9976 if (events == 0) {
9977 events = RUBY_IO_READABLE;
9978 }
9979 }
9980 else /* argc == 2 and neither are symbols */ {
9981 // This is the fast path:
9982 events = io_event_from_value(argv[0]);
9983 timeout = argv[1];
9984 }
9985
9986 if (events & RUBY_IO_READABLE) {
9987 rb_io_t *fptr = NULL;
9988 RB_IO_POINTER(io, fptr);
9989
9990 if (rb_io_read_pending(fptr)) {
9991 // This was the original behaviour:
9992 if (return_io) return Qtrue;
9993 // New behaviour always returns an event mask:
9994 else return RB_INT2NUM(RUBY_IO_READABLE);
9995 }
9996 }
9997
9998 return io_wait_event(io, events, timeout, return_io);
9999}
10000
10001static void
10002argf_mark(void *ptr)
10003{
10004 struct argf *p = ptr;
10005 rb_gc_mark(p->filename);
10006 rb_gc_mark(p->current_file);
10007 rb_gc_mark(p->argv);
10008 rb_gc_mark(p->inplace);
10009 rb_gc_mark(p->encs.ecopts);
10010}
10011
10012static size_t
10013argf_memsize(const void *ptr)
10014{
10015 const struct argf *p = ptr;
10016 size_t size = sizeof(*p);
10017 return size;
10018}
10019
10020static void
10021argf_compact(void *ptr)
10022{
10023 struct argf *p = ptr;
10024 p->filename = rb_gc_location(p->filename);
10025 p->current_file = rb_gc_location(p->current_file);
10026 p->argv = rb_gc_location(p->argv);
10027 p->inplace = rb_gc_location(p->inplace);
10028 p->encs.ecopts = rb_gc_location(p->encs.ecopts);
10029}
10030
10031static const rb_data_type_t argf_type = {
10032 "ARGF",
10033 {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_compact},
10034 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
10035};
10036
10037static inline void
10038argf_init(struct argf *p, VALUE v)
10039{
10040 p->filename = Qnil;
10041 p->current_file = Qnil;
10042 p->lineno = 0;
10043 p->argv = v;
10044}
10045
10046static VALUE
10047argf_alloc(VALUE klass)
10048{
10049 struct argf *p;
10050 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10051
10052 argf_init(p, Qnil);
10053 return argf;
10054}
10055
10056#undef rb_argv
10057
10058/* :nodoc: */
10059static VALUE
10060argf_initialize(VALUE argf, VALUE argv)
10061{
10062 memset(&ARGF, 0, sizeof(ARGF));
10063 argf_init(&ARGF, argv);
10064
10065 return argf;
10066}
10067
10068/* :nodoc: */
10069static VALUE
10070argf_initialize_copy(VALUE argf, VALUE orig)
10071{
10072 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10073 ARGF = argf_of(orig);
10074 ARGF.argv = rb_obj_dup(ARGF.argv);
10075 return argf;
10076}
10077
10078/*
10079 * call-seq:
10080 * ARGF.lineno = integer -> integer
10081 *
10082 * Sets the line number of ARGF as a whole to the given Integer.
10083 *
10084 * ARGF sets the line number automatically as you read data, so normally
10085 * you will not need to set it explicitly. To access the current line number
10086 * use ARGF.lineno.
10087 *
10088 * For example:
10089 *
10090 * ARGF.lineno #=> 0
10091 * ARGF.readline #=> "This is line 1\n"
10092 * ARGF.lineno #=> 1
10093 * ARGF.lineno = 0 #=> 0
10094 * ARGF.lineno #=> 0
10095 */
10096static VALUE
10097argf_set_lineno(VALUE argf, VALUE val)
10098{
10099 ARGF.lineno = NUM2INT(val);
10100 ARGF.last_lineno = ARGF.lineno;
10101 return val;
10102}
10103
10104/*
10105 * call-seq:
10106 * ARGF.lineno -> integer
10107 *
10108 * Returns the current line number of ARGF as a whole. This value
10109 * can be set manually with ARGF.lineno=.
10110 *
10111 * For example:
10112 *
10113 * ARGF.lineno #=> 0
10114 * ARGF.readline #=> "This is line 1\n"
10115 * ARGF.lineno #=> 1
10116 */
10117static VALUE
10118argf_lineno(VALUE argf)
10119{
10120 return INT2FIX(ARGF.lineno);
10121}
10122
10123static VALUE
10124argf_forward(int argc, VALUE *argv, VALUE argf)
10125{
10126 return forward_current(rb_frame_this_func(), argc, argv);
10127}
10128
10129#define next_argv() argf_next_argv(argf)
10130#define ARGF_GENERIC_INPUT_P() \
10131 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10132#define ARGF_FORWARD(argc, argv) do {\
10133 if (ARGF_GENERIC_INPUT_P())\
10134 return argf_forward((argc), (argv), argf);\
10135} while (0)
10136#define NEXT_ARGF_FORWARD(argc, argv) do {\
10137 if (!next_argv()) return Qnil;\
10138 ARGF_FORWARD((argc), (argv));\
10139} while (0)
10140
10141static void
10142argf_close(VALUE argf)
10143{
10144 VALUE file = ARGF.current_file;
10145 if (file == rb_stdin) return;
10146 if (RB_TYPE_P(file, T_FILE)) {
10147 rb_io_set_write_io(file, Qnil);
10148 }
10149 io_close(file);
10150 ARGF.init_p = -1;
10151}
10152
10153static int
10154argf_next_argv(VALUE argf)
10155{
10156 char *fn;
10157 rb_io_t *fptr;
10158 int stdout_binmode = 0;
10159 enum rb_io_mode fmode;
10160
10161 VALUE r_stdout = rb_ractor_stdout();
10162
10163 if (RB_TYPE_P(r_stdout, T_FILE)) {
10164 GetOpenFile(r_stdout, fptr);
10165 if (fptr->mode & FMODE_BINMODE)
10166 stdout_binmode = 1;
10167 }
10168
10169 if (ARGF.init_p == 0) {
10170 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10171 ARGF.next_p = 1;
10172 }
10173 else {
10174 ARGF.next_p = -1;
10175 }
10176 ARGF.init_p = 1;
10177 }
10178 else {
10179 if (NIL_P(ARGF.argv)) {
10180 ARGF.next_p = -1;
10181 }
10182 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10183 ARGF.next_p = 1;
10184 }
10185 }
10186
10187 if (ARGF.next_p == 1) {
10188 if (ARGF.init_p == 1) argf_close(argf);
10189 retry:
10190 if (RARRAY_LEN(ARGF.argv) > 0) {
10191 VALUE filename = rb_ary_shift(ARGF.argv);
10192 FilePathValue(filename);
10193 ARGF.filename = filename;
10194 filename = rb_str_encode_ospath(filename);
10195 fn = StringValueCStr(filename);
10196 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10197 ARGF.current_file = rb_stdin;
10198 if (ARGF.inplace) {
10199 rb_warn("Can't do inplace edit for stdio; skipping");
10200 goto retry;
10201 }
10202 }
10203 else {
10204 VALUE write_io = Qnil;
10205 int fr = rb_sysopen(filename, O_RDONLY, 0);
10206
10207 if (ARGF.inplace) {
10208 struct stat st;
10209#ifndef NO_SAFE_RENAME
10210 struct stat st2;
10211#endif
10212 VALUE str;
10213 int fw;
10214
10215 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10216 rb_io_close(r_stdout);
10217 }
10218 fstat(fr, &st);
10219 str = filename;
10220 if (!NIL_P(ARGF.inplace)) {
10221 VALUE suffix = ARGF.inplace;
10222 str = rb_str_dup(str);
10223 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10224 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10225 rb_enc_get(suffix), 0, Qnil))) {
10226 rb_str_append(str, suffix);
10227 }
10228#ifdef NO_SAFE_RENAME
10229 (void)close(fr);
10230 (void)unlink(RSTRING_PTR(str));
10231 if (rename(fn, RSTRING_PTR(str)) < 0) {
10232 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10233 filename, str, strerror(errno));
10234 goto retry;
10235 }
10236 fr = rb_sysopen(str, O_RDONLY, 0);
10237#else
10238 if (rename(fn, RSTRING_PTR(str)) < 0) {
10239 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10240 filename, str, strerror(errno));
10241 close(fr);
10242 goto retry;
10243 }
10244#endif
10245 }
10246 else {
10247#ifdef NO_SAFE_RENAME
10248 rb_fatal("Can't do inplace edit without backup");
10249#else
10250 if (unlink(fn) < 0) {
10251 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10252 filename, strerror(errno));
10253 close(fr);
10254 goto retry;
10255 }
10256#endif
10257 }
10258 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10259#ifndef NO_SAFE_RENAME
10260 fstat(fw, &st2);
10261#ifdef HAVE_FCHMOD
10262 fchmod(fw, st.st_mode);
10263#else
10264 chmod(fn, st.st_mode);
10265#endif
10266 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10267 int err;
10268#ifdef HAVE_FCHOWN
10269 err = fchown(fw, st.st_uid, st.st_gid);
10270#else
10271 err = chown(fn, st.st_uid, st.st_gid);
10272#endif
10273 if (err && getuid() == 0 && st2.st_uid == 0) {
10274 const char *wkfn = RSTRING_PTR(filename);
10275 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10276 filename, str, strerror(errno));
10277 (void)close(fr);
10278 (void)close(fw);
10279 (void)unlink(wkfn);
10280 goto retry;
10281 }
10282 }
10283#endif
10284 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10285 rb_ractor_stdout_set(write_io);
10286 if (stdout_binmode) rb_io_binmode(rb_stdout);
10287 }
10288 fmode = FMODE_READABLE;
10289 if (!ARGF.binmode) {
10290 fmode |= DEFAULT_TEXTMODE;
10291 }
10292 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10293 if (!NIL_P(write_io)) {
10294 rb_io_set_write_io(ARGF.current_file, write_io);
10295 }
10296 RB_GC_GUARD(filename);
10297 }
10298 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10299 GetOpenFile(ARGF.current_file, fptr);
10300 if (ARGF.encs.enc) {
10301 fptr->encs = ARGF.encs;
10302 clear_codeconv(fptr);
10303 }
10304 else {
10305 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10306 if (!ARGF.binmode) {
10308#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10309 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10310#endif
10311 }
10312 }
10313 ARGF.next_p = 0;
10314 }
10315 else {
10316 ARGF.next_p = 1;
10317 return FALSE;
10318 }
10319 }
10320 else if (ARGF.next_p == -1) {
10321 ARGF.current_file = rb_stdin;
10322 ARGF.filename = rb_str_new2("-");
10323 if (ARGF.inplace) {
10324 rb_warn("Can't do inplace edit for stdio");
10325 rb_ractor_stdout_set(orig_stdout);
10326 }
10327 }
10328 if (ARGF.init_p == -1) ARGF.init_p = 1;
10329 return TRUE;
10330}
10331
10332static VALUE
10333argf_getline(int argc, VALUE *argv, VALUE argf)
10334{
10335 VALUE line;
10336 long lineno = ARGF.lineno;
10337
10338 retry:
10339 if (!next_argv()) return Qnil;
10340 if (ARGF_GENERIC_INPUT_P()) {
10341 line = forward_current(idGets, argc, argv);
10342 }
10343 else {
10344 if (argc == 0 && rb_rs == rb_default_rs) {
10345 line = rb_io_gets(ARGF.current_file);
10346 }
10347 else {
10348 line = rb_io_getline(argc, argv, ARGF.current_file);
10349 }
10350 if (NIL_P(line) && ARGF.next_p != -1) {
10351 argf_close(argf);
10352 ARGF.next_p = 1;
10353 goto retry;
10354 }
10355 }
10356 if (!NIL_P(line)) {
10357 ARGF.lineno = ++lineno;
10358 ARGF.last_lineno = ARGF.lineno;
10359 }
10360 return line;
10361}
10362
10363static VALUE
10364argf_lineno_getter(ID id, VALUE *var)
10365{
10366 VALUE argf = *var;
10367 return INT2FIX(ARGF.last_lineno);
10368}
10369
10370static void
10371argf_lineno_setter(VALUE val, ID id, VALUE *var)
10372{
10373 VALUE argf = *var;
10374 int n = NUM2INT(val);
10375 ARGF.last_lineno = ARGF.lineno = n;
10376}
10377
10378void
10379rb_reset_argf_lineno(long n)
10380{
10381 ARGF.last_lineno = ARGF.lineno = n;
10382}
10383
10384static VALUE argf_gets(int, VALUE *, VALUE);
10385
10386/*
10387 * call-seq:
10388 * gets(sep=$/ [, getline_args]) -> string or nil
10389 * gets(limit [, getline_args]) -> string or nil
10390 * gets(sep, limit [, getline_args]) -> string or nil
10391 *
10392 * Returns (and assigns to <code>$_</code>) the next line from the list
10393 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10394 * no files are present on the command line. Returns +nil+ at end of
10395 * file. The optional argument specifies the record separator. The
10396 * separator is included with the contents of each record. A separator
10397 * of +nil+ reads the entire contents, and a zero-length separator
10398 * reads the input one paragraph at a time, where paragraphs are
10399 * divided by two consecutive newlines. If the first argument is an
10400 * integer, or optional second argument is given, the returning string
10401 * would not be longer than the given value in bytes. If multiple
10402 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10403 * the contents one file at a time.
10404 *
10405 * ARGV << "testfile"
10406 * print while gets
10407 *
10408 * <em>produces:</em>
10409 *
10410 * This is line one
10411 * This is line two
10412 * This is line three
10413 * And so on...
10414 *
10415 * The style of programming using <code>$_</code> as an implicit
10416 * parameter is gradually losing favor in the Ruby community.
10417 */
10418
10419static VALUE
10420rb_f_gets(int argc, VALUE *argv, VALUE recv)
10421{
10422 if (recv == argf) {
10423 return argf_gets(argc, argv, argf);
10424 }
10425 return forward(argf, idGets, argc, argv);
10426}
10427
10428/*
10429 * call-seq:
10430 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10431 * ARGF.gets(limit [, getline_args]) -> string or nil
10432 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10433 *
10434 * Returns the next line from the current file in ARGF.
10435 *
10436 * By default lines are assumed to be separated by <code>$/</code>;
10437 * to use a different character as a separator, supply it as a String
10438 * for the _sep_ argument.
10439 *
10440 * The optional _limit_ argument specifies how many characters of each line
10441 * to return. By default all characters are returned.
10442 *
10443 * See IO.readlines for details about getline_args.
10444 *
10445 */
10446static VALUE
10447argf_gets(int argc, VALUE *argv, VALUE argf)
10448{
10449 VALUE line;
10450
10451 line = argf_getline(argc, argv, argf);
10452 rb_lastline_set(line);
10453
10454 return line;
10455}
10456
10457VALUE
10459{
10460 VALUE line;
10461
10462 if (rb_rs != rb_default_rs) {
10463 return rb_f_gets(0, 0, argf);
10464 }
10465
10466 retry:
10467 if (!next_argv()) return Qnil;
10468 line = rb_io_gets(ARGF.current_file);
10469 if (NIL_P(line) && ARGF.next_p != -1) {
10470 rb_io_close(ARGF.current_file);
10471 ARGF.next_p = 1;
10472 goto retry;
10473 }
10474 rb_lastline_set(line);
10475 if (!NIL_P(line)) {
10476 ARGF.lineno++;
10477 ARGF.last_lineno = ARGF.lineno;
10478 }
10479
10480 return line;
10481}
10482
10483static VALUE argf_readline(int, VALUE *, VALUE);
10484
10485/*
10486 * call-seq:
10487 * readline(sep = $/, chomp: false) -> string
10488 * readline(limit, chomp: false) -> string
10489 * readline(sep, limit, chomp: false) -> string
10490 *
10491 * Equivalent to method Kernel#gets, except that it raises an exception
10492 * if called at end-of-stream:
10493 *
10494 * $ cat t.txt | ruby -e "p readlines; readline"
10495 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10496 * in `readline': end of file reached (EOFError)
10497 *
10498 * Optional keyword argument +chomp+ specifies whether line separators
10499 * are to be omitted.
10500 */
10501
10502static VALUE
10503rb_f_readline(int argc, VALUE *argv, VALUE recv)
10504{
10505 if (recv == argf) {
10506 return argf_readline(argc, argv, argf);
10507 }
10508 return forward(argf, rb_intern("readline"), argc, argv);
10509}
10510
10511
10512/*
10513 * call-seq:
10514 * ARGF.readline(sep=$/) -> string
10515 * ARGF.readline(limit) -> string
10516 * ARGF.readline(sep, limit) -> string
10517 *
10518 * Returns the next line from the current file in ARGF.
10519 *
10520 * By default lines are assumed to be separated by <code>$/</code>;
10521 * to use a different character as a separator, supply it as a String
10522 * for the _sep_ argument.
10523 *
10524 * The optional _limit_ argument specifies how many characters of each line
10525 * to return. By default all characters are returned.
10526 *
10527 * An EOFError is raised at the end of the file.
10528 */
10529static VALUE
10530argf_readline(int argc, VALUE *argv, VALUE argf)
10531{
10532 VALUE line;
10533
10534 if (!next_argv()) rb_eof_error();
10535 ARGF_FORWARD(argc, argv);
10536 line = argf_gets(argc, argv, argf);
10537 if (NIL_P(line)) {
10538 rb_eof_error();
10539 }
10540
10541 return line;
10542}
10543
10544static VALUE argf_readlines(int, VALUE *, VALUE);
10545
10546/*
10547 * call-seq:
10548 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10549 * readlines(limit, chomp: false, **enc_opts) -> array
10550 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10551 *
10552 * Returns an array containing the lines returned by calling
10553 * Kernel#gets until the end-of-stream is reached;
10554 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10555 *
10556 * With only string argument +sep+ given,
10557 * returns the remaining lines as determined by line separator +sep+,
10558 * or +nil+ if none;
10559 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10560 *
10561 * # Default separator.
10562 * $ cat t.txt | ruby -e "p readlines"
10563 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10564 *
10565 * # Specified separator.
10566 * $ cat t.txt | ruby -e "p readlines 'li'"
10567 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10568 *
10569 * # Get-all separator.
10570 * $ cat t.txt | ruby -e "p readlines nil"
10571 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10572 *
10573 * # Get-paragraph separator.
10574 * $ cat t.txt | ruby -e "p readlines ''"
10575 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10576 *
10577 * With only integer argument +limit+ given,
10578 * limits the number of bytes in the line;
10579 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10580 *
10581 * $cat t.txt | ruby -e "p readlines 10"
10582 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10583 *
10584 * $cat t.txt | ruby -e "p readlines 11"
10585 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10586 *
10587 * $cat t.txt | ruby -e "p readlines 12"
10588 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10589 *
10590 * With arguments +sep+ and +limit+ given,
10591 * combines the two behaviors
10592 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10593 *
10594 * Optional keyword argument +chomp+ specifies whether line separators
10595 * are to be omitted:
10596 *
10597 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10598 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10599 *
10600 * Optional keyword arguments +enc_opts+ specify encoding options;
10601 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10602 *
10603 */
10604
10605static VALUE
10606rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10607{
10608 if (recv == argf) {
10609 return argf_readlines(argc, argv, argf);
10610 }
10611 return forward(argf, rb_intern("readlines"), argc, argv);
10612}
10613
10614/*
10615 * call-seq:
10616 * ARGF.readlines(sep = $/, chomp: false) -> array
10617 * ARGF.readlines(limit, chomp: false) -> array
10618 * ARGF.readlines(sep, limit, chomp: false) -> array
10619 *
10620 * ARGF.to_a(sep = $/, chomp: false) -> array
10621 * ARGF.to_a(limit, chomp: false) -> array
10622 * ARGF.to_a(sep, limit, chomp: false) -> array
10623 *
10624 * Reads each file in ARGF in its entirety, returning an Array containing
10625 * lines from the files. Lines are assumed to be separated by _sep_.
10626 *
10627 * lines = ARGF.readlines
10628 * lines[0] #=> "This is line one\n"
10629 *
10630 * See +IO.readlines+ for a full description of all options.
10631 */
10632static VALUE
10633argf_readlines(int argc, VALUE *argv, VALUE argf)
10634{
10635 long lineno = ARGF.lineno;
10636 VALUE lines, ary;
10637
10638 ary = rb_ary_new();
10639 while (next_argv()) {
10640 if (ARGF_GENERIC_INPUT_P()) {
10641 lines = forward_current(rb_intern("readlines"), argc, argv);
10642 }
10643 else {
10644 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10645 argf_close(argf);
10646 }
10647 ARGF.next_p = 1;
10648 rb_ary_concat(ary, lines);
10649 ARGF.lineno = lineno + RARRAY_LEN(ary);
10650 ARGF.last_lineno = ARGF.lineno;
10651 }
10652 ARGF.init_p = 0;
10653 return ary;
10654}
10655
10656/*
10657 * call-seq:
10658 * `command` -> string
10659 *
10660 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10661 * sets global variable <tt>$?</tt> to the process status.
10662 *
10663 * This method has potential security vulnerabilities if called with untrusted input;
10664 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10665 *
10666 * Examples:
10667 *
10668 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10669 * $ `echo oops && exit 99` # => "oops\n"
10670 * $ $? # => #<Process::Status: pid 17088 exit 99>
10671 * $ $?.status # => 99>
10672 *
10673 * The built-in syntax <tt>%x{...}</tt> uses this method.
10674 *
10675 */
10676
10677static VALUE
10678rb_f_backquote(VALUE obj, VALUE str)
10679{
10680 VALUE port;
10681 VALUE result;
10682 rb_io_t *fptr;
10683
10684 StringValue(str);
10685 rb_last_status_clear();
10686 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10687 if (NIL_P(port)) return rb_str_new(0,0);
10688
10689 GetOpenFile(port, fptr);
10690 result = read_all(fptr, remain_size(fptr), Qnil);
10691 rb_io_close(port);
10692 rb_io_fptr_cleanup_all(fptr);
10693 RB_GC_GUARD(port);
10694
10695 return result;
10696}
10697
10698#ifdef HAVE_SYS_SELECT_H
10699#include <sys/select.h>
10700#endif
10701
10702static VALUE
10703select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10704{
10705 VALUE res, list;
10706 rb_fdset_t *rp, *wp, *ep;
10707 rb_io_t *fptr;
10708 long i;
10709 int max = 0, n;
10710 int pending = 0;
10711 struct timeval timerec;
10712
10713 if (!NIL_P(read)) {
10714 Check_Type(read, T_ARRAY);
10715 for (i=0; i<RARRAY_LEN(read); i++) {
10716 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10717 rb_fd_set(fptr->fd, &fds[0]);
10718 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10719 pending++;
10720 rb_fd_set(fptr->fd, &fds[3]);
10721 }
10722 if (max < fptr->fd) max = fptr->fd;
10723 }
10724 if (pending) { /* no blocking if there's buffered data */
10725 timerec.tv_sec = timerec.tv_usec = 0;
10726 tp = &timerec;
10727 }
10728 rp = &fds[0];
10729 }
10730 else
10731 rp = 0;
10732
10733 if (!NIL_P(write)) {
10734 Check_Type(write, T_ARRAY);
10735 for (i=0; i<RARRAY_LEN(write); i++) {
10736 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10737 GetOpenFile(write_io, fptr);
10738 rb_fd_set(fptr->fd, &fds[1]);
10739 if (max < fptr->fd) max = fptr->fd;
10740 }
10741 wp = &fds[1];
10742 }
10743 else
10744 wp = 0;
10745
10746 if (!NIL_P(except)) {
10747 Check_Type(except, T_ARRAY);
10748 for (i=0; i<RARRAY_LEN(except); i++) {
10749 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10750 VALUE write_io = GetWriteIO(io);
10751 GetOpenFile(io, fptr);
10752 rb_fd_set(fptr->fd, &fds[2]);
10753 if (max < fptr->fd) max = fptr->fd;
10754 if (io != write_io) {
10755 GetOpenFile(write_io, fptr);
10756 rb_fd_set(fptr->fd, &fds[2]);
10757 if (max < fptr->fd) max = fptr->fd;
10758 }
10759 }
10760 ep = &fds[2];
10761 }
10762 else {
10763 ep = 0;
10764 }
10765
10766 max++;
10767
10768 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10769 if (n < 0) {
10770 rb_sys_fail(0);
10771 }
10772 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10773
10774 res = rb_ary_new2(3);
10775 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10776 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10777 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10778
10779 if (rp) {
10780 list = RARRAY_AREF(res, 0);
10781 for (i=0; i< RARRAY_LEN(read); i++) {
10782 VALUE obj = rb_ary_entry(read, i);
10783 VALUE io = rb_io_get_io(obj);
10784 GetOpenFile(io, fptr);
10785 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10786 rb_fd_isset(fptr->fd, &fds[3])) {
10787 rb_ary_push(list, obj);
10788 }
10789 }
10790 }
10791
10792 if (wp) {
10793 list = RARRAY_AREF(res, 1);
10794 for (i=0; i< RARRAY_LEN(write); i++) {
10795 VALUE obj = rb_ary_entry(write, i);
10796 VALUE io = rb_io_get_io(obj);
10797 VALUE write_io = GetWriteIO(io);
10798 GetOpenFile(write_io, fptr);
10799 if (rb_fd_isset(fptr->fd, &fds[1])) {
10800 rb_ary_push(list, obj);
10801 }
10802 }
10803 }
10804
10805 if (ep) {
10806 list = RARRAY_AREF(res, 2);
10807 for (i=0; i< RARRAY_LEN(except); i++) {
10808 VALUE obj = rb_ary_entry(except, i);
10809 VALUE io = rb_io_get_io(obj);
10810 VALUE write_io = GetWriteIO(io);
10811 GetOpenFile(io, fptr);
10812 if (rb_fd_isset(fptr->fd, &fds[2])) {
10813 rb_ary_push(list, obj);
10814 }
10815 else if (io != write_io) {
10816 GetOpenFile(write_io, fptr);
10817 if (rb_fd_isset(fptr->fd, &fds[2])) {
10818 rb_ary_push(list, obj);
10819 }
10820 }
10821 }
10822 }
10823
10824 return res; /* returns an empty array on interrupt */
10825}
10826
10828 VALUE read, write, except;
10829 struct timeval *timeout;
10830 rb_fdset_t fdsets[4];
10831};
10832
10833static VALUE
10834select_call(VALUE arg)
10835{
10836 struct select_args *p = (struct select_args *)arg;
10837
10838 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10839}
10840
10841static VALUE
10842select_end(VALUE arg)
10843{
10844 struct select_args *p = (struct select_args *)arg;
10845 int i;
10846
10847 for (i = 0; i < numberof(p->fdsets); ++i)
10848 rb_fd_term(&p->fdsets[i]);
10849 return Qnil;
10850}
10851
10852static VALUE sym_normal, sym_sequential, sym_random,
10853 sym_willneed, sym_dontneed, sym_noreuse;
10854
10855#ifdef HAVE_POSIX_FADVISE
10856struct io_advise_struct {
10857 int fd;
10858 int advice;
10859 rb_off_t offset;
10860 rb_off_t len;
10861};
10862
10863static VALUE
10864io_advise_internal(void *arg)
10865{
10866 struct io_advise_struct *ptr = arg;
10867 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10868}
10869
10870static VALUE
10871io_advise_sym_to_const(VALUE sym)
10872{
10873#ifdef POSIX_FADV_NORMAL
10874 if (sym == sym_normal)
10875 return INT2NUM(POSIX_FADV_NORMAL);
10876#endif
10877
10878#ifdef POSIX_FADV_RANDOM
10879 if (sym == sym_random)
10880 return INT2NUM(POSIX_FADV_RANDOM);
10881#endif
10882
10883#ifdef POSIX_FADV_SEQUENTIAL
10884 if (sym == sym_sequential)
10885 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10886#endif
10887
10888#ifdef POSIX_FADV_WILLNEED
10889 if (sym == sym_willneed)
10890 return INT2NUM(POSIX_FADV_WILLNEED);
10891#endif
10892
10893#ifdef POSIX_FADV_DONTNEED
10894 if (sym == sym_dontneed)
10895 return INT2NUM(POSIX_FADV_DONTNEED);
10896#endif
10897
10898#ifdef POSIX_FADV_NOREUSE
10899 if (sym == sym_noreuse)
10900 return INT2NUM(POSIX_FADV_NOREUSE);
10901#endif
10902
10903 return Qnil;
10904}
10905
10906static VALUE
10907do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10908{
10909 int rv;
10910 struct io_advise_struct ias;
10911 VALUE num_adv;
10912
10913 num_adv = io_advise_sym_to_const(advice);
10914
10915 /*
10916 * The platform doesn't support this hint. We don't raise exception, instead
10917 * silently ignore it. Because IO::advise is only hint.
10918 */
10919 if (NIL_P(num_adv))
10920 return Qnil;
10921
10922 ias.fd = fptr->fd;
10923 ias.advice = NUM2INT(num_adv);
10924 ias.offset = offset;
10925 ias.len = len;
10926
10927 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10928 if (rv && rv != ENOSYS) {
10929 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10930 it returns the error code. */
10931 VALUE message = rb_sprintf("%"PRIsVALUE" "
10932 "(%"PRI_OFFT_PREFIX"d, "
10933 "%"PRI_OFFT_PREFIX"d, "
10934 "%"PRIsVALUE")",
10935 fptr->pathv, offset, len, advice);
10936 rb_syserr_fail_str(rv, message);
10937 }
10938
10939 return Qnil;
10940}
10941
10942#endif /* HAVE_POSIX_FADVISE */
10943
10944static void
10945advice_arg_check(VALUE advice)
10946{
10947 if (!SYMBOL_P(advice))
10948 rb_raise(rb_eTypeError, "advice must be a Symbol");
10949
10950 if (advice != sym_normal &&
10951 advice != sym_sequential &&
10952 advice != sym_random &&
10953 advice != sym_willneed &&
10954 advice != sym_dontneed &&
10955 advice != sym_noreuse) {
10956 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10957 }
10958}
10959
10960/*
10961 * call-seq:
10962 * advise(advice, offset = 0, len = 0) -> nil
10963 *
10964 * Invokes Posix system call
10965 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10966 * which announces an intention to access data from the current file
10967 * in a particular manner.
10968 *
10969 * The arguments and results are platform-dependent.
10970 *
10971 * The relevant data is specified by:
10972 *
10973 * - +offset+: The offset of the first byte of data.
10974 * - +len+: The number of bytes to be accessed;
10975 * if +len+ is zero, or is larger than the number of bytes remaining,
10976 * all remaining bytes will be accessed.
10977 *
10978 * Argument +advice+ is one of the following symbols:
10979 *
10980 * - +:normal+: The application has no advice to give
10981 * about its access pattern for the specified data.
10982 * If no advice is given for an open file, this is the default assumption.
10983 * - +:sequential+: The application expects to access the specified data sequentially
10984 * (with lower offsets read before higher ones).
10985 * - +:random+: The specified data will be accessed in random order.
10986 * - +:noreuse+: The specified data will be accessed only once.
10987 * - +:willneed+: The specified data will be accessed in the near future.
10988 * - +:dontneed+: The specified data will not be accessed in the near future.
10989 *
10990 * Not implemented on all platforms.
10991 *
10992 */
10993static VALUE
10994rb_io_advise(int argc, VALUE *argv, VALUE io)
10995{
10996 VALUE advice, offset, len;
10997 rb_off_t off, l;
10998 rb_io_t *fptr;
10999
11000 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
11001 advice_arg_check(advice);
11002
11003 io = GetWriteIO(io);
11004 GetOpenFile(io, fptr);
11005
11006 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
11007 l = NIL_P(len) ? 0 : NUM2OFFT(len);
11008
11009#ifdef HAVE_POSIX_FADVISE
11010 return do_io_advise(fptr, advice, off, l);
11011#else
11012 ((void)off, (void)l); /* Ignore all hint */
11013 return Qnil;
11014#endif
11015}
11016
11017static int
11018is_pos_inf(VALUE x)
11019{
11020 double f;
11021 if (!RB_FLOAT_TYPE_P(x))
11022 return 0;
11023 f = RFLOAT_VALUE(x);
11024 return isinf(f) && 0 < f;
11025}
11026
11027/*
11028 * call-seq:
11029 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11030 *
11031 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
11032 * which monitors multiple file descriptors,
11033 * waiting until one or more of the file descriptors
11034 * becomes ready for some class of I/O operation.
11035 *
11036 * Not implemented on all platforms.
11037 *
11038 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11039 * is an array of IO objects.
11040 *
11041 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11042 * interval in seconds.
11043 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11044 * +nil+ and +Float::INFINITY+ means no timeout.
11045 *
11046 * The method monitors the \IO objects given in all three arrays,
11047 * waiting for some to be ready;
11048 * returns a 3-element array whose elements are:
11049 *
11050 * - An array of the objects in +read_ios+ that are ready for reading.
11051 * - An array of the objects in +write_ios+ that are ready for writing.
11052 * - An array of the objects in +error_ios+ have pending exceptions.
11053 *
11054 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11055 *
11056 * \IO.select peeks the buffer of \IO objects for testing readability.
11057 * If the \IO buffer is not empty, \IO.select immediately notifies
11058 * readability. This "peek" only happens for \IO objects. It does not
11059 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11060 *
11061 * The best way to use \IO.select is invoking it after non-blocking
11062 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11063 * raise an exception which is extended by IO::WaitReadable or
11064 * IO::WaitWritable. The modules notify how the caller should wait
11065 * with \IO.select. If IO::WaitReadable is raised, the caller should
11066 * wait for reading. If IO::WaitWritable is raised, the caller should
11067 * wait for writing.
11068 *
11069 * So, blocking read (#readpartial) can be emulated using
11070 * #read_nonblock and \IO.select as follows:
11071 *
11072 * begin
11073 * result = io_like.read_nonblock(maxlen)
11074 * rescue IO::WaitReadable
11075 * IO.select([io_like])
11076 * retry
11077 * rescue IO::WaitWritable
11078 * IO.select(nil, [io_like])
11079 * retry
11080 * end
11081 *
11082 * Especially, the combination of non-blocking methods and \IO.select is
11083 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11084 * has #to_io method to return underlying IO object. IO.select calls
11085 * #to_io to obtain the file descriptor to wait.
11086 *
11087 * This means that readability notified by \IO.select doesn't mean
11088 * readability from OpenSSL::SSL::SSLSocket object.
11089 *
11090 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11091 * some data. \IO.select doesn't see the buffer. So \IO.select can
11092 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11093 *
11094 * However, several more complicated situations exist.
11095 *
11096 * SSL is a protocol which is sequence of records.
11097 * The record consists of multiple bytes.
11098 * So, the remote side of SSL sends a partial record, IO.select
11099 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11100 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11101 *
11102 * Also, the remote side can request SSL renegotiation which forces
11103 * the local SSL engine to write some data.
11104 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11105 * system call and it can block.
11106 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11107 * IO::WaitWritable instead of blocking.
11108 * So, the caller should wait for ready for writability as above
11109 * example.
11110 *
11111 * The combination of non-blocking methods and \IO.select is also useful
11112 * for streams such as tty, pipe socket socket when multiple processes
11113 * read from a stream.
11114 *
11115 * Finally, Linux kernel developers don't guarantee that
11116 * readability of select(2) means readability of following read(2) even
11117 * for a single process;
11118 * see {select(2)}[https://linux.die.net/man/2/select]
11119 *
11120 * Invoking \IO.select before IO#readpartial works well as usual.
11121 * However it is not the best way to use \IO.select.
11122 *
11123 * The writability notified by select(2) doesn't show
11124 * how many bytes are writable.
11125 * IO#write method blocks until given whole string is written.
11126 * So, <tt>IO#write(two or more bytes)</tt> can block after
11127 * writability is notified by \IO.select. IO#write_nonblock is required
11128 * to avoid the blocking.
11129 *
11130 * Blocking write (#write) can be emulated using #write_nonblock and
11131 * IO.select as follows: IO::WaitReadable should also be rescued for
11132 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11133 *
11134 * while 0 < string.bytesize
11135 * begin
11136 * written = io_like.write_nonblock(string)
11137 * rescue IO::WaitReadable
11138 * IO.select([io_like])
11139 * retry
11140 * rescue IO::WaitWritable
11141 * IO.select(nil, [io_like])
11142 * retry
11143 * end
11144 * string = string.byteslice(written..-1)
11145 * end
11146 *
11147 * Example:
11148 *
11149 * rp, wp = IO.pipe
11150 * mesg = "ping "
11151 * 100.times {
11152 * # IO.select follows IO#read. Not the best way to use IO.select.
11153 * rs, ws, = IO.select([rp], [wp])
11154 * if r = rs[0]
11155 * ret = r.read(5)
11156 * print ret
11157 * case ret
11158 * when /ping/
11159 * mesg = "pong\n"
11160 * when /pong/
11161 * mesg = "ping "
11162 * end
11163 * end
11164 * if w = ws[0]
11165 * w.write(mesg)
11166 * end
11167 * }
11168 *
11169 * Output:
11170 *
11171 * ping pong
11172 * ping pong
11173 * ping pong
11174 * (snipped)
11175 * ping
11176 *
11177 */
11178
11179static VALUE
11180rb_f_select(int argc, VALUE *argv, VALUE obj)
11181{
11182 VALUE scheduler = rb_fiber_scheduler_current();
11183 if (scheduler != Qnil) {
11184 // It's optionally supported.
11185 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11186 if (!UNDEF_P(result)) return result;
11187 }
11188
11189 VALUE timeout;
11190 struct select_args args;
11191 struct timeval timerec;
11192 int i;
11193
11194 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11195 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11196 args.timeout = 0;
11197 }
11198 else {
11199 timerec = rb_time_interval(timeout);
11200 args.timeout = &timerec;
11201 }
11202
11203 for (i = 0; i < numberof(args.fdsets); ++i)
11204 rb_fd_init(&args.fdsets[i]);
11205
11206 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11207}
11208
11209#ifdef IOCTL_REQ_TYPE
11210 typedef IOCTL_REQ_TYPE ioctl_req_t;
11211#else
11212 typedef int ioctl_req_t;
11213# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11214#endif
11215
11216#ifdef HAVE_IOCTL
11217struct ioctl_arg {
11218 int fd;
11219 ioctl_req_t cmd;
11220 long narg;
11221};
11222
11223static VALUE
11224nogvl_ioctl(void *ptr)
11225{
11226 struct ioctl_arg *arg = ptr;
11227
11228 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11229}
11230
11231static int
11232do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11233{
11234 int retval;
11235 struct ioctl_arg arg;
11236
11237 arg.fd = io->fd;
11238 arg.cmd = cmd;
11239 arg.narg = narg;
11240
11241 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11242
11243 return retval;
11244}
11245#endif
11246
11247#define DEFAULT_IOCTL_NARG_LEN (256)
11248
11249#if defined(__linux__) && defined(_IOC_SIZE)
11250static long
11251linux_iocparm_len(ioctl_req_t cmd)
11252{
11253 long len;
11254
11255 if ((cmd & 0xFFFF0000) == 0) {
11256 /* legacy and unstructured ioctl number. */
11257 return DEFAULT_IOCTL_NARG_LEN;
11258 }
11259
11260 len = _IOC_SIZE(cmd);
11261
11262 /* paranoia check for silly drivers which don't keep ioctl convention */
11263 if (len < DEFAULT_IOCTL_NARG_LEN)
11264 len = DEFAULT_IOCTL_NARG_LEN;
11265
11266 return len;
11267}
11268#endif
11269
11270#ifdef HAVE_IOCTL
11271static long
11272ioctl_narg_len(ioctl_req_t cmd)
11273{
11274 long len;
11275
11276#ifdef IOCPARM_MASK
11277#ifndef IOCPARM_LEN
11278#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11279#endif
11280#endif
11281#ifdef IOCPARM_LEN
11282 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11283#elif defined(__linux__) && defined(_IOC_SIZE)
11284 len = linux_iocparm_len(cmd);
11285#else
11286 /* otherwise guess at what's safe */
11287 len = DEFAULT_IOCTL_NARG_LEN;
11288#endif
11289
11290 return len;
11291}
11292#endif
11293
11294#ifdef HAVE_FCNTL
11295#ifdef __linux__
11296typedef long fcntl_arg_t;
11297#else
11298/* posix */
11299typedef int fcntl_arg_t;
11300#endif
11301
11302static long
11303fcntl_narg_len(ioctl_req_t cmd)
11304{
11305 long len;
11306
11307 switch (cmd) {
11308#ifdef F_DUPFD
11309 case F_DUPFD:
11310 len = sizeof(fcntl_arg_t);
11311 break;
11312#endif
11313#ifdef F_DUP2FD /* bsd specific */
11314 case F_DUP2FD:
11315 len = sizeof(int);
11316 break;
11317#endif
11318#ifdef F_DUPFD_CLOEXEC /* linux specific */
11319 case F_DUPFD_CLOEXEC:
11320 len = sizeof(fcntl_arg_t);
11321 break;
11322#endif
11323#ifdef F_GETFD
11324 case F_GETFD:
11325 len = 1;
11326 break;
11327#endif
11328#ifdef F_SETFD
11329 case F_SETFD:
11330 len = sizeof(fcntl_arg_t);
11331 break;
11332#endif
11333#ifdef F_GETFL
11334 case F_GETFL:
11335 len = 1;
11336 break;
11337#endif
11338#ifdef F_SETFL
11339 case F_SETFL:
11340 len = sizeof(fcntl_arg_t);
11341 break;
11342#endif
11343#ifdef F_GETOWN
11344 case F_GETOWN:
11345 len = 1;
11346 break;
11347#endif
11348#ifdef F_SETOWN
11349 case F_SETOWN:
11350 len = sizeof(fcntl_arg_t);
11351 break;
11352#endif
11353#ifdef F_GETOWN_EX /* linux specific */
11354 case F_GETOWN_EX:
11355 len = sizeof(struct f_owner_ex);
11356 break;
11357#endif
11358#ifdef F_SETOWN_EX /* linux specific */
11359 case F_SETOWN_EX:
11360 len = sizeof(struct f_owner_ex);
11361 break;
11362#endif
11363#ifdef F_GETLK
11364 case F_GETLK:
11365 len = sizeof(struct flock);
11366 break;
11367#endif
11368#ifdef F_SETLK
11369 case F_SETLK:
11370 len = sizeof(struct flock);
11371 break;
11372#endif
11373#ifdef F_SETLKW
11374 case F_SETLKW:
11375 len = sizeof(struct flock);
11376 break;
11377#endif
11378#ifdef F_READAHEAD /* bsd specific */
11379 case F_READAHEAD:
11380 len = sizeof(int);
11381 break;
11382#endif
11383#ifdef F_RDAHEAD /* Darwin specific */
11384 case F_RDAHEAD:
11385 len = sizeof(int);
11386 break;
11387#endif
11388#ifdef F_GETSIG /* linux specific */
11389 case F_GETSIG:
11390 len = 1;
11391 break;
11392#endif
11393#ifdef F_SETSIG /* linux specific */
11394 case F_SETSIG:
11395 len = sizeof(fcntl_arg_t);
11396 break;
11397#endif
11398#ifdef F_GETLEASE /* linux specific */
11399 case F_GETLEASE:
11400 len = 1;
11401 break;
11402#endif
11403#ifdef F_SETLEASE /* linux specific */
11404 case F_SETLEASE:
11405 len = sizeof(fcntl_arg_t);
11406 break;
11407#endif
11408#ifdef F_NOTIFY /* linux specific */
11409 case F_NOTIFY:
11410 len = sizeof(fcntl_arg_t);
11411 break;
11412#endif
11413
11414 default:
11415 len = 256;
11416 break;
11417 }
11418
11419 return len;
11420}
11421#else /* HAVE_FCNTL */
11422static long
11423fcntl_narg_len(ioctl_req_t cmd)
11424{
11425 return 0;
11426}
11427#endif /* HAVE_FCNTL */
11428
11429#define NARG_SENTINEL 17
11430
11431static long
11432setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11433{
11434 long narg = 0;
11435 VALUE arg = *argp;
11436
11437 if (!RTEST(arg)) {
11438 narg = 0;
11439 }
11440 else if (FIXNUM_P(arg)) {
11441 narg = FIX2LONG(arg);
11442 }
11443 else if (arg == Qtrue) {
11444 narg = 1;
11445 }
11446 else {
11447 VALUE tmp = rb_check_string_type(arg);
11448
11449 if (NIL_P(tmp)) {
11450 narg = NUM2LONG(arg);
11451 }
11452 else {
11453 char *ptr;
11454 long len, slen;
11455
11456 *argp = arg = tmp;
11457 len = narg_len(cmd);
11458 rb_str_modify(arg);
11459
11460 slen = RSTRING_LEN(arg);
11461 /* expand for data + sentinel. */
11462 if (slen < len+1) {
11463 rb_str_resize(arg, len+1);
11464 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11465 slen = len+1;
11466 }
11467 /* a little sanity check here */
11468 ptr = RSTRING_PTR(arg);
11469 ptr[slen - 1] = NARG_SENTINEL;
11470 narg = (long)(SIGNED_VALUE)ptr;
11471 }
11472 }
11473
11474 return narg;
11475}
11476
11477static VALUE
11478finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11479{
11480 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11481 if (RB_TYPE_P(arg, T_STRING)) {
11482 char *ptr;
11483 long slen;
11484 RSTRING_GETMEM(arg, ptr, slen);
11485 if (ptr[slen-1] != NARG_SENTINEL)
11486 rb_raise(rb_eArgError, "return value overflowed string");
11487 ptr[slen-1] = '\0';
11488 }
11489
11490 return INT2NUM(retval);
11491}
11492
11493#ifdef HAVE_IOCTL
11494static VALUE
11495rb_ioctl(VALUE io, VALUE req, VALUE arg)
11496{
11497 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11498 rb_io_t *fptr;
11499 long narg;
11500 int retval;
11501
11502 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11503 GetOpenFile(io, fptr);
11504 retval = do_ioctl(fptr, cmd, narg);
11505 return finish_narg(retval, arg, fptr);
11506}
11507
11508/*
11509 * call-seq:
11510 * ioctl(integer_cmd, argument) -> integer
11511 *
11512 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11513 * which issues a low-level command to an I/O device.
11514 *
11515 * Issues a low-level command to an I/O device.
11516 * The arguments and returned value are platform-dependent.
11517 * The effect of the call is platform-dependent.
11518 *
11519 * If argument +argument+ is an integer, it is passed directly;
11520 * if it is a string, it is interpreted as a binary sequence of bytes.
11521 *
11522 * Not implemented on all platforms.
11523 *
11524 */
11525
11526static VALUE
11527rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11528{
11529 VALUE req, arg;
11530
11531 rb_scan_args(argc, argv, "11", &req, &arg);
11532 return rb_ioctl(io, req, arg);
11533}
11534#else
11535#define rb_io_ioctl rb_f_notimplement
11536#endif
11537
11538#ifdef HAVE_FCNTL
11539struct fcntl_arg {
11540 int fd;
11541 int cmd;
11542 long narg;
11543};
11544
11545static VALUE
11546nogvl_fcntl(void *ptr)
11547{
11548 struct fcntl_arg *arg = ptr;
11549
11550#if defined(F_DUPFD)
11551 if (arg->cmd == F_DUPFD)
11552 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11553#endif
11554 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11555}
11556
11557static int
11558do_fcntl(struct rb_io *io, int cmd, long narg)
11559{
11560 int retval;
11561 struct fcntl_arg arg;
11562
11563 arg.fd = io->fd;
11564 arg.cmd = cmd;
11565 arg.narg = narg;
11566
11567 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11568 if (retval != -1) {
11569 switch (cmd) {
11570#if defined(F_DUPFD)
11571 case F_DUPFD:
11572#endif
11573#if defined(F_DUPFD_CLOEXEC)
11574 case F_DUPFD_CLOEXEC:
11575#endif
11576 rb_update_max_fd(retval);
11577 }
11578 }
11579
11580 return retval;
11581}
11582
11583static VALUE
11584rb_fcntl(VALUE io, VALUE req, VALUE arg)
11585{
11586 int cmd = NUM2INT(req);
11587 rb_io_t *fptr;
11588 long narg;
11589 int retval;
11590
11591 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11592 GetOpenFile(io, fptr);
11593 retval = do_fcntl(fptr, cmd, narg);
11594 return finish_narg(retval, arg, fptr);
11595}
11596
11597/*
11598 * call-seq:
11599 * fcntl(integer_cmd, argument) -> integer
11600 *
11601 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11602 * which provides a mechanism for issuing low-level commands to control or query
11603 * a file-oriented I/O stream. Arguments and results are platform
11604 * dependent.
11605 *
11606 * If +argument+ is a number, its value is passed directly;
11607 * if it is a string, it is interpreted as a binary sequence of bytes.
11608 * (Array#pack might be a useful way to build this string.)
11609 *
11610 * Not implemented on all platforms.
11611 *
11612 */
11613
11614static VALUE
11615rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11616{
11617 VALUE req, arg;
11618
11619 rb_scan_args(argc, argv, "11", &req, &arg);
11620 return rb_fcntl(io, req, arg);
11621}
11622#else
11623#define rb_io_fcntl rb_f_notimplement
11624#endif
11625
11626#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11627/*
11628 * call-seq:
11629 * syscall(integer_callno, *arguments) -> integer
11630 *
11631 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11632 * which calls a specified function.
11633 *
11634 * Calls the operating system function identified by +integer_callno+;
11635 * returns the result of the function or raises SystemCallError if it failed.
11636 * The effect of the call is platform-dependent.
11637 * The arguments and returned value are platform-dependent.
11638 *
11639 * For each of +arguments+: if it is an integer, it is passed directly;
11640 * if it is a string, it is interpreted as a binary sequence of bytes.
11641 * There may be as many as nine such arguments.
11642 *
11643 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11644 * are platform-dependent.
11645 *
11646 * Note: Method +syscall+ is essentially unsafe and unportable.
11647 * The DL (Fiddle) library is preferred for safer and a bit
11648 * more portable programming.
11649 *
11650 * Not implemented on all platforms.
11651 *
11652 */
11653
11654static VALUE
11655rb_f_syscall(int argc, VALUE *argv, VALUE _)
11656{
11657 VALUE arg[8];
11658#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11659# define SYSCALL __syscall
11660# define NUM2SYSCALLID(x) NUM2LONG(x)
11661# define RETVAL2NUM(x) LONG2NUM(x)
11662# if SIZEOF_LONG == 8
11663 long num, retval = -1;
11664# elif SIZEOF_LONG_LONG == 8
11665 long long num, retval = -1;
11666# else
11667# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11668# endif
11669#elif defined(__linux__)
11670# define SYSCALL syscall
11671# define NUM2SYSCALLID(x) NUM2LONG(x)
11672# define RETVAL2NUM(x) LONG2NUM(x)
11673 /*
11674 * Linux man page says, syscall(2) function prototype is below.
11675 *
11676 * int syscall(int number, ...);
11677 *
11678 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11679 */
11680 long num, retval = -1;
11681#else
11682# define SYSCALL syscall
11683# define NUM2SYSCALLID(x) NUM2INT(x)
11684# define RETVAL2NUM(x) INT2NUM(x)
11685 int num, retval = -1;
11686#endif
11687 int i;
11688
11689 if (RTEST(ruby_verbose)) {
11691 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11692 }
11693
11694 if (argc == 0)
11695 rb_raise(rb_eArgError, "too few arguments for syscall");
11696 if (argc > numberof(arg))
11697 rb_raise(rb_eArgError, "too many arguments for syscall");
11698 num = NUM2SYSCALLID(argv[0]); ++argv;
11699 for (i = argc - 1; i--; ) {
11700 VALUE v = rb_check_string_type(argv[i]);
11701
11702 if (!NIL_P(v)) {
11703 StringValue(v);
11704 rb_str_modify(v);
11705 arg[i] = (VALUE)StringValueCStr(v);
11706 }
11707 else {
11708 arg[i] = (VALUE)NUM2LONG(argv[i]);
11709 }
11710 }
11711
11712 switch (argc) {
11713 case 1:
11714 retval = SYSCALL(num);
11715 break;
11716 case 2:
11717 retval = SYSCALL(num, arg[0]);
11718 break;
11719 case 3:
11720 retval = SYSCALL(num, arg[0],arg[1]);
11721 break;
11722 case 4:
11723 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11724 break;
11725 case 5:
11726 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11727 break;
11728 case 6:
11729 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11730 break;
11731 case 7:
11732 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11733 break;
11734 case 8:
11735 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11736 break;
11737 }
11738
11739 if (retval == -1)
11740 rb_sys_fail(0);
11741 return RETVAL2NUM(retval);
11742#undef SYSCALL
11743#undef NUM2SYSCALLID
11744#undef RETVAL2NUM
11745}
11746#else
11747#define rb_f_syscall rb_f_notimplement
11748#endif
11749
11750static VALUE
11751io_new_instance(VALUE args)
11752{
11753 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11754}
11755
11756static rb_encoding *
11757find_encoding(VALUE v)
11758{
11759 rb_encoding *enc = rb_find_encoding(v);
11760 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11761 return enc;
11762}
11763
11764static void
11765io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11766{
11767 rb_encoding *enc, *enc2;
11768 int ecflags = fptr->encs.ecflags;
11769 VALUE ecopts, tmp;
11770
11771 if (!NIL_P(v2)) {
11772 enc2 = find_encoding(v1);
11773 tmp = rb_check_string_type(v2);
11774 if (!NIL_P(tmp)) {
11775 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11776 /* Special case - "-" => no transcoding */
11777 enc = enc2;
11778 enc2 = NULL;
11779 }
11780 else
11781 enc = find_encoding(v2);
11782 if (enc == enc2) {
11783 /* Special case - "-" => no transcoding */
11784 enc2 = NULL;
11785 }
11786 }
11787 else {
11788 enc = find_encoding(v2);
11789 if (enc == enc2) {
11790 /* Special case - "-" => no transcoding */
11791 enc2 = NULL;
11792 }
11793 }
11794 if (enc2 == rb_ascii8bit_encoding()) {
11795 /* If external is ASCII-8BIT, no transcoding */
11796 enc = enc2;
11797 enc2 = NULL;
11798 }
11799 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11800 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11801 }
11802 else {
11803 if (NIL_P(v1)) {
11804 /* Set to default encodings */
11805 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11806 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11807 ecopts = Qnil;
11808 }
11809 else {
11810 tmp = rb_check_string_type(v1);
11811 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11812 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11813 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11814 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11815 }
11816 else {
11817 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11818 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11819 ecopts = Qnil;
11820 }
11821 }
11822 }
11823 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11824 fptr->encs.enc = enc;
11825 fptr->encs.enc2 = enc2;
11826 fptr->encs.ecflags = ecflags;
11827 fptr->encs.ecopts = ecopts;
11828 clear_codeconv(fptr);
11829
11830}
11831
11833 rb_io_t *fptr;
11834 VALUE v1;
11835 VALUE v2;
11836 VALUE opt;
11837};
11838
11839static VALUE
11840io_encoding_set_v(VALUE v)
11841{
11842 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11843 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11844 return Qnil;
11845}
11846
11847static VALUE
11848pipe_pair_close(VALUE rw)
11849{
11850 VALUE *rwp = (VALUE *)rw;
11851 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11852}
11853
11854/*
11855 * call-seq:
11856 * IO.pipe(**opts) -> [read_io, write_io]
11857 * IO.pipe(enc, **opts) -> [read_io, write_io]
11858 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11859 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11860 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11861 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11862 *
11863 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11864 * connected to each other.
11865 *
11866 * If argument +enc_string+ is given, it must be a string containing one of:
11867 *
11868 * - The name of the encoding to be used as the external encoding.
11869 * - The colon-separated names of two encodings to be used as the external
11870 * and internal encodings.
11871 *
11872 * If argument +int_enc+ is given, it must be an Encoding object
11873 * or encoding name string that specifies the internal encoding to be used;
11874 * if argument +ext_enc+ is also given, it must be an Encoding object
11875 * or encoding name string that specifies the external encoding to be used.
11876 *
11877 * The string read from +read_io+ is tagged with the external encoding;
11878 * if an internal encoding is also specified, the string is converted
11879 * to, and tagged with, that encoding.
11880 *
11881 * If any encoding is specified,
11882 * optional hash arguments specify the conversion option.
11883 *
11884 * Optional keyword arguments +opts+ specify:
11885 *
11886 * - {Open Options}[rdoc-ref:IO@Open+Options].
11887 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11888 *
11889 * With no block given, returns the two endpoints in an array:
11890 *
11891 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11892 *
11893 * With a block given, calls the block with the two endpoints;
11894 * closes both endpoints and returns the value of the block:
11895 *
11896 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11897 *
11898 * Output:
11899 *
11900 * #<IO:fd 6>
11901 * #<IO:fd 7>
11902 *
11903 * Not available on all platforms.
11904 *
11905 * In the example below, the two processes close the ends of the pipe
11906 * that they are not using. This is not just a cosmetic nicety. The
11907 * read end of a pipe will not generate an end of file condition if
11908 * there are any writers with the pipe still open. In the case of the
11909 * parent process, the <tt>rd.read</tt> will never return if it
11910 * does not first issue a <tt>wr.close</tt>:
11911 *
11912 * rd, wr = IO.pipe
11913 *
11914 * if fork
11915 * wr.close
11916 * puts "Parent got: <#{rd.read}>"
11917 * rd.close
11918 * Process.wait
11919 * else
11920 * rd.close
11921 * puts 'Sending message to parent'
11922 * wr.write "Hi Dad"
11923 * wr.close
11924 * end
11925 *
11926 * <em>produces:</em>
11927 *
11928 * Sending message to parent
11929 * Parent got: <Hi Dad>
11930 *
11931 */
11932
11933static VALUE
11934rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11935{
11936 int pipes[2], state;
11937 VALUE r, w, args[3], v1, v2;
11938 VALUE opt;
11939 rb_io_t *fptr, *fptr2;
11940 struct io_encoding_set_args ies_args;
11941 enum rb_io_mode fmode = 0;
11942 VALUE ret;
11943
11944 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11945 if (rb_pipe(pipes) < 0)
11946 rb_sys_fail(0);
11947
11948 args[0] = klass;
11949 args[1] = INT2NUM(pipes[0]);
11950 args[2] = INT2FIX(O_RDONLY);
11951 r = rb_protect(io_new_instance, (VALUE)args, &state);
11952 if (state) {
11953 close(pipes[0]);
11954 close(pipes[1]);
11955 rb_jump_tag(state);
11956 }
11957 GetOpenFile(r, fptr);
11958
11959 ies_args.fptr = fptr;
11960 ies_args.v1 = v1;
11961 ies_args.v2 = v2;
11962 ies_args.opt = opt;
11963 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11964 if (state) {
11965 close(pipes[1]);
11966 io_close(r);
11967 rb_jump_tag(state);
11968 }
11969
11970 args[1] = INT2NUM(pipes[1]);
11971 args[2] = INT2FIX(O_WRONLY);
11972 w = rb_protect(io_new_instance, (VALUE)args, &state);
11973 if (state) {
11974 close(pipes[1]);
11975 if (!NIL_P(r)) rb_io_close(r);
11976 rb_jump_tag(state);
11977 }
11978 GetOpenFile(w, fptr2);
11979 rb_io_synchronized(fptr2);
11980
11981 extract_binmode(opt, &fmode);
11982
11983 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11986 }
11987
11988#if DEFAULT_TEXTMODE
11989 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11990 fptr->mode &= ~FMODE_TEXTMODE;
11991 setmode(fptr->fd, O_BINARY);
11992 }
11993#if RUBY_CRLF_ENVIRONMENT
11996 }
11997#endif
11998#endif
11999 fptr->mode |= fmode;
12000#if DEFAULT_TEXTMODE
12001 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12002 fptr2->mode &= ~FMODE_TEXTMODE;
12003 setmode(fptr2->fd, O_BINARY);
12004 }
12005#endif
12006 fptr2->mode |= fmode;
12007
12008 ret = rb_assoc_new(r, w);
12009 if (rb_block_given_p()) {
12010 VALUE rw[2];
12011 rw[0] = r;
12012 rw[1] = w;
12013 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12014 }
12015 return ret;
12016}
12017
12019 int argc;
12020 VALUE *argv;
12021 VALUE io;
12022};
12023
12024static void
12025open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12026{
12027 VALUE path, v;
12028 VALUE vmode = Qnil, vperm = Qnil;
12029
12030 path = *argv++;
12031 argc--;
12032 FilePathValue(path);
12033 arg->io = 0;
12034 arg->argc = argc;
12035 arg->argv = argv;
12036 if (NIL_P(opt)) {
12037 vmode = INT2NUM(O_RDONLY);
12038 vperm = INT2FIX(0666);
12039 }
12040 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12041 int n;
12042
12043 v = rb_to_array_type(v);
12044 n = RARRAY_LENINT(v);
12045 rb_check_arity(n, 0, 3); /* rb_io_open */
12046 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12047 }
12048 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12049}
12050
12051static VALUE
12052io_s_foreach(VALUE v)
12053{
12054 struct getline_arg *arg = (void *)v;
12055 VALUE str;
12056
12057 if (arg->limit == 0)
12058 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12059 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12060 rb_lastline_set(str);
12061 rb_yield(str);
12062 }
12064 return Qnil;
12065}
12066
12067/*
12068 * call-seq:
12069 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12070 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12071 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12072 * IO.foreach(...) -> an_enumerator
12073 *
12074 * Calls the block with each successive line read from the stream.
12075 *
12076 * When called from class \IO (but not subclasses of \IO),
12077 * this method has potential security vulnerabilities if called with untrusted input;
12078 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12079 *
12080 * The first argument must be a string that is the path to a file.
12081 *
12082 * With only argument +path+ given, parses lines from the file at the given +path+,
12083 * as determined by the default line separator,
12084 * and calls the block with each successive line:
12085 *
12086 * File.foreach('t.txt') {|line| p line }
12087 *
12088 * Output: the same as above.
12089 *
12090 * For both forms, command and path, the remaining arguments are the same.
12091 *
12092 * With argument +sep+ given, parses lines as determined by that line separator
12093 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12094 *
12095 * File.foreach('t.txt', 'li') {|line| p line }
12096 *
12097 * Output:
12098 *
12099 * "First li"
12100 * "ne\nSecond li"
12101 * "ne\n\nThird li"
12102 * "ne\nFourth li"
12103 * "ne\n"
12104 *
12105 * Each paragraph:
12106 *
12107 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12108 *
12109 * Output:
12110 *
12111 * "First line\nSecond line\n\n"
12112 * "Third line\nFourth line\n"
12113 *
12114 * With argument +limit+ given, parses lines as determined by the default
12115 * line separator and the given line-length limit
12116 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12117 *
12118 * File.foreach('t.txt', 7) {|line| p line }
12119 *
12120 * Output:
12121 *
12122 * "First l"
12123 * "ine\n"
12124 * "Second "
12125 * "line\n"
12126 * "\n"
12127 * "Third l"
12128 * "ine\n"
12129 * "Fourth l"
12130 * "line\n"
12131 *
12132 * With arguments +sep+ and +limit+ given,
12133 * combines the two behaviors
12134 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12135 *
12136 * Optional keyword arguments +opts+ specify:
12137 *
12138 * - {Open Options}[rdoc-ref:IO@Open+Options].
12139 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12140 * - {Line Options}[rdoc-ref:IO@Line+IO].
12141 *
12142 * Returns an Enumerator if no block is given.
12143 *
12144 */
12145
12146static VALUE
12147rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12148{
12149 VALUE opt;
12150 int orig_argc = argc;
12151 struct foreach_arg arg;
12152 struct getline_arg garg;
12153
12154 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12155 RETURN_ENUMERATOR(self, orig_argc, argv);
12156 extract_getline_args(argc-1, argv+1, &garg);
12157 open_key_args(self, argc, argv, opt, &arg);
12158 if (NIL_P(arg.io)) return Qnil;
12159 extract_getline_opts(opt, &garg);
12160 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12161 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12162}
12163
12164static VALUE
12165io_s_readlines(VALUE v)
12166{
12167 struct getline_arg *arg = (void *)v;
12168 return io_readlines(arg, arg->io);
12169}
12170
12171/*
12172 * call-seq:
12173 * IO.readlines(path, sep = $/, **opts) -> array
12174 * IO.readlines(path, limit, **opts) -> array
12175 * IO.readlines(path, sep, limit, **opts) -> array
12176 *
12177 * Returns an array of all lines read from the stream.
12178 *
12179 * When called from class \IO (but not subclasses of \IO),
12180 * this method has potential security vulnerabilities if called with untrusted input;
12181 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12182 *
12183 * The first argument must be a string that is the path to a file.
12184 *
12185 * With only argument +path+ given, parses lines from the file at the given +path+,
12186 * as determined by the default line separator,
12187 * and returns those lines in an array:
12188 *
12189 * IO.readlines('t.txt')
12190 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12191 *
12192 * With argument +sep+ given, parses lines as determined by that line separator
12193 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12194 *
12195 * # Ordinary separator.
12196 * IO.readlines('t.txt', 'li')
12197 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12198 * # Get-paragraphs separator.
12199 * IO.readlines('t.txt', '')
12200 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12201 * # Get-all separator.
12202 * IO.readlines('t.txt', nil)
12203 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12204 *
12205 * With argument +limit+ given, parses lines as determined by the default
12206 * line separator and the given line-length limit
12207 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12208 *
12209 * IO.readlines('t.txt', 7)
12210 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12211 *
12212 * With arguments +sep+ and +limit+ given,
12213 * combines the two behaviors
12214 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12215 *
12216 * Optional keyword arguments +opts+ specify:
12217 *
12218 * - {Open Options}[rdoc-ref:IO@Open+Options].
12219 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12220 * - {Line Options}[rdoc-ref:IO@Line+IO].
12221 *
12222 */
12223
12224static VALUE
12225rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12226{
12227 VALUE opt;
12228 struct foreach_arg arg;
12229 struct getline_arg garg;
12230
12231 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12232 extract_getline_args(argc-1, argv+1, &garg);
12233 open_key_args(io, argc, argv, opt, &arg);
12234 if (NIL_P(arg.io)) return Qnil;
12235 extract_getline_opts(opt, &garg);
12236 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12237 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12238}
12239
12240static VALUE
12241io_s_read(VALUE v)
12242{
12243 struct foreach_arg *arg = (void *)v;
12244 return io_read(arg->argc, arg->argv, arg->io);
12245}
12246
12247struct seek_arg {
12248 VALUE io;
12249 VALUE offset;
12250 int mode;
12251};
12252
12253static VALUE
12254seek_before_access(VALUE argp)
12255{
12256 struct seek_arg *arg = (struct seek_arg *)argp;
12257 rb_io_binmode(arg->io);
12258 return rb_io_seek(arg->io, arg->offset, arg->mode);
12259}
12260
12261/*
12262 * call-seq:
12263 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12264 *
12265 * Opens the stream, reads and returns some or all of its content,
12266 * and closes the stream; returns +nil+ if no bytes were read.
12267 *
12268 * When called from class \IO (but not subclasses of \IO),
12269 * this method has potential security vulnerabilities if called with untrusted input;
12270 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12271 *
12272 * The first argument must be a string that is the path to a file.
12273 *
12274 * With only argument +path+ given, reads in text mode and returns the entire content
12275 * of the file at the given path:
12276 *
12277 * IO.read('t.txt')
12278 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12279 *
12280 * On Windows, text mode can terminate reading and leave bytes in the file
12281 * unread when encountering certain special bytes. Consider using
12282 * IO.binread if all bytes in the file should be read.
12283 *
12284 * With argument +length+, returns +length+ bytes if available:
12285 *
12286 * IO.read('t.txt', 7) # => "First l"
12287 * IO.read('t.txt', 700)
12288 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12289 *
12290 * With arguments +length+ and +offset+, returns +length+ bytes
12291 * if available, beginning at the given +offset+:
12292 *
12293 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12294 * IO.read('t.txt', 10, 200) # => nil
12295 *
12296 * Optional keyword arguments +opts+ specify:
12297 *
12298 * - {Open Options}[rdoc-ref:IO@Open+Options].
12299 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12300 *
12301 */
12302
12303static VALUE
12304rb_io_s_read(int argc, VALUE *argv, VALUE io)
12305{
12306 VALUE opt, offset;
12307 long off;
12308 struct foreach_arg arg;
12309
12310 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12311 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12312 rb_raise(rb_eArgError, "negative offset %ld given", off);
12313 }
12314 open_key_args(io, argc, argv, opt, &arg);
12315 if (NIL_P(arg.io)) return Qnil;
12316 if (!NIL_P(offset)) {
12317 struct seek_arg sarg;
12318 int state = 0;
12319 sarg.io = arg.io;
12320 sarg.offset = offset;
12321 sarg.mode = SEEK_SET;
12322 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12323 if (state) {
12324 rb_io_close(arg.io);
12325 rb_jump_tag(state);
12326 }
12327 if (arg.argc == 2) arg.argc = 1;
12328 }
12329 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12330}
12331
12332/*
12333 * call-seq:
12334 * IO.binread(path, length = nil, offset = 0) -> string or nil
12335 *
12336 * Behaves like IO.read, except that the stream is opened in binary mode
12337 * with ASCII-8BIT encoding.
12338 *
12339 * When called from class \IO (but not subclasses of \IO),
12340 * this method has potential security vulnerabilities if called with untrusted input;
12341 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12342 *
12343 */
12344
12345static VALUE
12346rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12347{
12348 VALUE offset;
12349 struct foreach_arg arg;
12350 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12351 enum {
12352 oflags = O_RDONLY
12353#ifdef O_BINARY
12354 |O_BINARY
12355#endif
12356 };
12357 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12358
12359 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12360 FilePathValue(argv[0]);
12361 convconfig.enc = rb_ascii8bit_encoding();
12362 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12363 if (NIL_P(arg.io)) return Qnil;
12364 arg.argv = argv+1;
12365 arg.argc = (argc > 1) ? 1 : 0;
12366 if (!NIL_P(offset)) {
12367 struct seek_arg sarg;
12368 int state = 0;
12369 sarg.io = arg.io;
12370 sarg.offset = offset;
12371 sarg.mode = SEEK_SET;
12372 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12373 if (state) {
12374 rb_io_close(arg.io);
12375 rb_jump_tag(state);
12376 }
12377 }
12378 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12379}
12380
12381static VALUE
12382io_s_write0(VALUE v)
12383{
12384 struct write_arg *arg = (void *)v;
12385 return io_write(arg->io,arg->str,arg->nosync);
12386}
12387
12388static VALUE
12389io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12390{
12391 VALUE string, offset, opt;
12392 struct foreach_arg arg;
12393 struct write_arg warg;
12394
12395 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12396
12397 if (NIL_P(opt)) opt = rb_hash_new();
12398 else opt = rb_hash_dup(opt);
12399
12400
12401 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12402 int mode = O_WRONLY|O_CREAT;
12403#ifdef O_BINARY
12404 if (binary) mode |= O_BINARY;
12405#endif
12406 if (NIL_P(offset)) mode |= O_TRUNC;
12407 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12408 }
12409 open_key_args(klass, argc, argv, opt, &arg);
12410
12411#ifndef O_BINARY
12412 if (binary) rb_io_binmode_m(arg.io);
12413#endif
12414
12415 if (NIL_P(arg.io)) return Qnil;
12416 if (!NIL_P(offset)) {
12417 struct seek_arg sarg;
12418 int state = 0;
12419 sarg.io = arg.io;
12420 sarg.offset = offset;
12421 sarg.mode = SEEK_SET;
12422 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12423 if (state) {
12424 rb_io_close(arg.io);
12425 rb_jump_tag(state);
12426 }
12427 }
12428
12429 warg.io = arg.io;
12430 warg.str = string;
12431 warg.nosync = 0;
12432
12433 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12434}
12435
12436/*
12437 * call-seq:
12438 * IO.write(path, data, offset = 0, **opts) -> integer
12439 *
12440 * Opens the stream, writes the given +data+ to it,
12441 * and closes the stream; returns the number of bytes written.
12442 *
12443 * When called from class \IO (but not subclasses of \IO),
12444 * this method has potential security vulnerabilities if called with untrusted input;
12445 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12446 *
12447 * The first argument must be a string that is the path to a file.
12448 *
12449 * With only argument +path+ given, writes the given +data+ to the file at that path:
12450 *
12451 * IO.write('t.tmp', 'abc') # => 3
12452 * File.read('t.tmp') # => "abc"
12453 *
12454 * If +offset+ is zero (the default), the file is overwritten:
12455 *
12456 * IO.write('t.tmp', 'A') # => 1
12457 * File.read('t.tmp') # => "A"
12458 *
12459 * If +offset+ in within the file content, the file is partly overwritten:
12460 *
12461 * IO.write('t.tmp', 'abcdef') # => 3
12462 * File.read('t.tmp') # => "abcdef"
12463 * # Offset within content.
12464 * IO.write('t.tmp', '012', 2) # => 3
12465 * File.read('t.tmp') # => "ab012f"
12466 *
12467 * If +offset+ is outside the file content,
12468 * the file is padded with null characters <tt>"\u0000"</tt>:
12469 *
12470 * IO.write('t.tmp', 'xyz', 10) # => 3
12471 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12472 *
12473 * Optional keyword arguments +opts+ specify:
12474 *
12475 * - {Open Options}[rdoc-ref:IO@Open+Options].
12476 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12477 *
12478 */
12479
12480static VALUE
12481rb_io_s_write(int argc, VALUE *argv, VALUE io)
12482{
12483 return io_s_write(argc, argv, io, 0);
12484}
12485
12486/*
12487 * call-seq:
12488 * IO.binwrite(path, string, offset = 0) -> integer
12489 *
12490 * Behaves like IO.write, except that the stream is opened in binary mode
12491 * with ASCII-8BIT encoding.
12492 *
12493 * When called from class \IO (but not subclasses of \IO),
12494 * this method has potential security vulnerabilities if called with untrusted input;
12495 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12496 *
12497 */
12498
12499static VALUE
12500rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12501{
12502 return io_s_write(argc, argv, io, 1);
12503}
12504
12506 VALUE src;
12507 VALUE dst;
12508 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12509 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12510
12511 rb_io_t *src_fptr;
12512 rb_io_t *dst_fptr;
12513 unsigned close_src : 1;
12514 unsigned close_dst : 1;
12515 int error_no;
12516 rb_off_t total;
12517 const char *syserr;
12518 const char *notimp;
12519 VALUE th;
12520 struct stat src_stat;
12521 struct stat dst_stat;
12522#ifdef HAVE_FCOPYFILE
12523 copyfile_state_t copyfile_state;
12524#endif
12525};
12526
12527static void *
12528exec_interrupts(void *arg)
12529{
12530 VALUE th = (VALUE)arg;
12531 rb_thread_execute_interrupts(th);
12532 return NULL;
12533}
12534
12535/*
12536 * returns TRUE if the preceding system call was interrupted
12537 * so we can continue. If the thread was interrupted, we
12538 * reacquire the GVL to execute interrupts before continuing.
12539 */
12540static int
12541maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12542{
12543 switch (errno) {
12544 case EINTR:
12545#if defined(ERESTART)
12546 case ERESTART:
12547#endif
12548 if (rb_thread_interrupted(stp->th)) {
12549 if (has_gvl)
12550 rb_thread_execute_interrupts(stp->th);
12551 else
12552 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12553 }
12554 return TRUE;
12555 }
12556 return FALSE;
12557}
12558
12560 VALUE scheduler;
12561
12562 rb_io_t *fptr;
12563 short events;
12564
12565 VALUE result;
12566};
12567
12568static void *
12569fiber_scheduler_wait_for(void * _arguments)
12570{
12571 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12572
12573 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12574
12575 return NULL;
12576}
12577
12578#if USE_POLL
12579# define IOWAIT_SYSCALL "poll"
12580STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12581STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12582static int
12583nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12584{
12586 if (scheduler != Qnil) {
12587 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12588 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12589 return RTEST(args.result);
12590 }
12591
12592 int fd = fptr->fd;
12593 if (fd == -1) return 0;
12594
12595 struct pollfd fds;
12596
12597 fds.fd = fd;
12598 fds.events = events;
12599
12600 int timeout_milliseconds = -1;
12601
12602 if (timeout) {
12603 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12604 }
12605
12606 return poll(&fds, 1, timeout_milliseconds);
12607}
12608#else /* !USE_POLL */
12609# define IOWAIT_SYSCALL "select"
12610static int
12611nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12612{
12614 if (scheduler != Qnil) {
12615 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12616 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12617 return RTEST(args.result);
12618 }
12619
12620 int fd = fptr->fd;
12621
12622 if (fd == -1) {
12623 errno = EBADF;
12624 return -1;
12625 }
12626
12627 rb_fdset_t fds;
12628 int ret;
12629
12630 rb_fd_init(&fds);
12631 rb_fd_set(fd, &fds);
12632
12633 switch (events) {
12634 case RB_WAITFD_IN:
12635 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12636 break;
12637 case RB_WAITFD_OUT:
12638 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12639 break;
12640 default:
12641 VM_UNREACHABLE(nogvl_wait_for);
12642 }
12643
12644 rb_fd_term(&fds);
12645
12646 // On timeout, this returns 0.
12647 return ret;
12648}
12649#endif /* !USE_POLL */
12650
12651static int
12652maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12653{
12654 int ret;
12655
12656 do {
12657 if (has_gvl) {
12659 }
12660 else {
12661 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12662 }
12663 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12664
12665 if (ret < 0) {
12666 stp->syserr = IOWAIT_SYSCALL;
12667 stp->error_no = errno;
12668 return ret;
12669 }
12670 return 0;
12671}
12672
12673static int
12674nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12675{
12676 int ret;
12677
12678 do {
12679 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12680 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12681
12682 if (ret < 0) {
12683 stp->syserr = IOWAIT_SYSCALL;
12684 stp->error_no = errno;
12685 return ret;
12686 }
12687 return 0;
12688}
12689
12690#ifdef USE_COPY_FILE_RANGE
12691
12692static ssize_t
12693simple_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)
12694{
12695#ifdef HAVE_COPY_FILE_RANGE
12696 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12697#else
12698 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12699#endif
12700}
12701
12702static int
12703nogvl_copy_file_range(struct copy_stream_struct *stp)
12704{
12705 ssize_t ss;
12706 rb_off_t src_size;
12707 rb_off_t copy_length, src_offset, *src_offset_ptr;
12708
12709 if (!S_ISREG(stp->src_stat.st_mode))
12710 return 0;
12711
12712 src_size = stp->src_stat.st_size;
12713 src_offset = stp->src_offset;
12714 if (src_offset >= (rb_off_t)0) {
12715 src_offset_ptr = &src_offset;
12716 }
12717 else {
12718 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12719 }
12720
12721 copy_length = stp->copy_length;
12722 if (copy_length < (rb_off_t)0) {
12723 if (src_offset < (rb_off_t)0) {
12724 rb_off_t current_offset;
12725 errno = 0;
12726 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12727 if (current_offset < (rb_off_t)0 && errno) {
12728 stp->syserr = "lseek";
12729 stp->error_no = errno;
12730 return (int)current_offset;
12731 }
12732 copy_length = src_size - current_offset;
12733 }
12734 else {
12735 copy_length = src_size - src_offset;
12736 }
12737 }
12738
12739 retry_copy_file_range:
12740# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12741 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12742 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12743# else
12744 ss = (ssize_t)copy_length;
12745# endif
12746 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12747 if (0 < ss) {
12748 stp->total += ss;
12749 copy_length -= ss;
12750 if (0 < copy_length) {
12751 goto retry_copy_file_range;
12752 }
12753 }
12754 if (ss < 0) {
12755 if (maygvl_copy_stream_continue_p(0, stp)) {
12756 goto retry_copy_file_range;
12757 }
12758 switch (errno) {
12759 case EINVAL:
12760 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12761 docker container) */
12762#ifdef ENOSYS
12763 case ENOSYS:
12764#endif
12765#ifdef EXDEV
12766 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12767#endif
12768 return 0;
12769 case EAGAIN:
12770#if EWOULDBLOCK != EAGAIN
12771 case EWOULDBLOCK:
12772#endif
12773 {
12774 int ret = nogvl_copy_stream_wait_write(stp);
12775 if (ret < 0) return ret;
12776 }
12777 goto retry_copy_file_range;
12778 case EBADF:
12779 {
12780 int e = errno;
12781 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12782
12783 if (flags != -1 && flags & O_APPEND) {
12784 return 0;
12785 }
12786 errno = e;
12787 }
12788 }
12789 stp->syserr = "copy_file_range";
12790 stp->error_no = errno;
12791 return (int)ss;
12792 }
12793 return 1;
12794}
12795#endif
12796
12797#ifdef HAVE_FCOPYFILE
12798static int
12799nogvl_fcopyfile(struct copy_stream_struct *stp)
12800{
12801 rb_off_t cur, ss = 0;
12802 const rb_off_t src_offset = stp->src_offset;
12803 int ret;
12804
12805 if (stp->copy_length >= (rb_off_t)0) {
12806 /* copy_length can't be specified in fcopyfile(3) */
12807 return 0;
12808 }
12809
12810 if (!S_ISREG(stp->src_stat.st_mode))
12811 return 0;
12812
12813 if (!S_ISREG(stp->dst_stat.st_mode))
12814 return 0;
12815 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12816 return 0;
12817 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12818 /* fcopyfile(3) appends src IO to dst IO and then truncates
12819 * dst IO to src IO's original size. */
12820 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12821 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12822 if (end > (rb_off_t)0) return 0;
12823 }
12824
12825 if (src_offset > (rb_off_t)0) {
12826 rb_off_t r;
12827
12828 /* get current offset */
12829 errno = 0;
12830 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12831 if (cur < (rb_off_t)0 && errno) {
12832 stp->error_no = errno;
12833 return 1;
12834 }
12835
12836 errno = 0;
12837 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12838 if (r < (rb_off_t)0 && errno) {
12839 stp->error_no = errno;
12840 return 1;
12841 }
12842 }
12843
12844 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12845 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12846 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12847
12848 if (ret == 0) { /* success */
12849 stp->total = ss;
12850 if (src_offset > (rb_off_t)0) {
12851 rb_off_t r;
12852 errno = 0;
12853 /* reset offset */
12854 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12855 if (r < (rb_off_t)0 && errno) {
12856 stp->error_no = errno;
12857 return 1;
12858 }
12859 }
12860 }
12861 else {
12862 switch (errno) {
12863 case ENOTSUP:
12864 case EPERM:
12865 case EINVAL:
12866 return 0;
12867 }
12868 stp->syserr = "fcopyfile";
12869 stp->error_no = errno;
12870 return (int)ret;
12871 }
12872 return 1;
12873}
12874#endif
12875
12876#ifdef HAVE_SENDFILE
12877
12878# ifdef __linux__
12879# define USE_SENDFILE
12880
12881# ifdef HAVE_SYS_SENDFILE_H
12882# include <sys/sendfile.h>
12883# endif
12884
12885static ssize_t
12886simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12887{
12888 return sendfile(out_fd, in_fd, offset, (size_t)count);
12889}
12890
12891# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12892/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12893 * without cpuset -l 0.
12894 */
12895# define USE_SENDFILE
12896
12897static ssize_t
12898simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12899{
12900 int r;
12901 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12902 rb_off_t sbytes;
12903# ifdef __APPLE__
12904 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12905 sbytes = count;
12906# else
12907 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12908# endif
12909 if (r != 0 && sbytes == 0) return r;
12910 if (offset) {
12911 *offset += sbytes;
12912 }
12913 else {
12914 lseek(in_fd, sbytes, SEEK_CUR);
12915 }
12916 return (ssize_t)sbytes;
12917}
12918
12919# endif
12920
12921#endif
12922
12923#ifdef USE_SENDFILE
12924static int
12925nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12926{
12927 ssize_t ss;
12928 rb_off_t src_size;
12929 rb_off_t copy_length;
12930 rb_off_t src_offset;
12931 int use_pread;
12932
12933 if (!S_ISREG(stp->src_stat.st_mode))
12934 return 0;
12935
12936 src_size = stp->src_stat.st_size;
12937#ifndef __linux__
12938 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12939 return 0;
12940#endif
12941
12942 src_offset = stp->src_offset;
12943 use_pread = src_offset >= (rb_off_t)0;
12944
12945 copy_length = stp->copy_length;
12946 if (copy_length < (rb_off_t)0) {
12947 if (use_pread)
12948 copy_length = src_size - src_offset;
12949 else {
12950 rb_off_t cur;
12951 errno = 0;
12952 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12953 if (cur < (rb_off_t)0 && errno) {
12954 stp->syserr = "lseek";
12955 stp->error_no = errno;
12956 return (int)cur;
12957 }
12958 copy_length = src_size - cur;
12959 }
12960 }
12961
12962 retry_sendfile:
12963# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12964 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12965 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12966# else
12967 ss = (ssize_t)copy_length;
12968# endif
12969 if (use_pread) {
12970 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12971 }
12972 else {
12973 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12974 }
12975 if (0 < ss) {
12976 stp->total += ss;
12977 copy_length -= ss;
12978 if (0 < copy_length) {
12979 goto retry_sendfile;
12980 }
12981 }
12982 if (ss < 0) {
12983 if (maygvl_copy_stream_continue_p(0, stp))
12984 goto retry_sendfile;
12985 switch (errno) {
12986 case EINVAL:
12987#ifdef ENOSYS
12988 case ENOSYS:
12989#endif
12990#ifdef EOPNOTSUP
12991 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12992 see also: [Feature #16965] */
12993 case EOPNOTSUP:
12994#endif
12995 return 0;
12996 case EAGAIN:
12997#if EWOULDBLOCK != EAGAIN
12998 case EWOULDBLOCK:
12999#endif
13000 {
13001 int ret;
13002#ifndef __linux__
13003 /*
13004 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
13005 * select() reports regular files to always be "ready", so
13006 * there is no need to select() on it.
13007 * Other OSes may have the same limitation for sendfile() which
13008 * allow us to bypass maygvl_copy_stream_wait_read()...
13009 */
13010 ret = maygvl_copy_stream_wait_read(0, stp);
13011 if (ret < 0) return ret;
13012#endif
13013 ret = nogvl_copy_stream_wait_write(stp);
13014 if (ret < 0) return ret;
13015 }
13016 goto retry_sendfile;
13017 }
13018 stp->syserr = "sendfile";
13019 stp->error_no = errno;
13020 return (int)ss;
13021 }
13022 return 1;
13023}
13024#endif
13025
13026static ssize_t
13027maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13028{
13029 if (has_gvl)
13030 return rb_io_read_memory(fptr, buf, count);
13031 else
13032 return read(fptr->fd, buf, count);
13033}
13034
13035static ssize_t
13036maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13037{
13038 ssize_t ss;
13039 retry_read:
13040 if (offset < (rb_off_t)0) {
13041 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13042 }
13043 else {
13044 ss = pread(stp->src_fptr->fd, buf, len, offset);
13045 }
13046 if (ss == 0) {
13047 return 0;
13048 }
13049 if (ss < 0) {
13050 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13051 goto retry_read;
13052 switch (errno) {
13053 case EAGAIN:
13054#if EWOULDBLOCK != EAGAIN
13055 case EWOULDBLOCK:
13056#endif
13057 {
13058 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13059 if (ret < 0) return ret;
13060 }
13061 goto retry_read;
13062#ifdef ENOSYS
13063 case ENOSYS:
13064 stp->notimp = "pread";
13065 return ss;
13066#endif
13067 }
13068 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13069 stp->error_no = errno;
13070 }
13071 return ss;
13072}
13073
13074static int
13075nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13076{
13077 ssize_t ss;
13078 int off = 0;
13079 while (len) {
13080 ss = write(stp->dst_fptr->fd, buf+off, len);
13081 if (ss < 0) {
13082 if (maygvl_copy_stream_continue_p(0, stp))
13083 continue;
13084 if (io_again_p(errno)) {
13085 int ret = nogvl_copy_stream_wait_write(stp);
13086 if (ret < 0) return ret;
13087 continue;
13088 }
13089 stp->syserr = "write";
13090 stp->error_no = errno;
13091 return (int)ss;
13092 }
13093 off += (int)ss;
13094 len -= (int)ss;
13095 stp->total += ss;
13096 }
13097 return 0;
13098}
13099
13100static void
13101nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13102{
13103 char buf[1024*16];
13104 size_t len;
13105 ssize_t ss;
13106 int ret;
13107 rb_off_t copy_length;
13108 rb_off_t src_offset;
13109 int use_eof;
13110 int use_pread;
13111
13112 copy_length = stp->copy_length;
13113 use_eof = copy_length < (rb_off_t)0;
13114 src_offset = stp->src_offset;
13115 use_pread = src_offset >= (rb_off_t)0;
13116
13117 if (use_pread && stp->close_src) {
13118 rb_off_t r;
13119 errno = 0;
13120 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13121 if (r < (rb_off_t)0 && errno) {
13122 stp->syserr = "lseek";
13123 stp->error_no = errno;
13124 return;
13125 }
13126 src_offset = (rb_off_t)-1;
13127 use_pread = 0;
13128 }
13129
13130 while (use_eof || 0 < copy_length) {
13131 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13132 len = (size_t)copy_length;
13133 }
13134 else {
13135 len = sizeof(buf);
13136 }
13137 if (use_pread) {
13138 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13139 if (0 < ss)
13140 src_offset += ss;
13141 }
13142 else {
13143 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13144 }
13145 if (ss <= 0) /* EOF or error */
13146 return;
13147
13148 ret = nogvl_copy_stream_write(stp, buf, ss);
13149 if (ret < 0)
13150 return;
13151
13152 if (!use_eof)
13153 copy_length -= ss;
13154 }
13155}
13156
13157static void *
13158nogvl_copy_stream_func(void *arg)
13159{
13160 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13161#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13162 int ret;
13163#endif
13164
13165#ifdef USE_COPY_FILE_RANGE
13166 ret = nogvl_copy_file_range(stp);
13167 if (ret != 0)
13168 goto finish; /* error or success */
13169#endif
13170
13171#ifdef HAVE_FCOPYFILE
13172 ret = nogvl_fcopyfile(stp);
13173 if (ret != 0)
13174 goto finish; /* error or success */
13175#endif
13176
13177#ifdef USE_SENDFILE
13178 ret = nogvl_copy_stream_sendfile(stp);
13179 if (ret != 0)
13180 goto finish; /* error or success */
13181#endif
13182
13183 nogvl_copy_stream_read_write(stp);
13184
13185#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13186 finish:
13187#endif
13188 return 0;
13189}
13190
13191static VALUE
13192copy_stream_fallback_body(VALUE arg)
13193{
13194 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13195 const int buflen = 16*1024;
13196 VALUE n;
13197 VALUE buf = rb_str_buf_new(buflen);
13198 rb_off_t rest = stp->copy_length;
13199 rb_off_t off = stp->src_offset;
13200 ID read_method = id_readpartial;
13201
13202 if (!stp->src_fptr) {
13203 if (!rb_respond_to(stp->src, read_method)) {
13204 read_method = id_read;
13205 }
13206 }
13207
13208 while (1) {
13209 long numwrote;
13210 long l;
13211 rb_str_make_independent(buf);
13212 if (stp->copy_length < (rb_off_t)0) {
13213 l = buflen;
13214 }
13215 else {
13216 if (rest == 0) {
13217 rb_str_resize(buf, 0);
13218 break;
13219 }
13220 l = buflen < rest ? buflen : (long)rest;
13221 }
13222 if (!stp->src_fptr) {
13223 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13224
13225 if (read_method == id_read && NIL_P(rc))
13226 break;
13227 }
13228 else {
13229 ssize_t ss;
13230 rb_str_resize(buf, buflen);
13231 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13232 rb_str_resize(buf, ss > 0 ? ss : 0);
13233 if (ss < 0)
13234 return Qnil;
13235 if (ss == 0)
13236 rb_eof_error();
13237 if (off >= (rb_off_t)0)
13238 off += ss;
13239 }
13240 n = rb_io_write(stp->dst, buf);
13241 numwrote = NUM2LONG(n);
13242 stp->total += numwrote;
13243 rest -= numwrote;
13244 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13245 break;
13246 }
13247 }
13248
13249 return Qnil;
13250}
13251
13252static VALUE
13253copy_stream_fallback(struct copy_stream_struct *stp)
13254{
13255 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13256 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13257 }
13258 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13259 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13260 rb_eEOFError, (VALUE)0);
13261 return Qnil;
13262}
13263
13264static VALUE
13265copy_stream_body(VALUE arg)
13266{
13267 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13268 VALUE src_io = stp->src, dst_io = stp->dst;
13269 const int common_oflags = 0
13270#ifdef O_NOCTTY
13271 | O_NOCTTY
13272#endif
13273 ;
13274
13275 stp->th = rb_thread_current();
13276
13277 stp->total = 0;
13278
13279 if (src_io == argf ||
13280 !(RB_TYPE_P(src_io, T_FILE) ||
13281 RB_TYPE_P(src_io, T_STRING) ||
13282 rb_respond_to(src_io, rb_intern("to_path")))) {
13283 stp->src_fptr = NULL;
13284 }
13285 else {
13286 int stat_ret;
13287 VALUE tmp_io = rb_io_check_io(src_io);
13288 if (!NIL_P(tmp_io)) {
13289 src_io = tmp_io;
13290 }
13291 else if (!RB_TYPE_P(src_io, T_FILE)) {
13292 VALUE args[2];
13293 FilePathValue(src_io);
13294 args[0] = src_io;
13295 args[1] = INT2NUM(O_RDONLY|common_oflags);
13296 src_io = rb_class_new_instance(2, args, rb_cFile);
13297 stp->src = src_io;
13298 stp->close_src = 1;
13299 }
13300 RB_IO_POINTER(src_io, stp->src_fptr);
13301 rb_io_check_byte_readable(stp->src_fptr);
13302
13303 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13304 if (stat_ret < 0) {
13305 stp->syserr = "fstat";
13306 stp->error_no = errno;
13307 return Qnil;
13308 }
13309 }
13310
13311 if (dst_io == argf ||
13312 !(RB_TYPE_P(dst_io, T_FILE) ||
13313 RB_TYPE_P(dst_io, T_STRING) ||
13314 rb_respond_to(dst_io, rb_intern("to_path")))) {
13315 stp->dst_fptr = NULL;
13316 }
13317 else {
13318 int stat_ret;
13319 VALUE tmp_io = rb_io_check_io(dst_io);
13320 if (!NIL_P(tmp_io)) {
13321 dst_io = GetWriteIO(tmp_io);
13322 }
13323 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13324 VALUE args[3];
13325 FilePathValue(dst_io);
13326 args[0] = dst_io;
13327 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13328 args[2] = INT2FIX(0666);
13329 dst_io = rb_class_new_instance(3, args, rb_cFile);
13330 stp->dst = dst_io;
13331 stp->close_dst = 1;
13332 }
13333 else {
13334 dst_io = GetWriteIO(dst_io);
13335 stp->dst = dst_io;
13336 }
13337 RB_IO_POINTER(dst_io, stp->dst_fptr);
13338 rb_io_check_writable(stp->dst_fptr);
13339
13340 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13341 if (stat_ret < 0) {
13342 stp->syserr = "fstat";
13343 stp->error_no = errno;
13344 return Qnil;
13345 }
13346 }
13347
13348#ifdef O_BINARY
13349 if (stp->src_fptr)
13350 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13351#endif
13352 if (stp->dst_fptr)
13353 io_ascii8bit_binmode(stp->dst_fptr);
13354
13355 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13356 size_t len = stp->src_fptr->rbuf.len;
13357 VALUE str;
13358 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13359 len = (size_t)stp->copy_length;
13360 }
13361 str = rb_str_buf_new(len);
13362 rb_str_resize(str,len);
13363 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13364 if (stp->dst_fptr) { /* IO or filename */
13365 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13366 rb_sys_fail_on_write(stp->dst_fptr);
13367 }
13368 else /* others such as StringIO */
13369 rb_io_write(dst_io, str);
13370 rb_str_resize(str, 0);
13371 stp->total += len;
13372 if (stp->copy_length >= (rb_off_t)0)
13373 stp->copy_length -= len;
13374 }
13375
13376 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13377 rb_raise(rb_eIOError, "flush failed");
13378 }
13379
13380 if (stp->copy_length == 0)
13381 return Qnil;
13382
13383 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13384 return copy_stream_fallback(stp);
13385 }
13386
13387 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13388 return Qnil;
13389}
13390
13391static VALUE
13392copy_stream_finalize(VALUE arg)
13393{
13394 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13395
13396#ifdef HAVE_FCOPYFILE
13397 if (stp->copyfile_state) {
13398 copyfile_state_free(stp->copyfile_state);
13399 }
13400#endif
13401
13402 if (stp->close_src) {
13403 rb_io_close_m(stp->src);
13404 }
13405 if (stp->close_dst) {
13406 rb_io_close_m(stp->dst);
13407 }
13408 if (stp->syserr) {
13409 rb_syserr_fail(stp->error_no, stp->syserr);
13410 }
13411 if (stp->notimp) {
13412 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13413 }
13414 return Qnil;
13415}
13416
13417/*
13418 * call-seq:
13419 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13420 *
13421 * Copies from the given +src+ to the given +dst+,
13422 * returning the number of bytes copied.
13423 *
13424 * - The given +src+ must be one of the following:
13425 *
13426 * - The path to a readable file, from which source data is to be read.
13427 * - An \IO-like object, opened for reading and capable of responding
13428 * to method +:readpartial+ or method +:read+.
13429 *
13430 * - The given +dst+ must be one of the following:
13431 *
13432 * - The path to a writable file, to which data is to be written.
13433 * - An \IO-like object, opened for writing and capable of responding
13434 * to method +:write+.
13435 *
13436 * The examples here use file <tt>t.txt</tt> as source:
13437 *
13438 * File.read('t.txt')
13439 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13440 * File.read('t.txt').size # => 47
13441 *
13442 * If only arguments +src+ and +dst+ are given,
13443 * the entire source stream is copied:
13444 *
13445 * # Paths.
13446 * IO.copy_stream('t.txt', 't.tmp') # => 47
13447 *
13448 * # IOs (recall that a File is also an IO).
13449 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13450 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13451 * IO.copy_stream(src_io, dst_io) # => 47
13452 * src_io.close
13453 * dst_io.close
13454 *
13455 * With argument +src_length+ a non-negative integer,
13456 * no more than that many bytes are copied:
13457 *
13458 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13459 * File.read('t.tmp') # => "First line"
13460 *
13461 * With argument +src_offset+ also given,
13462 * the source stream is read beginning at that offset:
13463 *
13464 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13465 * IO.read('t.tmp') # => "Second line"
13466 *
13467 */
13468static VALUE
13469rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13470{
13471 VALUE src, dst, length, src_offset;
13472 struct copy_stream_struct st;
13473
13474 MEMZERO(&st, struct copy_stream_struct, 1);
13475
13476 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13477
13478 st.src = src;
13479 st.dst = dst;
13480
13481 st.src_fptr = NULL;
13482 st.dst_fptr = NULL;
13483
13484 if (NIL_P(length))
13485 st.copy_length = (rb_off_t)-1;
13486 else
13487 st.copy_length = NUM2OFFT(length);
13488
13489 if (NIL_P(src_offset))
13490 st.src_offset = (rb_off_t)-1;
13491 else
13492 st.src_offset = NUM2OFFT(src_offset);
13493
13494 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13495
13496 return OFFT2NUM(st.total);
13497}
13498
13499/*
13500 * call-seq:
13501 * external_encoding -> encoding or nil
13502 *
13503 * Returns the Encoding object that represents the encoding of the stream,
13504 * or +nil+ if the stream is in write mode and no encoding is specified.
13505 *
13506 * See {Encodings}[rdoc-ref:File@Encodings].
13507 *
13508 */
13509
13510static VALUE
13511rb_io_external_encoding(VALUE io)
13512{
13513 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13514
13515 if (fptr->encs.enc2) {
13516 return rb_enc_from_encoding(fptr->encs.enc2);
13517 }
13518 if (fptr->mode & FMODE_WRITABLE) {
13519 if (fptr->encs.enc)
13520 return rb_enc_from_encoding(fptr->encs.enc);
13521 return Qnil;
13522 }
13523 return rb_enc_from_encoding(io_read_encoding(fptr));
13524}
13525
13526/*
13527 * call-seq:
13528 * internal_encoding -> encoding or nil
13529 *
13530 * Returns the Encoding object that represents the encoding of the internal string,
13531 * if conversion is specified,
13532 * or +nil+ otherwise.
13533 *
13534 * See {Encodings}[rdoc-ref:File@Encodings].
13535 *
13536 */
13537
13538static VALUE
13539rb_io_internal_encoding(VALUE io)
13540{
13541 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13542
13543 if (!fptr->encs.enc2) return Qnil;
13544 return rb_enc_from_encoding(io_read_encoding(fptr));
13545}
13546
13547/*
13548 * call-seq:
13549 * set_encoding(ext_enc) -> self
13550 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13551 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13552 *
13553 * See {Encodings}[rdoc-ref:File@Encodings].
13554 *
13555 * Argument +ext_enc+, if given, must be an Encoding object
13556 * or a String with the encoding name;
13557 * it is assigned as the encoding for the stream.
13558 *
13559 * Argument +int_enc+, if given, must be an Encoding object
13560 * or a String with the encoding name;
13561 * it is assigned as the encoding for the internal string.
13562 *
13563 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13564 * containing two colon-separated encoding names;
13565 * corresponding Encoding objects are assigned as the external
13566 * and internal encodings for the stream.
13567 *
13568 * If the external encoding of a string is binary/ASCII-8BIT,
13569 * the internal encoding of the string is set to nil, since no
13570 * transcoding is needed.
13571 *
13572 * Optional keyword arguments +enc_opts+ specify
13573 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13574 *
13575 */
13576
13577static VALUE
13578rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13579{
13580 rb_io_t *fptr;
13581 VALUE v1, v2, opt;
13582
13583 if (!RB_TYPE_P(io, T_FILE)) {
13584 return forward(io, id_set_encoding, argc, argv);
13585 }
13586
13587 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13588 GetOpenFile(io, fptr);
13589 io_encoding_set(fptr, v1, v2, opt);
13590 return io;
13591}
13592
13593void
13594rb_stdio_set_default_encoding(void)
13595{
13596 VALUE val = Qnil;
13597
13598#ifdef _WIN32
13599 if (isatty(fileno(stdin))) {
13600 rb_encoding *external = rb_locale_encoding();
13601 rb_encoding *internal = rb_default_internal_encoding();
13602 if (!internal) internal = rb_default_external_encoding();
13603 io_encoding_set(RFILE(rb_stdin)->fptr,
13604 rb_enc_from_encoding(external),
13605 rb_enc_from_encoding(internal),
13606 Qnil);
13607 }
13608 else
13609#endif
13610 rb_io_set_encoding(1, &val, rb_stdin);
13611 rb_io_set_encoding(1, &val, rb_stdout);
13612 rb_io_set_encoding(1, &val, rb_stderr);
13613}
13614
13615static inline int
13616global_argf_p(VALUE arg)
13617{
13618 return arg == argf;
13619}
13620
13621typedef VALUE (*argf_encoding_func)(VALUE io);
13622
13623static VALUE
13624argf_encoding(VALUE argf, argf_encoding_func func)
13625{
13626 if (!RTEST(ARGF.current_file)) {
13627 return rb_enc_default_external();
13628 }
13629 return func(rb_io_check_io(ARGF.current_file));
13630}
13631
13632/*
13633 * call-seq:
13634 * ARGF.external_encoding -> encoding
13635 *
13636 * Returns the external encoding for files read from ARGF as an Encoding
13637 * object. The external encoding is the encoding of the text as stored in a
13638 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13639 * represent this text within Ruby.
13640 *
13641 * To set the external encoding use ARGF.set_encoding.
13642 *
13643 * For example:
13644 *
13645 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13646 *
13647 */
13648static VALUE
13649argf_external_encoding(VALUE argf)
13650{
13651 return argf_encoding(argf, rb_io_external_encoding);
13652}
13653
13654/*
13655 * call-seq:
13656 * ARGF.internal_encoding -> encoding
13657 *
13658 * Returns the internal encoding for strings read from ARGF as an
13659 * Encoding object.
13660 *
13661 * If ARGF.set_encoding has been called with two encoding names, the second
13662 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13663 * value is returned. Failing that, if a default external encoding was
13664 * specified on the command-line, that value is used. If the encoding is
13665 * unknown, +nil+ is returned.
13666 */
13667static VALUE
13668argf_internal_encoding(VALUE argf)
13669{
13670 return argf_encoding(argf, rb_io_internal_encoding);
13671}
13672
13673/*
13674 * call-seq:
13675 * ARGF.set_encoding(ext_enc) -> ARGF
13676 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13677 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13678 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13679 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13680 *
13681 * If single argument is specified, strings read from ARGF are tagged with
13682 * the encoding specified.
13683 *
13684 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13685 * the read string is converted from the first encoding (external encoding)
13686 * to the second encoding (internal encoding), then tagged with the second
13687 * encoding.
13688 *
13689 * If two arguments are specified, they must be encoding objects or encoding
13690 * names. Again, the first specifies the external encoding; the second
13691 * specifies the internal encoding.
13692 *
13693 * If the external encoding and the internal encoding are specified, the
13694 * optional Hash argument can be used to adjust the conversion process. The
13695 * structure of this hash is explained in the String#encode documentation.
13696 *
13697 * For example:
13698 *
13699 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13700 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13701 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13702 * # to UTF-8.
13703 */
13704static VALUE
13705argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13706{
13707 rb_io_t *fptr;
13708
13709 if (!next_argv()) {
13710 rb_raise(rb_eArgError, "no stream to set encoding");
13711 }
13712 rb_io_set_encoding(argc, argv, ARGF.current_file);
13713 GetOpenFile(ARGF.current_file, fptr);
13714 ARGF.encs = fptr->encs;
13715 return argf;
13716}
13717
13718/*
13719 * call-seq:
13720 * ARGF.tell -> Integer
13721 * ARGF.pos -> Integer
13722 *
13723 * Returns the current offset (in bytes) of the current file in ARGF.
13724 *
13725 * ARGF.pos #=> 0
13726 * ARGF.gets #=> "This is line one\n"
13727 * ARGF.pos #=> 17
13728 *
13729 */
13730static VALUE
13731argf_tell(VALUE argf)
13732{
13733 if (!next_argv()) {
13734 rb_raise(rb_eArgError, "no stream to tell");
13735 }
13736 ARGF_FORWARD(0, 0);
13737 return rb_io_tell(ARGF.current_file);
13738}
13739
13740/*
13741 * call-seq:
13742 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13743 *
13744 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13745 * the value of _whence_. See IO#seek for further details.
13746 */
13747static VALUE
13748argf_seek_m(int argc, VALUE *argv, VALUE argf)
13749{
13750 if (!next_argv()) {
13751 rb_raise(rb_eArgError, "no stream to seek");
13752 }
13753 ARGF_FORWARD(argc, argv);
13754 return rb_io_seek_m(argc, argv, ARGF.current_file);
13755}
13756
13757/*
13758 * call-seq:
13759 * ARGF.pos = position -> Integer
13760 *
13761 * Seeks to the position given by _position_ (in bytes) in ARGF.
13762 *
13763 * For example:
13764 *
13765 * ARGF.pos = 17
13766 * ARGF.gets #=> "This is line two\n"
13767 */
13768static VALUE
13769argf_set_pos(VALUE argf, VALUE offset)
13770{
13771 if (!next_argv()) {
13772 rb_raise(rb_eArgError, "no stream to set position");
13773 }
13774 ARGF_FORWARD(1, &offset);
13775 return rb_io_set_pos(ARGF.current_file, offset);
13776}
13777
13778/*
13779 * call-seq:
13780 * ARGF.rewind -> 0
13781 *
13782 * Positions the current file to the beginning of input, resetting
13783 * ARGF.lineno to zero.
13784 *
13785 * ARGF.readline #=> "This is line one\n"
13786 * ARGF.rewind #=> 0
13787 * ARGF.lineno #=> 0
13788 * ARGF.readline #=> "This is line one\n"
13789 */
13790static VALUE
13791argf_rewind(VALUE argf)
13792{
13793 VALUE ret;
13794 int old_lineno;
13795
13796 if (!next_argv()) {
13797 rb_raise(rb_eArgError, "no stream to rewind");
13798 }
13799 ARGF_FORWARD(0, 0);
13800 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13801 ret = rb_io_rewind(ARGF.current_file);
13802 if (!global_argf_p(argf)) {
13803 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13804 }
13805 return ret;
13806}
13807
13808/*
13809 * call-seq:
13810 * ARGF.fileno -> integer
13811 * ARGF.to_i -> integer
13812 *
13813 * Returns an integer representing the numeric file descriptor for
13814 * the current file. Raises an ArgumentError if there isn't a current file.
13815 *
13816 * ARGF.fileno #=> 3
13817 */
13818static VALUE
13819argf_fileno(VALUE argf)
13820{
13821 if (!next_argv()) {
13822 rb_raise(rb_eArgError, "no stream");
13823 }
13824 ARGF_FORWARD(0, 0);
13825 return rb_io_fileno(ARGF.current_file);
13826}
13827
13828/*
13829 * call-seq:
13830 * ARGF.to_io -> IO
13831 *
13832 * Returns an IO object representing the current file. This will be a
13833 * File object unless the current file is a stream such as STDIN.
13834 *
13835 * For example:
13836 *
13837 * ARGF.to_io #=> #<File:glark.txt>
13838 * ARGF.to_io #=> #<IO:<STDIN>>
13839 */
13840static VALUE
13841argf_to_io(VALUE argf)
13842{
13843 next_argv();
13844 ARGF_FORWARD(0, 0);
13845 return ARGF.current_file;
13846}
13847
13848/*
13849 * call-seq:
13850 * ARGF.eof? -> true or false
13851 * ARGF.eof -> true or false
13852 *
13853 * Returns true if the current file in ARGF is at end of file, i.e. it has
13854 * no data to read. The stream must be opened for reading or an IOError
13855 * will be raised.
13856 *
13857 * $ echo "eof" | ruby argf.rb
13858 *
13859 * ARGF.eof? #=> false
13860 * 3.times { ARGF.readchar }
13861 * ARGF.eof? #=> false
13862 * ARGF.readchar #=> "\n"
13863 * ARGF.eof? #=> true
13864 */
13865
13866static VALUE
13867argf_eof(VALUE argf)
13868{
13869 next_argv();
13870 if (RTEST(ARGF.current_file)) {
13871 if (ARGF.init_p == 0) return Qtrue;
13872 next_argv();
13873 ARGF_FORWARD(0, 0);
13874 if (rb_io_eof(ARGF.current_file)) {
13875 return Qtrue;
13876 }
13877 }
13878 return Qfalse;
13879}
13880
13881/*
13882 * call-seq:
13883 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13884 *
13885 * Reads _length_ bytes from ARGF. The files named on the command line
13886 * are concatenated and treated as a single file by this method, so when
13887 * called without arguments the contents of this pseudo file are returned in
13888 * their entirety.
13889 *
13890 * _length_ must be a non-negative integer or +nil+.
13891 *
13892 * If _length_ is a positive integer, +read+ tries to read
13893 * _length_ bytes without any conversion (binary mode).
13894 * It returns +nil+ if an EOF is encountered before anything can be read.
13895 * Fewer than _length_ bytes are returned if an EOF is encountered during
13896 * the read.
13897 * In the case of an integer _length_, the resulting string is always
13898 * in ASCII-8BIT encoding.
13899 *
13900 * If _length_ is omitted or is +nil+, it reads until EOF
13901 * and the encoding conversion is applied, if applicable.
13902 * A string is returned even if EOF is encountered before any data is read.
13903 *
13904 * If _length_ is zero, it returns an empty string (<code>""</code>).
13905 *
13906 * If the optional _outbuf_ argument is present,
13907 * it must reference a String, which will receive the data.
13908 * The _outbuf_ will contain only the received data after the method call
13909 * even if it is not empty at the beginning.
13910 *
13911 * For example:
13912 *
13913 * $ echo "small" > small.txt
13914 * $ echo "large" > large.txt
13915 * $ ./glark.rb small.txt large.txt
13916 *
13917 * ARGF.read #=> "small\nlarge"
13918 * ARGF.read(200) #=> "small\nlarge"
13919 * ARGF.read(2) #=> "sm"
13920 * ARGF.read(0) #=> ""
13921 *
13922 * Note that this method behaves like the fread() function in C.
13923 * This means it retries to invoke read(2) system calls to read data
13924 * with the specified length.
13925 * If you need the behavior like a single read(2) system call,
13926 * consider ARGF#readpartial or ARGF#read_nonblock.
13927 */
13928
13929static VALUE
13930argf_read(int argc, VALUE *argv, VALUE argf)
13931{
13932 VALUE tmp, str, length;
13933 long len = 0;
13934
13935 rb_scan_args(argc, argv, "02", &length, &str);
13936 if (!NIL_P(length)) {
13937 len = NUM2LONG(argv[0]);
13938 }
13939 if (!NIL_P(str)) {
13940 StringValue(str);
13941 rb_str_resize(str,0);
13942 argv[1] = Qnil;
13943 }
13944
13945 retry:
13946 if (!next_argv()) {
13947 return str;
13948 }
13949 if (ARGF_GENERIC_INPUT_P()) {
13950 tmp = argf_forward(argc, argv, argf);
13951 }
13952 else {
13953 tmp = io_read(argc, argv, ARGF.current_file);
13954 }
13955 if (NIL_P(str)) str = tmp;
13956 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13957 if (NIL_P(tmp) || NIL_P(length)) {
13958 if (ARGF.next_p != -1) {
13959 argf_close(argf);
13960 ARGF.next_p = 1;
13961 goto retry;
13962 }
13963 }
13964 else if (argc >= 1) {
13965 long slen = RSTRING_LEN(str);
13966 if (slen < len) {
13967 argv[0] = LONG2NUM(len - slen);
13968 goto retry;
13969 }
13970 }
13971 return str;
13972}
13973
13975 int argc;
13976 VALUE *argv;
13977 VALUE argf;
13978};
13979
13980static VALUE
13981argf_forward_call(VALUE arg)
13982{
13983 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13984 argf_forward(p->argc, p->argv, p->argf);
13985 return Qnil;
13986}
13987
13988static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13989 int nonblock);
13990
13991/*
13992 * call-seq:
13993 * ARGF.readpartial(maxlen) -> string
13994 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13995 *
13996 * Reads at most _maxlen_ bytes from the ARGF stream.
13997 *
13998 * If the optional _outbuf_ argument is present,
13999 * it must reference a String, which will receive the data.
14000 * The _outbuf_ will contain only the received data after the method call
14001 * even if it is not empty at the beginning.
14002 *
14003 * It raises EOFError on end of ARGF stream.
14004 * Since ARGF stream is a concatenation of multiple files,
14005 * internally EOF is occur for each file.
14006 * ARGF.readpartial returns empty strings for EOFs except the last one and
14007 * raises EOFError for the last one.
14008 *
14009 */
14010
14011static VALUE
14012argf_readpartial(int argc, VALUE *argv, VALUE argf)
14013{
14014 return argf_getpartial(argc, argv, argf, Qnil, 0);
14015}
14016
14017/*
14018 * call-seq:
14019 * ARGF.read_nonblock(maxlen[, options]) -> string
14020 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14021 *
14022 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14023 */
14024
14025static VALUE
14026argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14027{
14028 VALUE opts;
14029
14030 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14031
14032 if (!NIL_P(opts))
14033 argc--;
14034
14035 return argf_getpartial(argc, argv, argf, opts, 1);
14036}
14037
14038static VALUE
14039argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14040{
14041 VALUE tmp, str, length;
14042 int no_exception;
14043
14044 rb_scan_args(argc, argv, "11", &length, &str);
14045 if (!NIL_P(str)) {
14046 StringValue(str);
14047 argv[1] = str;
14048 }
14049 no_exception = no_exception_p(opts);
14050
14051 if (!next_argv()) {
14052 if (!NIL_P(str)) {
14053 rb_str_resize(str, 0);
14054 }
14055 rb_eof_error();
14056 }
14057 if (ARGF_GENERIC_INPUT_P()) {
14058 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14059 struct argf_call_arg arg;
14060 arg.argc = argc;
14061 arg.argv = argv;
14062 arg.argf = argf;
14063 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14064 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14065 }
14066 else {
14067 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14068 }
14069 if (NIL_P(tmp)) {
14070 if (ARGF.next_p == -1) {
14071 return io_nonblock_eof(no_exception);
14072 }
14073 argf_close(argf);
14074 ARGF.next_p = 1;
14075 if (RARRAY_LEN(ARGF.argv) == 0) {
14076 return io_nonblock_eof(no_exception);
14077 }
14078 if (NIL_P(str))
14079 str = rb_str_new(NULL, 0);
14080 return str;
14081 }
14082 return tmp;
14083}
14084
14085/*
14086 * call-seq:
14087 * ARGF.getc -> String or nil
14088 *
14089 * Reads the next character from ARGF and returns it as a String. Returns
14090 * +nil+ at the end of the stream.
14091 *
14092 * ARGF treats the files named on the command line as a single file created
14093 * by concatenating their contents. After returning the last character of the
14094 * first file, it returns the first character of the second file, and so on.
14095 *
14096 * For example:
14097 *
14098 * $ echo "foo" > file
14099 * $ ruby argf.rb file
14100 *
14101 * ARGF.getc #=> "f"
14102 * ARGF.getc #=> "o"
14103 * ARGF.getc #=> "o"
14104 * ARGF.getc #=> "\n"
14105 * ARGF.getc #=> nil
14106 * ARGF.getc #=> nil
14107 */
14108static VALUE
14109argf_getc(VALUE argf)
14110{
14111 VALUE ch;
14112
14113 retry:
14114 if (!next_argv()) return Qnil;
14115 if (ARGF_GENERIC_INPUT_P()) {
14116 ch = forward_current(rb_intern("getc"), 0, 0);
14117 }
14118 else {
14119 ch = rb_io_getc(ARGF.current_file);
14120 }
14121 if (NIL_P(ch) && ARGF.next_p != -1) {
14122 argf_close(argf);
14123 ARGF.next_p = 1;
14124 goto retry;
14125 }
14126
14127 return ch;
14128}
14129
14130/*
14131 * call-seq:
14132 * ARGF.getbyte -> Integer or nil
14133 *
14134 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14135 * the end of the stream.
14136 *
14137 * For example:
14138 *
14139 * $ echo "foo" > file
14140 * $ ruby argf.rb file
14141 *
14142 * ARGF.getbyte #=> 102
14143 * ARGF.getbyte #=> 111
14144 * ARGF.getbyte #=> 111
14145 * ARGF.getbyte #=> 10
14146 * ARGF.getbyte #=> nil
14147 */
14148static VALUE
14149argf_getbyte(VALUE argf)
14150{
14151 VALUE ch;
14152
14153 retry:
14154 if (!next_argv()) return Qnil;
14155 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14156 ch = forward_current(rb_intern("getbyte"), 0, 0);
14157 }
14158 else {
14159 ch = rb_io_getbyte(ARGF.current_file);
14160 }
14161 if (NIL_P(ch) && ARGF.next_p != -1) {
14162 argf_close(argf);
14163 ARGF.next_p = 1;
14164 goto retry;
14165 }
14166
14167 return ch;
14168}
14169
14170/*
14171 * call-seq:
14172 * ARGF.readchar -> String or nil
14173 *
14174 * Reads the next character from ARGF and returns it as a String. Raises
14175 * an EOFError after the last character of the last file has been read.
14176 *
14177 * For example:
14178 *
14179 * $ echo "foo" > file
14180 * $ ruby argf.rb file
14181 *
14182 * ARGF.readchar #=> "f"
14183 * ARGF.readchar #=> "o"
14184 * ARGF.readchar #=> "o"
14185 * ARGF.readchar #=> "\n"
14186 * ARGF.readchar #=> end of file reached (EOFError)
14187 */
14188static VALUE
14189argf_readchar(VALUE argf)
14190{
14191 VALUE ch;
14192
14193 retry:
14194 if (!next_argv()) rb_eof_error();
14195 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14196 ch = forward_current(rb_intern("getc"), 0, 0);
14197 }
14198 else {
14199 ch = rb_io_getc(ARGF.current_file);
14200 }
14201 if (NIL_P(ch) && ARGF.next_p != -1) {
14202 argf_close(argf);
14203 ARGF.next_p = 1;
14204 goto retry;
14205 }
14206
14207 return ch;
14208}
14209
14210/*
14211 * call-seq:
14212 * ARGF.readbyte -> Integer
14213 *
14214 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14215 * an EOFError after the last byte of the last file has been read.
14216 *
14217 * For example:
14218 *
14219 * $ echo "foo" > file
14220 * $ ruby argf.rb file
14221 *
14222 * ARGF.readbyte #=> 102
14223 * ARGF.readbyte #=> 111
14224 * ARGF.readbyte #=> 111
14225 * ARGF.readbyte #=> 10
14226 * ARGF.readbyte #=> end of file reached (EOFError)
14227 */
14228static VALUE
14229argf_readbyte(VALUE argf)
14230{
14231 VALUE c;
14232
14233 NEXT_ARGF_FORWARD(0, 0);
14234 c = argf_getbyte(argf);
14235 if (NIL_P(c)) {
14236 rb_eof_error();
14237 }
14238 return c;
14239}
14240
14241#define FOREACH_ARGF() while (next_argv())
14242
14243static VALUE
14244argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14245{
14246 const VALUE current = ARGF.current_file;
14247 rb_yield_values2(argc, argv);
14248 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14250 }
14251 return Qnil;
14252}
14253
14254#define ARGF_block_call(mid, argc, argv, func, argf) \
14255 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14256 func, argf, rb_keyword_given_p())
14257
14258static void
14259argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14260{
14261 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14262 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14263}
14264
14265static VALUE
14266argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14267{
14268 if (!global_argf_p(argf)) {
14269 ARGF.last_lineno = ++ARGF.lineno;
14270 }
14271 return argf_block_call_i(i, argf, argc, argv, blockarg);
14272}
14273
14274static void
14275argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14276{
14277 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14278 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14279}
14280
14281/*
14282 * call-seq:
14283 * ARGF.each(sep=$/) {|line| block } -> ARGF
14284 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14285 * ARGF.each(...) -> an_enumerator
14286 *
14287 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14288 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14289 * ARGF.each_line(...) -> an_enumerator
14290 *
14291 * Returns an enumerator which iterates over each line (separated by _sep_,
14292 * which defaults to your platform's newline character) of each file in
14293 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14294 * block, otherwise an enumerator is returned.
14295 * The optional _limit_ argument is an Integer specifying the maximum
14296 * length of each line; longer lines will be split according to this limit.
14297 *
14298 * This method allows you to treat the files supplied on the command line as
14299 * a single file consisting of the concatenation of each named file. After
14300 * the last line of the first file has been returned, the first line of the
14301 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14302 * used to determine the filename of the current line and line number of the
14303 * whole input, respectively.
14304 *
14305 * For example, the following code prints out each line of each named file
14306 * prefixed with its line number, displaying the filename once per file:
14307 *
14308 * ARGF.each_line do |line|
14309 * puts ARGF.filename if ARGF.file.lineno == 1
14310 * puts "#{ARGF.file.lineno}: #{line}"
14311 * end
14312 *
14313 * While the following code prints only the first file's name at first, and
14314 * the contents with line number counted through all named files.
14315 *
14316 * ARGF.each_line do |line|
14317 * puts ARGF.filename if ARGF.lineno == 1
14318 * puts "#{ARGF.lineno}: #{line}"
14319 * end
14320 */
14321static VALUE
14322argf_each_line(int argc, VALUE *argv, VALUE argf)
14323{
14324 RETURN_ENUMERATOR(argf, argc, argv);
14325 FOREACH_ARGF() {
14326 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14327 }
14328 return argf;
14329}
14330
14331/*
14332 * call-seq:
14333 * ARGF.each_byte {|byte| block } -> ARGF
14334 * ARGF.each_byte -> an_enumerator
14335 *
14336 * Iterates over each byte of each file in +ARGV+.
14337 * A byte is returned as an Integer in the range 0..255.
14338 *
14339 * This method allows you to treat the files supplied on the command line as
14340 * a single file consisting of the concatenation of each named file. After
14341 * the last byte of the first file has been returned, the first byte of the
14342 * second file is returned. The ARGF.filename method can be used to
14343 * determine the filename of the current byte.
14344 *
14345 * If no block is given, an enumerator is returned instead.
14346 *
14347 * For example:
14348 *
14349 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14350 *
14351 */
14352static VALUE
14353argf_each_byte(VALUE argf)
14354{
14355 RETURN_ENUMERATOR(argf, 0, 0);
14356 FOREACH_ARGF() {
14357 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14358 }
14359 return argf;
14360}
14361
14362/*
14363 * call-seq:
14364 * ARGF.each_char {|char| block } -> ARGF
14365 * ARGF.each_char -> an_enumerator
14366 *
14367 * Iterates over each character of each file in ARGF.
14368 *
14369 * This method allows you to treat the files supplied on the command line as
14370 * a single file consisting of the concatenation of each named file. After
14371 * the last character of the first file has been returned, the first
14372 * character of the second file is returned. The ARGF.filename method can
14373 * be used to determine the name of the file in which the current character
14374 * appears.
14375 *
14376 * If no block is given, an enumerator is returned instead.
14377 */
14378static VALUE
14379argf_each_char(VALUE argf)
14380{
14381 RETURN_ENUMERATOR(argf, 0, 0);
14382 FOREACH_ARGF() {
14383 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14384 }
14385 return argf;
14386}
14387
14388/*
14389 * call-seq:
14390 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14391 * ARGF.each_codepoint -> an_enumerator
14392 *
14393 * Iterates over each codepoint of each file in ARGF.
14394 *
14395 * This method allows you to treat the files supplied on the command line as
14396 * a single file consisting of the concatenation of each named file. After
14397 * the last codepoint of the first file has been returned, the first
14398 * codepoint of the second file is returned. The ARGF.filename method can
14399 * be used to determine the name of the file in which the current codepoint
14400 * appears.
14401 *
14402 * If no block is given, an enumerator is returned instead.
14403 */
14404static VALUE
14405argf_each_codepoint(VALUE argf)
14406{
14407 RETURN_ENUMERATOR(argf, 0, 0);
14408 FOREACH_ARGF() {
14409 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14410 }
14411 return argf;
14412}
14413
14414/*
14415 * call-seq:
14416 * ARGF.filename -> String
14417 * ARGF.path -> String
14418 *
14419 * Returns the current filename. "-" is returned when the current file is
14420 * STDIN.
14421 *
14422 * For example:
14423 *
14424 * $ echo "foo" > foo
14425 * $ echo "bar" > bar
14426 * $ echo "glark" > glark
14427 *
14428 * $ ruby argf.rb foo bar glark
14429 *
14430 * ARGF.filename #=> "foo"
14431 * ARGF.read(5) #=> "foo\nb"
14432 * ARGF.filename #=> "bar"
14433 * ARGF.skip
14434 * ARGF.filename #=> "glark"
14435 */
14436static VALUE
14437argf_filename(VALUE argf)
14438{
14439 next_argv();
14440 return ARGF.filename;
14441}
14442
14443static VALUE
14444argf_filename_getter(ID id, VALUE *var)
14445{
14446 return argf_filename(*var);
14447}
14448
14449/*
14450 * call-seq:
14451 * ARGF.file -> IO or File object
14452 *
14453 * Returns the current file as an IO or File object.
14454 * <code>$stdin</code> is returned when the current file is STDIN.
14455 *
14456 * For example:
14457 *
14458 * $ echo "foo" > foo
14459 * $ echo "bar" > bar
14460 *
14461 * $ ruby argf.rb foo bar
14462 *
14463 * ARGF.file #=> #<File:foo>
14464 * ARGF.read(5) #=> "foo\nb"
14465 * ARGF.file #=> #<File:bar>
14466 */
14467static VALUE
14468argf_file(VALUE argf)
14469{
14470 next_argv();
14471 return ARGF.current_file;
14472}
14473
14474/*
14475 * call-seq:
14476 * ARGF.binmode -> ARGF
14477 *
14478 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14479 * be reset to non-binary mode. This option has the following effects:
14480 *
14481 * * Newline conversion is disabled.
14482 * * Encoding conversion is disabled.
14483 * * Content is treated as ASCII-8BIT.
14484 */
14485static VALUE
14486argf_binmode_m(VALUE argf)
14487{
14488 ARGF.binmode = 1;
14489 next_argv();
14490 ARGF_FORWARD(0, 0);
14491 rb_io_ascii8bit_binmode(ARGF.current_file);
14492 return argf;
14493}
14494
14495/*
14496 * call-seq:
14497 * ARGF.binmode? -> true or false
14498 *
14499 * Returns true if ARGF is being read in binary mode; false otherwise.
14500 * To enable binary mode use ARGF.binmode.
14501 *
14502 * For example:
14503 *
14504 * ARGF.binmode? #=> false
14505 * ARGF.binmode
14506 * ARGF.binmode? #=> true
14507 */
14508static VALUE
14509argf_binmode_p(VALUE argf)
14510{
14511 return RBOOL(ARGF.binmode);
14512}
14513
14514/*
14515 * call-seq:
14516 * ARGF.skip -> ARGF
14517 *
14518 * Sets the current file to the next file in ARGV. If there aren't any more
14519 * files it has no effect.
14520 *
14521 * For example:
14522 *
14523 * $ ruby argf.rb foo bar
14524 * ARGF.filename #=> "foo"
14525 * ARGF.skip
14526 * ARGF.filename #=> "bar"
14527 */
14528static VALUE
14529argf_skip(VALUE argf)
14530{
14531 if (ARGF.init_p && ARGF.next_p == 0) {
14532 argf_close(argf);
14533 ARGF.next_p = 1;
14534 }
14535 return argf;
14536}
14537
14538/*
14539 * call-seq:
14540 * ARGF.close -> ARGF
14541 *
14542 * Closes the current file and skips to the next file in ARGV. If there are
14543 * no more files to open, just closes the current file. STDIN will not be
14544 * closed.
14545 *
14546 * For example:
14547 *
14548 * $ ruby argf.rb foo bar
14549 *
14550 * ARGF.filename #=> "foo"
14551 * ARGF.close
14552 * ARGF.filename #=> "bar"
14553 * ARGF.close
14554 */
14555static VALUE
14556argf_close_m(VALUE argf)
14557{
14558 next_argv();
14559 argf_close(argf);
14560 if (ARGF.next_p != -1) {
14561 ARGF.next_p = 1;
14562 }
14563 ARGF.lineno = 0;
14564 return argf;
14565}
14566
14567/*
14568 * call-seq:
14569 * ARGF.closed? -> true or false
14570 *
14571 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14572 * ARGF.close to actually close the current file.
14573 */
14574static VALUE
14575argf_closed(VALUE argf)
14576{
14577 next_argv();
14578 ARGF_FORWARD(0, 0);
14579 return rb_io_closed_p(ARGF.current_file);
14580}
14581
14582/*
14583 * call-seq:
14584 * ARGF.to_s -> String
14585 *
14586 * Returns "ARGF".
14587 */
14588static VALUE
14589argf_to_s(VALUE argf)
14590{
14591 return rb_str_new2("ARGF");
14592}
14593
14594/*
14595 * call-seq:
14596 * ARGF.inplace_mode -> String
14597 *
14598 * Returns the file extension appended to the names of backup copies of
14599 * modified files under in-place edit mode. This value can be set using
14600 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14601 */
14602static VALUE
14603argf_inplace_mode_get(VALUE argf)
14604{
14605 if (!ARGF.inplace) return Qnil;
14606 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14607 return rb_str_dup(ARGF.inplace);
14608}
14609
14610static VALUE
14611opt_i_get(ID id, VALUE *var)
14612{
14613 return argf_inplace_mode_get(*var);
14614}
14615
14616/*
14617 * call-seq:
14618 * ARGF.inplace_mode = ext -> ARGF
14619 *
14620 * Sets the filename extension for in-place editing mode to the given String.
14621 * The backup copy of each file being edited has this value appended to its
14622 * filename.
14623 *
14624 * For example:
14625 *
14626 * $ ruby argf.rb file.txt
14627 *
14628 * ARGF.inplace_mode = '.bak'
14629 * ARGF.each_line do |line|
14630 * print line.sub("foo","bar")
14631 * end
14632 *
14633 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14634 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14635 * "bar".
14636 */
14637static VALUE
14638argf_inplace_mode_set(VALUE argf, VALUE val)
14639{
14640 if (!RTEST(val)) {
14641 ARGF.inplace = Qfalse;
14642 }
14643 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14644 ARGF.inplace = Qnil;
14645 }
14646 else {
14647 ARGF.inplace = rb_str_new_frozen(val);
14648 }
14649 return argf;
14650}
14651
14652static void
14653opt_i_set(VALUE val, ID id, VALUE *var)
14654{
14655 argf_inplace_mode_set(*var, val);
14656}
14657
14658void
14659ruby_set_inplace_mode(const char *suffix)
14660{
14661 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14662}
14663
14664/*
14665 * call-seq:
14666 * ARGF.argv -> ARGV
14667 *
14668 * Returns the +ARGV+ array, which contains the arguments passed to your
14669 * script, one per element.
14670 *
14671 * For example:
14672 *
14673 * $ ruby argf.rb -v glark.txt
14674 *
14675 * ARGF.argv #=> ["-v", "glark.txt"]
14676 *
14677 */
14678static VALUE
14679argf_argv(VALUE argf)
14680{
14681 return ARGF.argv;
14682}
14683
14684static VALUE
14685argf_argv_getter(ID id, VALUE *var)
14686{
14687 return argf_argv(*var);
14688}
14689
14690VALUE
14692{
14693 return ARGF.argv;
14694}
14695
14696/*
14697 * call-seq:
14698 * ARGF.to_write_io -> io
14699 *
14700 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14701 * enabled.
14702 */
14703static VALUE
14704argf_write_io(VALUE argf)
14705{
14706 if (!RTEST(ARGF.current_file)) {
14707 rb_raise(rb_eIOError, "not opened for writing");
14708 }
14709 return GetWriteIO(ARGF.current_file);
14710}
14711
14712/*
14713 * call-seq:
14714 * ARGF.write(*objects) -> integer
14715 *
14716 * Writes each of the given +objects+ if inplace mode.
14717 */
14718static VALUE
14719argf_write(int argc, VALUE *argv, VALUE argf)
14720{
14721 return rb_io_writev(argf_write_io(argf), argc, argv);
14722}
14723
14724void
14725rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14726{
14727 rb_readwrite_syserr_fail(waiting, errno, mesg);
14728}
14729
14730void
14731rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14732{
14733 VALUE arg, c = Qnil;
14734 arg = mesg ? rb_str_new2(mesg) : Qnil;
14735 switch (waiting) {
14736 case RB_IO_WAIT_WRITABLE:
14737 switch (n) {
14738 case EAGAIN:
14739 c = rb_eEAGAINWaitWritable;
14740 break;
14741#if EAGAIN != EWOULDBLOCK
14742 case EWOULDBLOCK:
14743 c = rb_eEWOULDBLOCKWaitWritable;
14744 break;
14745#endif
14746 case EINPROGRESS:
14747 c = rb_eEINPROGRESSWaitWritable;
14748 break;
14749 default:
14751 }
14752 break;
14753 case RB_IO_WAIT_READABLE:
14754 switch (n) {
14755 case EAGAIN:
14756 c = rb_eEAGAINWaitReadable;
14757 break;
14758#if EAGAIN != EWOULDBLOCK
14759 case EWOULDBLOCK:
14760 c = rb_eEWOULDBLOCKWaitReadable;
14761 break;
14762#endif
14763 case EINPROGRESS:
14764 c = rb_eEINPROGRESSWaitReadable;
14765 break;
14766 default:
14768 }
14769 break;
14770 default:
14771 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14772 }
14774}
14775
14776static VALUE
14777get_LAST_READ_LINE(ID _x, VALUE *_y)
14778{
14779 return rb_lastline_get();
14780}
14781
14782static void
14783set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14784{
14785 rb_lastline_set(val);
14786}
14787
14788/*
14789 * Document-class: IOError
14790 *
14791 * Raised when an IO operation fails.
14792 *
14793 * File.open("/etc/hosts") {|f| f << "example"}
14794 * #=> IOError: not opened for writing
14795 *
14796 * File.open("/etc/hosts") {|f| f.close; f.read }
14797 * #=> IOError: closed stream
14798 *
14799 * Note that some IO failures raise <code>SystemCallError</code>s
14800 * and these are not subclasses of IOError:
14801 *
14802 * File.open("does/not/exist")
14803 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14804 */
14805
14806/*
14807 * Document-class: EOFError
14808 *
14809 * Raised by some IO operations when reaching the end of file. Many IO
14810 * methods exist in two forms,
14811 *
14812 * one that returns +nil+ when the end of file is reached, the other
14813 * raises EOFError.
14814 *
14815 * EOFError is a subclass of IOError.
14816 *
14817 * file = File.open("/etc/hosts")
14818 * file.read
14819 * file.gets #=> nil
14820 * file.readline #=> EOFError: end of file reached
14821 * file.close
14822 */
14823
14824/*
14825 * Document-class: ARGF
14826 *
14827 * == \ARGF and +ARGV+
14828 *
14829 * The \ARGF object works with the array at global variable +ARGV+
14830 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14831 *
14832 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14833 *
14834 * Initially, it contains the command-line arguments and options
14835 * that are passed to the Ruby program;
14836 * the program can modify that array as it likes.
14837 *
14838 * - **ARGF** may be thought of as the <b>argument files</b> object.
14839 *
14840 * It can access file streams and/or the <tt>$stdin</tt> stream,
14841 * based on what it finds in +ARGV+.
14842 * This provides a convenient way for the command line
14843 * to specify streams for a Ruby program to read.
14844 *
14845 * == Reading
14846 *
14847 * \ARGF may read from _source_ streams,
14848 * which at any particular time are determined by the content of +ARGV+.
14849 *
14850 * === Simplest Case
14851 *
14852 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14853 * the source is <tt>$stdin</tt>:
14854 *
14855 * - \File +t.rb+:
14856 *
14857 * p ['ARGV', ARGV]
14858 * p ['ARGF.read', ARGF.read]
14859 *
14860 * - Commands and outputs
14861 * (see below for the content of files +foo.txt+ and +bar.txt+):
14862 *
14863 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14864 * ["ARGV", []]
14865 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14866 *
14867 * $ cat foo.txt bar.txt | ruby t.rb
14868 * ["ARGV", []]
14869 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14870 *
14871 * === About the Examples
14872 *
14873 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14874 *
14875 * $ cat foo.txt
14876 * Foo 0
14877 * Foo 1
14878 * $ cat bar.txt
14879 * Bar 0
14880 * Bar 1
14881 * Bar 2
14882 * Bar 3
14883 *
14884 * === Sources in +ARGV+
14885 *
14886 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14887 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14888 * the sources are found in +ARGV+.
14889 *
14890 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14891 * and is one of:
14892 *
14893 * - The string path to a file that may be opened as a stream.
14894 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14895 *
14896 * Each element that is _not_ one of these
14897 * should be removed from +ARGV+ before \ARGF accesses that source.
14898 *
14899 * In the following example:
14900 *
14901 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14902 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14903 *
14904 * Example:
14905 *
14906 * - \File +t.rb+:
14907 *
14908 * # Print arguments (and options, if any) found on command line.
14909 * p ['ARGV', ARGV]
14910 *
14911 * - Command and output:
14912 *
14913 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14914 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14915 *
14916 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14917 *
14918 * - \File +t.rb+:
14919 *
14920 * p "ARGV: #{ARGV}"
14921 * p "Line: #{ARGF.read}" # Read everything from all specified streams.
14922 *
14923 * - Command and output:
14924 *
14925 * $ ruby t.rb foo.txt bar.txt
14926 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14927 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14928 *
14929 * Because the value at +ARGV+ is an ordinary array,
14930 * you can manipulate it to control which sources \ARGF considers:
14931 *
14932 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14933 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14934 *
14935 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14936 * when all sources have been accessed, the array is empty:
14937 *
14938 * - \File +t.rb+:
14939 *
14940 * until ARGV.empty? && ARGF.eof?
14941 * p "ARGV: #{ARGV}"
14942 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14943 * end
14944 *
14945 * - Command and output:
14946 *
14947 * $ ruby t.rb foo.txt bar.txt
14948 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14949 * "Line: Foo 0\n"
14950 * "ARGV: [\"bar.txt\"]"
14951 * "Line: Foo 1\n"
14952 * "ARGV: [\"bar.txt\"]"
14953 * "Line: Bar 0\n"
14954 * "ARGV: []"
14955 * "Line: Bar 1\n"
14956 * "ARGV: []"
14957 * "Line: Bar 2\n"
14958 * "ARGV: []"
14959 * "Line: Bar 3\n"
14960 *
14961 * ==== Filepaths in +ARGV+
14962 *
14963 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14964 *
14965 * This program prints what it reads from files at the paths specified
14966 * on the command line:
14967 *
14968 * - \File +t.rb+:
14969 *
14970 * p ['ARGV', ARGV]
14971 * # Read and print all content from the specified sources.
14972 * p ['ARGF.read', ARGF.read]
14973 *
14974 * - Command and output:
14975 *
14976 * $ ruby t.rb foo.txt bar.txt
14977 * ["ARGV", [foo.txt, bar.txt]
14978 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14979 *
14980 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14981 *
14982 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14983 *
14984 * - \File +t.rb+:
14985 *
14986 * p ['ARGV', ARGV]
14987 * p ['ARGF.read', ARGF.read]
14988 *
14989 * - Command and output:
14990 *
14991 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14992 * ["ARGV", ["-"]]
14993 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14994 *
14995 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
14996 * (exception:
14997 * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
14998 *
14999 * - Command and output:
15000 *
15001 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
15002 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15003 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15004 *
15005 * ==== Mixtures and Repetitions in +ARGV+
15006 *
15007 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
15008 * and character <tt>'-'</tt>, including repetitions.
15009 *
15010 * ==== Modifications to +ARGV+
15011 *
15012 * The running Ruby program may make any modifications to the +ARGV+ array;
15013 * the current value of +ARGV+ affects \ARGF reading.
15014 *
15015 * ==== Empty +ARGV+
15016 *
15017 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15018 * or raises an exception, depending on the specific method.
15019 *
15020 * === More Read Methods
15021 *
15022 * As seen above, method ARGF#read reads the content of all sources
15023 * into a single string.
15024 * Other \ARGF methods provide other ways to access that content;
15025 * these include:
15026 *
15027 * - Byte access: #each_byte, #getbyte, #readbyte.
15028 * - Character access: #each_char, #getc, #readchar.
15029 * - Codepoint access: #each_codepoint.
15030 * - Line access: #each_line, #gets, #readline, #readlines.
15031 * - Source access: #read, #read_nonblock, #readpartial.
15032 *
15033 * === About \Enumerable
15034 *
15035 * \ARGF includes module Enumerable.
15036 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15037 *
15038 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15039 * _not_ from +ARGV+;
15040 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15041 * not an array of the strings from +ARGV+:
15042 *
15043 * - \File +t.rb+:
15044 *
15045 * p ['ARGV', ARGV]
15046 * p ['ARGF.entries', ARGF.entries]
15047 *
15048 * - Command and output:
15049 *
15050 * $ ruby t.rb foo.txt bar.txt
15051 * ["ARGV", ["foo.txt", "bar.txt"]]
15052 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15053 *
15054 * == Writing
15055 *
15056 * If <i>inplace mode</i> is in effect,
15057 * \ARGF may write to target streams,
15058 * which at any particular time are determined by the content of ARGV.
15059 *
15060 * Methods about inplace mode:
15061 *
15062 * - #inplace_mode
15063 * - #inplace_mode=
15064 * - #to_write_io
15065 *
15066 * Methods for writing:
15067 *
15068 * - #print
15069 * - #printf
15070 * - #putc
15071 * - #puts
15072 * - #write
15073 *
15074 */
15075
15076/*
15077 * An instance of class \IO (commonly called a _stream_)
15078 * represents an input/output stream in the underlying operating system.
15079 * Class \IO is the basis for input and output in Ruby.
15080 *
15081 * Class File is the only class in the Ruby core that is a subclass of \IO.
15082 * Some classes in the Ruby standard library are also subclasses of \IO;
15083 * these include TCPSocket and UDPSocket.
15084 *
15085 * The global constant ARGF (also accessible as <tt>$<</tt>)
15086 * provides an IO-like stream that allows access to all file paths
15087 * found in ARGV (or found in STDIN if ARGV is empty).
15088 * ARGF is not itself a subclass of \IO.
15089 *
15090 * Class StringIO provides an IO-like stream that handles a String.
15091 * StringIO is not itself a subclass of \IO.
15092 *
15093 * Important objects based on \IO include:
15094 *
15095 * - $stdin.
15096 * - $stdout.
15097 * - $stderr.
15098 * - Instances of class File.
15099 *
15100 * An instance of \IO may be created using:
15101 *
15102 * - IO.new: returns a new \IO object for the given integer file descriptor.
15103 * - IO.open: passes a new \IO object to the given block.
15104 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15105 * of a newly-launched subprocess.
15106 * - Kernel#open: Returns a new \IO object connected to a given source:
15107 * stream, file, or subprocess.
15108 *
15109 * Like a File stream, an \IO stream has:
15110 *
15111 * - A read/write mode, which may be read-only, write-only, or read/write;
15112 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
15113 * - A data mode, which may be text-only or binary;
15114 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15115 * - Internal and external encodings;
15116 * see {Encodings}[rdoc-ref:File@Encodings].
15117 *
15118 * And like other \IO streams, it has:
15119 *
15120 * - A position, which determines where in the stream the next
15121 * read or write is to occur;
15122 * see {Position}[rdoc-ref:IO@Position].
15123 * - A line number, which is a special, line-oriented, "position"
15124 * (different from the position mentioned above);
15125 * see {Line Number}[rdoc-ref:IO@Line+Number].
15126 *
15127 * == Extension <tt>io/console</tt>
15128 *
15129 * Extension <tt>io/console</tt> provides numerous methods
15130 * for interacting with the console;
15131 * requiring it adds numerous methods to class \IO.
15132 *
15133 * == Example Files
15134 *
15135 * Many examples here use these variables:
15136 *
15137 * :include: doc/examples/files.rdoc
15138 *
15139 * == Open Options
15140 *
15141 * A number of \IO methods accept optional keyword arguments
15142 * that determine how a new stream is to be opened:
15143 *
15144 * - +:mode+: Stream mode.
15145 * - +:flags+: Integer file open flags;
15146 * If +mode+ is also given, the two are bitwise-ORed.
15147 * - +:external_encoding+: External encoding for the stream.
15148 * - +:internal_encoding+: Internal encoding for the stream.
15149 * <tt>'-'</tt> is a synonym for the default internal encoding.
15150 * If the value is +nil+ no conversion occurs.
15151 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15152 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15153 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15154 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15155 * when the stream closes; otherwise it remains open.
15156 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15157 * #path method.
15158 *
15159 * Also available are the options offered in String#encode,
15160 * which may control conversion between external and internal encoding.
15161 *
15162 * == Basic \IO
15163 *
15164 * You can perform basic stream \IO with these methods,
15165 * which typically operate on multi-byte strings:
15166 *
15167 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15168 * - IO#write: Writes zero or more strings to the stream;
15169 * each given object that is not already a string is converted via +to_s+.
15170 *
15171 * === Position
15172 *
15173 * An \IO stream has a nonnegative integer _position_,
15174 * which is the byte offset at which the next read or write is to occur.
15175 * A new stream has position zero (and line number zero);
15176 * method +rewind+ resets the position (and line number) to zero.
15177 *
15178 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15179 * Encoding::Converter instances used for that \IO.
15180 *
15181 * The relevant methods:
15182 *
15183 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15184 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15185 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15186 * relative to a given position +whence+
15187 * (indicating the beginning, end, or current position).
15188 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15189 *
15190 * === Open and Closed Streams
15191 *
15192 * A new \IO stream may be open for reading, open for writing, or both.
15193 *
15194 * A stream is automatically closed when claimed by the garbage collector.
15195 *
15196 * Attempted reading or writing on a closed stream raises an exception.
15197 *
15198 * The relevant methods:
15199 *
15200 * - IO#close: Closes the stream for both reading and writing.
15201 * - IO#close_read: Closes the stream for reading.
15202 * - IO#close_write: Closes the stream for writing.
15203 * - IO#closed?: Returns whether the stream is closed.
15204 *
15205 * === End-of-Stream
15206 *
15207 * You can query whether a stream is positioned at its end:
15208 *
15209 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15210 *
15211 * You can reposition to end-of-stream by using method IO#seek:
15212 *
15213 * f = File.new('t.txt')
15214 * f.eof? # => false
15215 * f.seek(0, :END)
15216 * f.eof? # => true
15217 * f.close
15218 *
15219 * Or by reading all stream content (which is slower than using IO#seek):
15220 *
15221 * f.rewind
15222 * f.eof? # => false
15223 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15224 * f.eof? # => true
15225 *
15226 * == Line \IO
15227 *
15228 * Class \IO supports line-oriented
15229 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15230 *
15231 * === Line Input
15232 *
15233 * Class \IO supports line-oriented input for
15234 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15235 *
15236 * ==== \File Line Input
15237 *
15238 * You can read lines from a file using these methods:
15239 *
15240 * - IO.foreach: Reads each line and passes it to the given block.
15241 * - IO.readlines: Reads and returns all lines in an array.
15242 *
15243 * For each of these methods:
15244 *
15245 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15246 * - Line parsing depends on the effective <i>line separator</i>;
15247 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15248 * - The length of each returned line depends on the effective <i>line limit</i>;
15249 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15250 *
15251 * ==== Stream Line Input
15252 *
15253 * You can read lines from an \IO stream using these methods:
15254 *
15255 * - IO#each_line: Reads each remaining line, passing it to the given block.
15256 * - IO#gets: Returns the next line.
15257 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15258 * - IO#readlines: Returns all remaining lines in an array.
15259 *
15260 * For each of these methods:
15261 *
15262 * - Reading may begin mid-line,
15263 * depending on the stream's _position_;
15264 * see {Position}[rdoc-ref:IO@Position].
15265 * - Line parsing depends on the effective <i>line separator</i>;
15266 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15267 * - The length of each returned line depends on the effective <i>line limit</i>;
15268 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15269 *
15270 * ===== Line Separator
15271 *
15272 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15273 * the string that determines what is considered a line;
15274 * it is sometimes called the <i>input record separator</i>.
15275 *
15276 * The default line separator is taken from global variable <tt>$/</tt>,
15277 * whose initial value is <tt>"\n"</tt>.
15278 *
15279 * Generally, the line to be read next is all data
15280 * from the current {position}[rdoc-ref:IO@Position]
15281 * to the next line separator
15282 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15283 *
15284 * f = File.new('t.txt')
15285 * # Method gets with no sep argument returns the next line, according to $/.
15286 * f.gets # => "First line\n"
15287 * f.gets # => "Second line\n"
15288 * f.gets # => "\n"
15289 * f.gets # => "Fourth line\n"
15290 * f.gets # => "Fifth line\n"
15291 * f.close
15292 *
15293 * You can use a different line separator by passing argument +sep+:
15294 *
15295 * f = File.new('t.txt')
15296 * f.gets('l') # => "First l"
15297 * f.gets('li') # => "ine\nSecond li"
15298 * f.gets('lin') # => "ne\n\nFourth lin"
15299 * f.gets # => "e\n"
15300 * f.close
15301 *
15302 * Or by setting global variable <tt>$/</tt>:
15303 *
15304 * f = File.new('t.txt')
15305 * $/ = 'l'
15306 * f.gets # => "First l"
15307 * f.gets # => "ine\nSecond l"
15308 * f.gets # => "ine\n\nFourth l"
15309 * f.close
15310 *
15311 * ===== Special Line Separator Values
15312 *
15313 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15314 * accepts two special values for parameter +sep+:
15315 *
15316 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15317 *
15318 * f = File.new('t.txt')
15319 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15320 * f.close
15321 *
15322 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15323 * (paragraphs being separated by two consecutive line separators):
15324 *
15325 * f = File.new('t.txt')
15326 * f.gets('') # => "First line\nSecond line\n\n"
15327 * f.gets('') # => "Fourth line\nFifth line\n"
15328 * f.close
15329 *
15330 * ===== Line Limit
15331 *
15332 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15333 * uses an integer <i>line limit</i>,
15334 * which restricts the number of bytes that may be returned.
15335 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15336 * than the limit).
15337 *
15338 * The default limit value is <tt>-1</tt>;
15339 * any negative limit value means that there is no limit.
15340 *
15341 * If there is no limit, the line is determined only by +sep+.
15342 *
15343 * # Text with 1-byte characters.
15344 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15345 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15346 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15347 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15348 * # No more than one line.
15349 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15350 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15351 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15352 *
15353 * # Text with 2-byte characters, which will not be split.
15354 * File.open('t.rus') {|f| f.gets(1).size } # => 1
15355 * File.open('t.rus') {|f| f.gets(2).size } # => 1
15356 * File.open('t.rus') {|f| f.gets(3).size } # => 2
15357 * File.open('t.rus') {|f| f.gets(4).size } # => 2
15358 *
15359 * ===== Line Separator and Line Limit
15360 *
15361 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15362 *
15363 * - Returns the next line as determined by line separator +sep+.
15364 * - But returns no more bytes than are allowed by the limit +limit+.
15365 *
15366 * Example:
15367 *
15368 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15369 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15370 *
15371 * ===== Line Number
15372 *
15373 * A readable \IO stream has a non-negative integer <i>line number</i>:
15374 *
15375 * - IO#lineno: Returns the line number.
15376 * - IO#lineno=: Resets and returns the line number.
15377 *
15378 * Unless modified by a call to method IO#lineno=,
15379 * the line number is the number of lines read
15380 * by certain line-oriented methods,
15381 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15382 *
15383 * - IO.foreach: Increments the line number on each call to the block.
15384 * - IO#each_line: Increments the line number on each call to the block.
15385 * - IO#gets: Increments the line number.
15386 * - IO#readline: Increments the line number.
15387 * - IO#readlines: Increments the line number for each line read.
15388 *
15389 * A new stream is initially has line number zero (and position zero);
15390 * method +rewind+ resets the line number (and position) to zero:
15391 *
15392 * f = File.new('t.txt')
15393 * f.lineno # => 0
15394 * f.gets # => "First line\n"
15395 * f.lineno # => 1
15396 * f.rewind
15397 * f.lineno # => 0
15398 * f.close
15399 *
15400 * Reading lines from a stream usually changes its line number:
15401 *
15402 * f = File.new('t.txt', 'r')
15403 * f.lineno # => 0
15404 * f.readline # => "This is line one.\n"
15405 * f.lineno # => 1
15406 * f.readline # => "This is the second line.\n"
15407 * f.lineno # => 2
15408 * f.readline # => "Here's the third line.\n"
15409 * f.lineno # => 3
15410 * f.eof? # => true
15411 * f.close
15412 *
15413 * Iterating over lines in a stream usually changes its line number:
15414 *
15415 * File.open('t.txt') do |f|
15416 * f.each_line do |line|
15417 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15418 * end
15419 * end
15420 *
15421 * Output:
15422 *
15423 * "position=11 eof?=false lineno=1"
15424 * "position=23 eof?=false lineno=2"
15425 * "position=24 eof?=false lineno=3"
15426 * "position=36 eof?=false lineno=4"
15427 * "position=47 eof?=true lineno=5"
15428 *
15429 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15430 * the line number does not affect where the next read or write will occur:
15431 *
15432 * f = File.new('t.txt')
15433 * f.lineno = 1000
15434 * f.lineno # => 1000
15435 * f.gets # => "First line\n"
15436 * f.lineno # => 1001
15437 * f.close
15438 *
15439 * Associated with the line number is the global variable <tt>$.</tt>:
15440 *
15441 * - When a stream is opened, <tt>$.</tt> is not set;
15442 * its value is left over from previous activity in the process:
15443 *
15444 * $. = 41
15445 * f = File.new('t.txt')
15446 * $. = 41
15447 * # => 41
15448 * f.close
15449 *
15450 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15451 *
15452 * f0 = File.new('t.txt')
15453 * f1 = File.new('t.dat')
15454 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15455 * $. # => 5
15456 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15457 * $. # => 1
15458 * f0.close
15459 * f1.close
15460 *
15461 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15462 *
15463 * f = File.new('t.txt')
15464 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15465 * $. # => 5
15466 * f.rewind
15467 * f.seek(0, :SET)
15468 * $. # => 5
15469 * f.close
15470 *
15471 * === Line Output
15472 *
15473 * You can write to an \IO stream line-by-line using this method:
15474 *
15475 * - IO#puts: Writes objects to the stream.
15476 *
15477 * == Character \IO
15478 *
15479 * You can process an \IO stream character-by-character using these methods:
15480 *
15481 * - IO#getc: Reads and returns the next character from the stream.
15482 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15483 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15484 * - IO#putc: Writes a character to the stream.
15485 * - IO#each_char: Reads each remaining character in the stream,
15486 * passing the character to the given block.
15487 *
15488 * == Byte \IO
15489 *
15490 * You can process an \IO stream byte-by-byte using these methods:
15491 *
15492 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15493 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15494 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15495 * - IO#each_byte: Reads each remaining byte in the stream,
15496 * passing the byte to the given block.
15497 *
15498 * == Codepoint \IO
15499 *
15500 * You can process an \IO stream codepoint-by-codepoint:
15501 *
15502 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15503 *
15504 * == What's Here
15505 *
15506 * First, what's elsewhere. Class \IO:
15507 *
15508 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15509 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15510 * which provides dozens of additional methods.
15511 *
15512 * Here, class \IO provides methods that are useful for:
15513 *
15514 * - {Creating}[rdoc-ref:IO@Creating]
15515 * - {Reading}[rdoc-ref:IO@Reading]
15516 * - {Writing}[rdoc-ref:IO@Writing]
15517 * - {Positioning}[rdoc-ref:IO@Positioning]
15518 * - {Iterating}[rdoc-ref:IO@Iterating]
15519 * - {Settings}[rdoc-ref:IO@Settings]
15520 * - {Querying}[rdoc-ref:IO@Querying]
15521 * - {Buffering}[rdoc-ref:IO@Buffering]
15522 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15523 * - {Other}[rdoc-ref:IO@Other]
15524 *
15525 * === Creating
15526 *
15527 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15528 * integer file descriptor.
15529 * - ::open: Creates a new \IO object.
15530 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15531 * - ::popen: Creates an \IO object to interact with a subprocess.
15532 * - ::select: Selects which given \IO instances are ready for reading,
15533 * writing, or have pending exceptions.
15534 *
15535 * === Reading
15536 *
15537 * - ::binread: Returns a binary string with all or a subset of bytes
15538 * from the given file.
15539 * - ::read: Returns a string with all or a subset of bytes from the given file.
15540 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15541 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15542 * - #getc: Returns the next character read from +self+ as a string.
15543 * - #gets: Returns the line read from +self+.
15544 * - #pread: Returns all or the next _n_ bytes read from +self+,
15545 * not updating the receiver's offset.
15546 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15547 * for a given _n_.
15548 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15549 * in non-block mode.
15550 * - #readbyte: Returns the next byte read from +self+;
15551 * same as #getbyte, but raises an exception on end-of-stream.
15552 * - #readchar: Returns the next character read from +self+;
15553 * same as #getc, but raises an exception on end-of-stream.
15554 * - #readline: Returns the next line read from +self+;
15555 * same as #getline, but raises an exception of end-of-stream.
15556 * - #readlines: Returns an array of all lines read read from +self+.
15557 * - #readpartial: Returns up to the given number of bytes from +self+.
15558 *
15559 * === Writing
15560 *
15561 * - ::binwrite: Writes the given string to the file at the given filepath,
15562 * in binary mode.
15563 * - ::write: Writes the given string to +self+.
15564 * - #<<: Appends the given string to +self+.
15565 * - #print: Prints last read line or given objects to +self+.
15566 * - #printf: Writes to +self+ based on the given format string and objects.
15567 * - #putc: Writes a character to +self+.
15568 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15569 * - #pwrite: Writes the given string at the given offset,
15570 * not updating the receiver's offset.
15571 * - #write: Writes one or more given strings to +self+.
15572 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15573 *
15574 * === Positioning
15575 *
15576 * - #lineno: Returns the current line number in +self+.
15577 * - #lineno=: Sets the line number is +self+.
15578 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15579 * - #pos=: Sets the byte offset in +self+.
15580 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15581 * - #rewind: Positions +self+ to the beginning of input.
15582 * - #seek: Sets the offset for +self+ relative to given position.
15583 *
15584 * === Iterating
15585 *
15586 * - ::foreach: Yields each line of given file to the block.
15587 * - #each (aliased as #each_line): Calls the given block
15588 * with each successive line in +self+.
15589 * - #each_byte: Calls the given block with each successive byte in +self+
15590 * as an integer.
15591 * - #each_char: Calls the given block with each successive character in +self+
15592 * as a string.
15593 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15594 * as an integer.
15595 *
15596 * === Settings
15597 *
15598 * - #autoclose=: Sets whether +self+ auto-closes.
15599 * - #binmode: Sets +self+ to binary mode.
15600 * - #close: Closes +self+.
15601 * - #close_on_exec=: Sets the close-on-exec flag.
15602 * - #close_read: Closes +self+ for reading.
15603 * - #close_write: Closes +self+ for writing.
15604 * - #set_encoding: Sets the encoding for +self+.
15605 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15606 * Unicode byte-order-mark.
15607 * - #sync=: Sets the sync-mode to the given value.
15608 *
15609 * === Querying
15610 *
15611 * - #autoclose?: Returns whether +self+ auto-closes.
15612 * - #binmode?: Returns whether +self+ is in binary mode.
15613 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15614 * - #closed?: Returns whether +self+ is closed.
15615 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15616 * - #external_encoding: Returns the external encoding object for +self+.
15617 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15618 * - #internal_encoding: Returns the internal encoding object for +self+.
15619 * - #pid: Returns the process ID of a child process associated with +self+,
15620 * if +self+ was created by ::popen.
15621 * - #stat: Returns the File::Stat object containing status information for +self+.
15622 * - #sync: Returns whether +self+ is in sync-mode.
15623 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15624 *
15625 * === Buffering
15626 *
15627 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15628 * - #flush: Flushes any buffered data within +self+ to the underlying
15629 * operating system.
15630 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15631 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15632 * - #ungetc: Prepends buffer for +self+ with given string.
15633 *
15634 * === Low-Level Access
15635 *
15636 * - ::sysopen: Opens the file given by its path,
15637 * returning the integer file descriptor.
15638 * - #advise: Announces the intention to access data from +self+ in a specific way.
15639 * - #fcntl: Passes a low-level command to the file specified
15640 * by the given file descriptor.
15641 * - #ioctl: Passes a low-level command to the device specified
15642 * by the given file descriptor.
15643 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15644 * - #sysseek: Sets the offset for +self+.
15645 * - #syswrite: Writes the given string to +self+ using a low-level write.
15646 *
15647 * === Other
15648 *
15649 * - ::copy_stream: Copies data from a source to a destination,
15650 * each of which is a filepath or an \IO-like object.
15651 * - ::try_convert: Returns a new \IO object resulting from converting
15652 * the given object.
15653 * - #inspect: Returns the string representation of +self+.
15654 *
15655 */
15656
15657void
15658Init_IO(void)
15659{
15660 VALUE rb_cARGF;
15661#ifdef __CYGWIN__
15662#include <sys/cygwin.h>
15663 static struct __cygwin_perfile pf[] =
15664 {
15665 {"", O_RDONLY | O_BINARY},
15666 {"", O_WRONLY | O_BINARY},
15667 {"", O_RDWR | O_BINARY},
15668 {"", O_APPEND | O_BINARY},
15669 {NULL, 0}
15670 };
15671 cygwin_internal(CW_PERFILE, pf);
15672#endif
15673
15676
15677 id_write = rb_intern_const("write");
15678 id_read = rb_intern_const("read");
15679 id_getc = rb_intern_const("getc");
15680 id_flush = rb_intern_const("flush");
15681 id_readpartial = rb_intern_const("readpartial");
15682 id_set_encoding = rb_intern_const("set_encoding");
15683 id_fileno = rb_intern_const("fileno");
15684
15685 rb_define_global_function("syscall", rb_f_syscall, -1);
15686
15687 rb_define_global_function("open", rb_f_open, -1);
15688 rb_define_global_function("printf", rb_f_printf, -1);
15689 rb_define_global_function("print", rb_f_print, -1);
15690 rb_define_global_function("putc", rb_f_putc, 1);
15691 rb_define_global_function("puts", rb_f_puts, -1);
15692 rb_define_global_function("gets", rb_f_gets, -1);
15693 rb_define_global_function("readline", rb_f_readline, -1);
15694 rb_define_global_function("select", rb_f_select, -1);
15695
15696 rb_define_global_function("readlines", rb_f_readlines, -1);
15697
15698 rb_define_global_function("`", rb_f_backquote, 1);
15699
15700 rb_define_global_function("p", rb_f_p, -1);
15701 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15702
15703 rb_cIO = rb_define_class("IO", rb_cObject);
15705
15706 /* Can be raised by IO operations when IO#timeout= is set. */
15708
15709 /* Readable event mask for IO#wait. */
15710 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15711 /* Writable event mask for IO#wait. */
15712 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15713 /* Priority event mask for IO#wait. */
15714 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15715
15716 /* exception to wait for reading. see IO.select. */
15718 /* exception to wait for writing. see IO.select. */
15720 /* exception to wait for reading by EAGAIN. see IO.select. */
15721 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15722 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15723 /* exception to wait for writing by EAGAIN. see IO.select. */
15724 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15725 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15726#if EAGAIN == EWOULDBLOCK
15727 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15728 /* same as IO::EAGAINWaitReadable */
15729 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15730 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15731 /* same as IO::EAGAINWaitWritable */
15732 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15733#else
15734 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15735 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15736 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15737 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15738 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15739 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15740#endif
15741 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15742 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15743 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15744 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15745 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15746 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15747
15748#if 0
15749 /* This is necessary only for forcing rdoc handle File::open */
15750 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15751#endif
15752
15753 rb_define_alloc_func(rb_cIO, io_alloc);
15754 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15755 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15756 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15757 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15758 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15759 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15760 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15761 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15762 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15763 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15764 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15765 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15766 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15767 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15768 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15769
15770 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15771
15773 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15774
15775 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15776 rb_vm_register_global_object(rb_default_rs);
15777 rb_rs = rb_default_rs;
15779 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15780 rb_gvar_ractor_local("$/"); // not local but ractor safe
15781 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15782 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15783 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15784
15785 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15786 rb_gvar_ractor_local("$_");
15787
15788 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15789 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15790
15791 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15792 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15793 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15794 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15795
15796 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15797 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15798 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15799 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15800 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15801
15802 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15803 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15804
15805 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15806 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15807
15808 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15809 rb_define_alias(rb_cIO, "to_i", "fileno");
15810 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15811
15812 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15813 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15814
15815 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15816 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15817 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15818 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15819
15820 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15821 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15822
15823 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15824
15825 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15826 rb_define_method(rb_cIO, "read", io_read, -1);
15827 rb_define_method(rb_cIO, "write", io_write_m, -1);
15828 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15829 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15830 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15831 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15832 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15833 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15834 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15836 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15837 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15838 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15839 /* Set I/O position from the beginning */
15840 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15841 /* Set I/O position from the current position */
15842 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15843 /* Set I/O position from the end */
15844 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15845#ifdef SEEK_DATA
15846 /* Set I/O position to the next location containing data */
15847 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15848#endif
15849#ifdef SEEK_HOLE
15850 /* Set I/O position to the next hole */
15851 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15852#endif
15853 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15854 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15855 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15856 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15857 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15858
15859 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15860 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15861
15862 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15863 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15864 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15865 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15866
15867 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15868 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15869 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15870 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15871 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15872 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15873
15874 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15875 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15876 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15877
15878 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15879 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15880
15881 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15882
15883 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15884 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15885 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15886 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15887
15888 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15889 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15890
15891 rb_define_method(rb_cIO, "wait", io_wait, -1);
15892
15893 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15894 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15895 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15896
15897 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15898 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15899 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15900 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15901
15902 rb_gvar_ractor_local("$stdin");
15903 rb_gvar_ractor_local("$stdout");
15904 rb_gvar_ractor_local("$>");
15905 rb_gvar_ractor_local("$stderr");
15906
15908 rb_stdin = rb_io_prep_stdin();
15910 rb_stdout = rb_io_prep_stdout();
15912 rb_stderr = rb_io_prep_stderr();
15913
15914 orig_stdout = rb_stdout;
15915 orig_stderr = rb_stderr;
15916
15917 /* Holds the original stdin */
15919 /* Holds the original stdout */
15921 /* Holds the original stderr */
15923
15924#if 0
15925 /* Hack to get rdoc to regard ARGF as a class: */
15926 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15927#endif
15928
15929 rb_cARGF = rb_class_new(rb_cObject);
15930 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15931 rb_define_alloc_func(rb_cARGF, argf_alloc);
15932
15934
15935 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15936 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15937 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15938 rb_define_alias(rb_cARGF, "inspect", "to_s");
15939 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15940
15941 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15942 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15943 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15944 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15945 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15946 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15947 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15948 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15949 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15950
15951 rb_define_method(rb_cARGF, "read", argf_read, -1);
15952 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15953 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15954 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15955 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15956 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15957 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15958 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15959 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15960 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15961 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15962 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15963 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15964 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15965 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15966 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15967 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15968 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15969 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15970 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15971
15972 rb_define_method(rb_cARGF, "write", argf_write, -1);
15973 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15974 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15975 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15976 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15977
15978 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15979 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15980 rb_define_method(rb_cARGF, "file", argf_file, 0);
15981 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15982 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15983 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15984
15985 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15986 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15987
15988 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15989 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15990
15991 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15992 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15993 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15994
15995 argf = rb_class_new_instance(0, 0, rb_cARGF);
15996
15998 /*
15999 * ARGF is a stream designed for use in scripts that process files given
16000 * as command-line arguments or passed in via STDIN.
16001 *
16002 * See ARGF (the class) for more details.
16003 */
16005
16006 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
16007 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
16008 ARGF.filename = rb_str_new2("-");
16009
16010 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
16011 rb_gvar_ractor_local("$-i");
16012
16013 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16014
16015#if defined (_WIN32) || defined(__CYGWIN__)
16016 atexit(pipe_atexit);
16017#endif
16018
16019 Init_File();
16020
16021 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16022
16023 sym_mode = ID2SYM(rb_intern_const("mode"));
16024 sym_perm = ID2SYM(rb_intern_const("perm"));
16025 sym_flags = ID2SYM(rb_intern_const("flags"));
16026 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16027 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16028 sym_encoding = ID2SYM(rb_id_encoding());
16029 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16030 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16031 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16032 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16033 sym_normal = ID2SYM(rb_intern_const("normal"));
16034 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16035 sym_random = ID2SYM(rb_intern_const("random"));
16036 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16037 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16038 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16039 sym_SET = ID2SYM(rb_intern_const("SET"));
16040 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16041 sym_END = ID2SYM(rb_intern_const("END"));
16042#ifdef SEEK_DATA
16043 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16044#endif
16045#ifdef SEEK_HOLE
16046 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16047#endif
16048 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16049 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16050}
16051
16052#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:1701
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1484
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:855
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1520
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1630
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2848
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:3151
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:3138
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:943
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2927
#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:682
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:14731
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:14725
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2117
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1450
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:61
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3229
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:646
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2125
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2166
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:2154
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
VALUE rb_stdin
STDIN constant.
Definition io.c:201
VALUE rb_stderr
STDERR constant.
Definition io.c:201
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:243
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:553
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:657
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:1299
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:3210
VALUE rb_cFile
File class.
Definition file.c:190
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:3223
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:1663
int rb_enc_str_coderange(VALUE str)
Scans the passed string to collect its code range.
Definition string.c:1278
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:1162
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:8614
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4304
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:427
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
Definition io.c:8759
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2351
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9188
VALUE rb_io_ungetbyte(VALUE io, VALUE b)
Identical to rb_io_ungetc(), except it doesn't take the encoding of the passed IO into account.
Definition io.c:5173
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5079
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:374
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
Definition io.c:9369
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:248
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:328
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:206
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2696
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
Definition io.c:9168
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
Definition io.c:298
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6379
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6333
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5237
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7381
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10458
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:461
VALUE rb_output_fs
The field separator character for outputs, or the $,.
Definition io.c:204
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
Definition io.c:7264
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:367
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7271
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5753
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:207
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:1879
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:1873
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
Definition proc.c:2980
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1168
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:682
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c: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:1332
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1839
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:2302
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:4587
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:3255
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3555
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3674
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:3049
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:2029
#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:2161
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1455
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:1438
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:3152
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:1461
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2962
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:434
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:2127
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:493
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3094
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:4199
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:834
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:162
enum rb_io_mode rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
Definition io.c:6465
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:811
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:857
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:781
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1069
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
Definition io.c:6598
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
Definition io.h:260
rb_io_event
Type of events that an IO can wait.
Definition io.h:96
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:97
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition io.h:99
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition io.h:98
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:168
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
Definition io.h:252
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:442
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
Definition io.c:1015
#define FMODE_TTY
The IO is a TTY.
Definition io.h:192
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:215
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition io.c:1024
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
Definition io.c:1592
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
Definition io.c:7081
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
Definition io.c:6747
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2899
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:165
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
Definition io.c:9415
#define FMODE_APPEND
The IO is opened for appending.
Definition io.h:207
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition io.h:465
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition io.h:200
#define FMODE_BINMODE
The IO is in "binary mode".
Definition io.h:179
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
Definition io.c:1651
int capa
Designed capacity of the buffer.
Definition io.h:11
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition io.h:436
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
Definition io.c:1610
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:190
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:2
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:186
int off
Offset inside of ptr.
Definition io.h:5
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
Definition io.c:2973
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, enum rb_io_mode *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
Definition io.c:6872
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:788
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
Definition io.h:223
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition io.h:243
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
Definition io.c:5675
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
Definition io.c:817
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:5861
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:886
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:2016
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:996
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
Definition io.h:229
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:823
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3425
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1549
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
Definition io.c:9281
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:834
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1048
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
Definition io.c:1666
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:796
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1515
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7368
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1454
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:1014
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:1074
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:1062
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:1050
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:2032
#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:497
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14691
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9067
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:90
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
Definition scan_args.h:59
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition scan_args.h:78
Scheduler APIs.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
Definition scheduler.c:463
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
Definition scheduler.c:957
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
Definition scheduler.c:506
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
Definition scheduler.c:709
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
Definition scheduler.c:933
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:695
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
Definition scheduler.h:71
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:739
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
Definition scheduler.c:969
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread instead of...
Definition scheduler.c:468
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
Definition scheduler.c:945
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
Definition scheduler.c:715
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
Definition thread.c:4505
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
@ RUBY_Qfalse
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
C99 shim for <stdbool.h>
Ruby's File and IO.
Definition rfile.h:35
Definition io.c:236
Definition win32.h:239
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h: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:134
int ecflags
Flags.
Definition io.h:144
VALUE ecopts
Flags as Ruby hash.
Definition io.h:152
rb_encoding * enc2
External encoding.
Definition io.h:138
rb_encoding * enc
Internal encoding.
Definition io.h:136
IO buffers.
Definition io.h:109
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:112
int off
Offset inside of ptr.
Definition io.h:115
int len
Length of the buffer.
Definition io.h:118
int capa
Designed capacity of the buffer.
Definition io.h:121
Ruby's IO, metadata and buffers.
Definition io.h:295
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:330
enum rb_io_mode mode
mode flags: FMODE_XXXs
Definition io.h:310
void(* finalize)(struct rb_io *, int)
finalize proc
Definition io.h:326
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:352
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:363
struct rb_io_encoding encs
Decomposed encoding flags.
Definition io.h:348
VALUE self
The IO's Ruby level counterpart.
Definition io.h:298
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:400
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:406
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:302
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
Definition io.h:390
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:345
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:376
int fd
file descriptor.
Definition io.h:306
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:337
int lineno
number of lines read
Definition io.h:318
struct ccan_list_head blocking_operations
Threads that are performing a blocking operation without the GVL using this IO.
Definition io.h:131
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:372
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:359
rb_pid_t pid
child's pid (for pipes)
Definition io.h:314
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
Definition io.h:383
VALUE pathv
pathname for file
Definition io.h:322
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
Definition value_type.h:307
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:433
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376