Ruby 4.0.5p0 (2026-05-20 revision 64336ffd0ee9e1f4c05891695a3d7b49cb709721)
io.c
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17#include "ruby/io/buffer.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <stddef.h>
22
23/* non-Linux poll may not work on all FDs */
24#if defined(HAVE_POLL)
25# if defined(__linux__)
26# define USE_POLL 1
27# endif
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29# define USE_POLL 1
30# endif
31#endif
32
33#ifndef USE_POLL
34# define USE_POLL 0
35#endif
36
37#undef free
38#define free(x) xfree(x)
39
40#if defined(DOSISH) || defined(__CYGWIN__)
41#include <io.h>
42#endif
43
44#include <sys/types.h>
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
49#endif
50
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
53#endif
54
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
56# define USE_SETVBUF
57#endif
58
59#ifdef __QNXNTO__
60#include <unix.h>
61#endif
62
63#include <sys/types.h>
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
65#include <sys/ioctl.h>
66#endif
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
68#include <fcntl.h>
69#elif defined(HAVE_SYS_FCNTL_H)
70#include <sys/fcntl.h>
71#endif
72
73#ifdef HAVE_SYS_TIME_H
74# include <sys/time.h>
75#endif
76
77#include <sys/stat.h>
78
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
81#endif
82
83#if !defined NOFILE
84# define NOFILE 64
85#endif
86
87#ifdef HAVE_UNISTD_H
88#include <unistd.h>
89#endif
90
91#ifdef HAVE_SYSCALL_H
92#include <syscall.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
95#endif
96
97#ifdef HAVE_SYS_UIO_H
98#include <sys/uio.h>
99#endif
100
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h> /* for WNOHANG on BSD */
103#endif
104
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
107
108# ifndef COPYFILE_STATE_COPIED
109/*
110 * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
111 * COPYFILE_STATE_COPIED. Since the only use of the former here
112 * requires the latter, we disable the former when the latter is undefined.
113 */
114# undef HAVE_FCOPYFILE
115# endif
116
117#endif
118
120#include "ccan/list/list.h"
121#include "dln.h"
122#include "encindex.h"
123#include "id.h"
124#include "internal.h"
125#include "internal/class.h"
126#include "internal/encoding.h"
127#include "internal/error.h"
128#include "internal/inits.h"
129#include "internal/io.h"
130#include "internal/numeric.h"
131#include "internal/object.h"
132#include "internal/process.h"
133#include "internal/thread.h"
134#include "internal/transcode.h"
135#include "internal/variable.h"
136#include "ruby/io.h"
137#include "ruby/io/buffer.h"
138#include "ruby/missing.h"
139#include "ruby/thread.h"
140#include "ruby/util.h"
141#include "ruby_atomic.h"
142#include "ruby/ractor.h"
143
144#if !USE_POLL
145# include "vm_core.h"
146#endif
147
148#include "builtin.h"
149
150#ifndef O_ACCMODE
151#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
152#endif
153
154#ifndef PIPE_BUF
155# ifdef _POSIX_PIPE_BUF
156# define PIPE_BUF _POSIX_PIPE_BUF
157# else
158# define PIPE_BUF 512 /* is this ok? */
159# endif
160#endif
161
162#ifndef EWOULDBLOCK
163# define EWOULDBLOCK EAGAIN
164#endif
165
166#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
167/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
168off_t __syscall(quad_t number, ...);
169#endif
170
171#define IO_RBUF_CAPA_MIN 8192
172#define IO_CBUF_CAPA_MIN (128*1024)
173#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174#define IO_WBUF_CAPA_MIN 8192
175
176#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
177
178/* define system APIs */
179#ifdef _WIN32
180#undef open
181#define open rb_w32_uopen
182#undef rename
183#define rename(f, t) rb_w32_urename((f), (t))
184#include "win32/file.h"
185#endif
186
193
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196static VALUE rb_eEWOULDBLOCKWaitReadable;
197static VALUE rb_eEWOULDBLOCKWaitWritable;
198static VALUE rb_eEINPROGRESSWaitWritable;
199static VALUE rb_eEINPROGRESSWaitReadable;
200
202static VALUE orig_stdout, orig_stderr;
203
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
776{
777 rb_raise(rb_eEOFError, "end of file reached");
778}
779
780VALUE
782{
783 rb_check_frozen(io);
784 return io;
785}
786
787void
789{
790 if (!fptr) {
791 rb_raise(rb_eIOError, "uninitialized stream");
792 }
793}
794
795void
796rb_io_check_closed(rb_io_t *fptr)
797{
799 io_fd_check_closed(fptr->fd);
800}
801
802static rb_io_t *
803rb_io_get_fptr(VALUE io)
804{
805 rb_io_t *fptr = RFILE(io)->fptr;
807 return fptr;
808}
809
810VALUE
812{
813 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
814}
815
816VALUE
818{
819 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
820}
821
822VALUE
824{
825 VALUE write_io;
826 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
827 if (write_io) {
828 return write_io;
829 }
830 return io;
831}
832
833VALUE
835{
836 VALUE write_io;
837 rb_io_t *fptr = rb_io_get_fptr(io);
838 if (!RTEST(w)) {
839 w = 0;
840 }
841 else {
842 GetWriteIO(w);
843 }
844 write_io = fptr->tied_io_for_writing;
845 fptr->tied_io_for_writing = w;
846 return write_io ? write_io : Qnil;
847}
848
849/*
850 * call-seq:
851 * timeout -> duration or nil
852 *
853 * Get the internal timeout duration or nil if it was not set.
854 *
855 */
856VALUE
858{
859 rb_io_t *fptr = rb_io_get_fptr(self);
860
861 return fptr->timeout;
862}
863
864/*
865 * call-seq:
866 * timeout = duration -> duration
867 * timeout = nil -> nil
868 *
869 * Sets the internal timeout to the specified duration or nil. The timeout
870 * applies to all blocking operations where possible.
871 *
872 * When the operation performs longer than the timeout set, IO::TimeoutError
873 * is raised.
874 *
875 * This affects the following methods (but is not limited to): #gets, #puts,
876 * #read, #write, #wait_readable and #wait_writable. This also affects
877 * blocking socket operations like Socket#accept and Socket#connect.
878 *
879 * Some operations like File#open and IO#close are not affected by the
880 * timeout. A timeout during a write operation may leave the IO in an
881 * inconsistent state, e.g. data was partially written. Generally speaking, a
882 * timeout is a last ditch effort to prevent an application from hanging on
883 * slow I/O operations, such as those that occur during a slowloris attack.
884 */
885VALUE
887{
888 // Validate it:
889 if (RTEST(timeout)) {
890 rb_time_interval(timeout);
891 }
892
893 rb_io_t *fptr = rb_io_get_fptr(self);
894
895 fptr->timeout = timeout;
896
897 return self;
898}
899
900/*
901 * call-seq:
902 * IO.try_convert(object) -> new_io or nil
903 *
904 * Attempts to convert +object+ into an \IO object via method +to_io+;
905 * returns the new \IO object if successful, or +nil+ otherwise:
906 *
907 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
908 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
909 * IO.try_convert('STDOUT') # => nil
910 *
911 */
912static VALUE
913rb_io_s_try_convert(VALUE dummy, VALUE io)
914{
915 return rb_io_check_io(io);
916}
917
918#if !RUBY_CRLF_ENVIRONMENT
919static void
920io_unread(rb_io_t *fptr, bool discard_rbuf)
921{
922 rb_off_t r;
923 rb_io_check_closed(fptr);
924 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
925 return;
926 /* xxx: target position may be negative if buffer is filled by ungetc */
927 errno = 0;
928 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
929 if (r < 0 && errno) {
930 if (errno == ESPIPE)
931 fptr->mode |= FMODE_DUPLEX;
932 if (!discard_rbuf) return;
933 }
934 fptr->rbuf.off = 0;
935 fptr->rbuf.len = 0;
936 clear_codeconv(fptr);
937 return;
938}
939#endif
940
941static rb_encoding *io_input_encoding(rb_io_t *fptr);
942
943static void
944io_ungetbyte(VALUE str, rb_io_t *fptr)
945{
946 long len = RSTRING_LEN(str);
947
948 if (fptr->rbuf.ptr == NULL) {
949 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
950 fptr->rbuf.off = 0;
951 fptr->rbuf.len = 0;
952#if SIZEOF_LONG > SIZEOF_INT
953 if (len > INT_MAX)
954 rb_raise(rb_eIOError, "ungetbyte failed");
955#endif
956 if (len > min_capa)
957 fptr->rbuf.capa = (int)len;
958 else
959 fptr->rbuf.capa = min_capa;
960 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
961 }
962 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
963 rb_raise(rb_eIOError, "ungetbyte failed");
964 }
965 if (fptr->rbuf.off < len) {
966 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
967 fptr->rbuf.ptr+fptr->rbuf.off,
968 char, fptr->rbuf.len);
969 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
970 }
971 fptr->rbuf.off-=(int)len;
972 fptr->rbuf.len+=(int)len;
973 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
974}
975
976static rb_io_t *
977flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
978{
979 if (io_fflush(fptr) < 0)
980 rb_sys_fail_on_write(fptr);
981 io_unread(fptr, discard_rbuf);
982 errno = 0;
983 return fptr;
984}
985
986#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
987#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
988
989#ifndef SEEK_CUR
990# define SEEK_SET 0
991# define SEEK_CUR 1
992# define SEEK_END 2
993#endif
994
995void
997{
998 rb_io_check_closed(fptr);
999 if (!(fptr->mode & FMODE_READABLE)) {
1000 rb_raise(rb_eIOError, "not opened for reading");
1001 }
1002 if (fptr->wbuf.len) {
1003 if (io_fflush(fptr) < 0)
1004 rb_sys_fail_on_write(fptr);
1005 }
1006 if (fptr->tied_io_for_writing) {
1007 rb_io_t *wfptr;
1008 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1009 if (io_fflush(wfptr) < 0)
1010 rb_sys_fail_on_write(wfptr);
1011 }
1012}
1013
1014void
1016{
1018 if (READ_CHAR_PENDING(fptr)) {
1019 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1020 }
1021}
1022
1023void
1025{
1027}
1028
1029static rb_encoding*
1030io_read_encoding(rb_io_t *fptr)
1031{
1032 if (fptr->encs.enc) {
1033 return fptr->encs.enc;
1034 }
1036}
1037
1038static rb_encoding*
1039io_input_encoding(rb_io_t *fptr)
1040{
1041 if (fptr->encs.enc2) {
1042 return fptr->encs.enc2;
1043 }
1044 return io_read_encoding(fptr);
1045}
1046
1047void
1049{
1050 rb_io_check_closed(fptr);
1051 if (!(fptr->mode & FMODE_WRITABLE)) {
1052 rb_raise(rb_eIOError, "not opened for writing");
1053 }
1054 if (fptr->rbuf.len) {
1055 io_unread(fptr, true);
1056 }
1057}
1058
1059int
1061{
1062 /* This function is used for bytes and chars. Confusing. */
1063 if (READ_CHAR_PENDING(fptr))
1064 return 1; /* should raise? */
1065 return READ_DATA_PENDING(fptr);
1066}
1067
1068void
1069rb_io_read_check(rb_io_t *fptr)
1070{
1071 if (!READ_DATA_PENDING(fptr)) {
1072 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1073 }
1074 return;
1075}
1076
1077int
1078rb_gc_for_fd(int err)
1079{
1080 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1081 rb_gc();
1082 return 1;
1083 }
1084 return 0;
1085}
1086
1087/* try `expr` upto twice while it returns false and `errno`
1088 * is to GC. Each `errno`s are available as `first_errno` and
1089 * `retried_errno` respectively */
1090#define TRY_WITH_GC(expr) \
1091 for (int first_errno, retried_errno = 0, retried = 0; \
1092 (!retried && \
1093 !(expr) && \
1094 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1095 (retried_errno = errno, 1)); \
1096 (void)retried_errno, retried = 1)
1097
1098static int
1099ruby_dup(int orig)
1100{
1101 int fd = -1;
1102
1103 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1104 rb_syserr_fail(first_errno, 0);
1105 }
1106 rb_update_max_fd(fd);
1107 return fd;
1108}
1109
1110static VALUE
1111io_alloc(VALUE klass)
1112{
1113 NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
1114
1115 io->fptr = 0;
1116
1117 return (VALUE)io;
1118}
1119
1120#ifndef S_ISREG
1121# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1122#endif
1123
1125 VALUE th;
1126 rb_io_t *fptr;
1127 int nonblock;
1128 int fd;
1129
1130 void *buf;
1131 size_t capa;
1132 struct timeval *timeout;
1133};
1134
1136 VALUE th;
1137 rb_io_t *fptr;
1138 int nonblock;
1139 int fd;
1140
1141 const void *buf;
1142 size_t capa;
1143 struct timeval *timeout;
1144};
1145
1146#ifdef HAVE_WRITEV
1147struct io_internal_writev_struct {
1148 VALUE th;
1149 rb_io_t *fptr;
1150 int nonblock;
1151 int fd;
1152
1153 int iovcnt;
1154 const struct iovec *iov;
1155 struct timeval *timeout;
1156};
1157#endif
1158
1159static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1160
1166static inline int
1167io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1168{
1169 if (!timeout && rb_thread_mn_schedulable(thread)) {
1170 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1171 return -1;
1172 }
1173
1174 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1175
1176 if (ready > 0) {
1177 return ready;
1178 }
1179 else if (ready == 0) {
1180 errno = ETIMEDOUT;
1181 return -1;
1182 }
1183
1184 // If there was an error BEFORE we started waiting, return it:
1185 if (error) {
1186 errno = error;
1187 return -1;
1188 }
1189 else {
1190 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1191 return ready;
1192 }
1193}
1194
1195static VALUE
1196internal_read_func(void *ptr)
1197{
1198 struct io_internal_read_struct *iis = ptr;
1199 ssize_t result;
1200
1201 if (iis->timeout && !iis->nonblock) {
1202 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1203 return -1;
1204 }
1205 }
1206
1207 retry:
1208 result = read(iis->fd, iis->buf, iis->capa);
1209
1210 if (result < 0 && !iis->nonblock) {
1211 if (io_again_p(errno)) {
1212 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1213 return -1;
1214 }
1215 else {
1216 goto retry;
1217 }
1218 }
1219 }
1220
1221 return result;
1222}
1223
1224#if defined __APPLE__
1225# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1226#else
1227# define do_write_retry(code) result = code
1228#endif
1229
1230static VALUE
1231internal_write_func(void *ptr)
1232{
1233 struct io_internal_write_struct *iis = ptr;
1234 ssize_t result;
1235
1236 if (iis->timeout && !iis->nonblock) {
1237 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1238 return -1;
1239 }
1240 }
1241
1242 retry:
1243 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1244
1245 if (result < 0 && !iis->nonblock) {
1246 int e = errno;
1247 if (io_again_p(e)) {
1248 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1249 return -1;
1250 }
1251 else {
1252 goto retry;
1253 }
1254 }
1255 }
1256
1257 return result;
1258}
1259
1260#ifdef HAVE_WRITEV
1261static VALUE
1262internal_writev_func(void *ptr)
1263{
1264 struct io_internal_writev_struct *iis = ptr;
1265 ssize_t result;
1266
1267 if (iis->timeout && !iis->nonblock) {
1268 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1269 return -1;
1270 }
1271 }
1272
1273 retry:
1274 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1275
1276 if (result < 0 && !iis->nonblock) {
1277 if (io_again_p(errno)) {
1278 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1279 return -1;
1280 }
1281 else {
1282 goto retry;
1283 }
1284 }
1285 }
1286
1287 return result;
1288}
1289#endif
1290
1291static ssize_t
1292rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1293{
1294 rb_thread_t *th = GET_THREAD();
1296 if (scheduler != Qnil) {
1297 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1298
1299 if (!UNDEF_P(result)) {
1301 }
1302 }
1303
1304 struct io_internal_read_struct iis = {
1305 .th = th->self,
1306 .fptr = fptr,
1307 .nonblock = 0,
1308 .fd = fptr->fd,
1309
1310 .buf = buf,
1311 .capa = count,
1312 .timeout = NULL,
1313 };
1314
1315 struct timeval timeout_storage;
1316
1317 if (fptr->timeout != Qnil) {
1318 timeout_storage = rb_time_interval(fptr->timeout);
1319 iis.timeout = &timeout_storage;
1320 }
1321
1322 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1323}
1324
1325static ssize_t
1326rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1327{
1328 rb_thread_t *th = GET_THREAD();
1330 if (scheduler != Qnil) {
1331 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1332
1333 if (!UNDEF_P(result)) {
1335 }
1336 }
1337
1338 struct io_internal_write_struct iis = {
1339 .th = th->self,
1340 .fptr = fptr,
1341 .nonblock = 0,
1342 .fd = fptr->fd,
1343
1344 .buf = buf,
1345 .capa = count,
1346 .timeout = NULL
1347 };
1348
1349 struct timeval timeout_storage;
1350
1351 if (fptr->timeout != Qnil) {
1352 timeout_storage = rb_time_interval(fptr->timeout);
1353 iis.timeout = &timeout_storage;
1354 }
1355
1356 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1357}
1358
1359#ifdef HAVE_WRITEV
1360static ssize_t
1361rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1362{
1363 if (!iovcnt) return 0;
1364
1365 rb_thread_t *th = GET_THREAD();
1366
1368 if (scheduler != Qnil) {
1369 // This path assumes at least one `iov`:
1370 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1371
1372 if (!UNDEF_P(result)) {
1374 }
1375 }
1376
1377 struct io_internal_writev_struct iis = {
1378 .th = th->self,
1379 .fptr = fptr,
1380 .nonblock = 0,
1381 .fd = fptr->fd,
1382
1383 .iov = iov,
1384 .iovcnt = iovcnt,
1385 .timeout = NULL
1386 };
1387
1388 struct timeval timeout_storage;
1389
1390 if (fptr->timeout != Qnil) {
1391 timeout_storage = rb_time_interval(fptr->timeout);
1392 iis.timeout = &timeout_storage;
1393 }
1394
1395 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1396}
1397#endif
1398
1399static VALUE
1400io_flush_buffer_sync(void *arg)
1401{
1402 rb_io_t *fptr = arg;
1403 long l = fptr->wbuf.len;
1404 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1405
1406 if (fptr->wbuf.len <= r) {
1407 fptr->wbuf.off = 0;
1408 fptr->wbuf.len = 0;
1409 return 0;
1410 }
1411
1412 if (0 <= r) {
1413 fptr->wbuf.off += (int)r;
1414 fptr->wbuf.len -= (int)r;
1415 errno = EAGAIN;
1416 }
1417
1418 return (VALUE)-1;
1419}
1420
1421static inline VALUE
1422io_flush_buffer_fiber_scheduler(VALUE scheduler, rb_io_t *fptr)
1423{
1424 VALUE ret = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, fptr->wbuf.ptr+fptr->wbuf.off, fptr->wbuf.len, 0);
1425 if (!UNDEF_P(ret)) {
1426 ssize_t result = rb_fiber_scheduler_io_result_apply(ret);
1427 if (result > 0) {
1428 fptr->wbuf.off += result;
1429 fptr->wbuf.len -= result;
1430 }
1431 return result >= 0 ? (VALUE)0 : (VALUE)-1;
1432 }
1433 return ret;
1434}
1435
1436static VALUE
1437io_flush_buffer_async(VALUE arg)
1438{
1439 rb_io_t *fptr = (rb_io_t *)arg;
1440
1441 VALUE scheduler = rb_fiber_scheduler_current();
1442 if (scheduler != Qnil) {
1443 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1444 if (!UNDEF_P(result)) {
1445 return result;
1446 }
1447 }
1448
1449 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1450}
1451
1452static inline int
1453io_flush_buffer(rb_io_t *fptr)
1454{
1455 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1456 return (int)io_flush_buffer_async((VALUE)fptr);
1457 }
1458 else {
1459 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1460 }
1461}
1462
1463static int
1464io_fflush(rb_io_t *fptr)
1465{
1466 rb_io_check_closed(fptr);
1467
1468 if (fptr->wbuf.len == 0)
1469 return 0;
1470
1471 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1472 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1473 return -1;
1474
1475 rb_io_check_closed(fptr);
1476 }
1477
1478 return 0;
1479}
1480
1481VALUE
1482rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1483{
1484 rb_thread_t *th = GET_THREAD();
1486
1487 if (scheduler != Qnil) {
1488 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1489 }
1490
1491 rb_io_t * fptr = NULL;
1492 RB_IO_POINTER(io, fptr);
1493
1494 struct timeval tv_storage;
1495 struct timeval *tv = NULL;
1496
1497 if (NIL_OR_UNDEF_P(timeout)) {
1498 timeout = fptr->timeout;
1499 }
1500
1501 if (timeout != Qnil) {
1502 tv_storage = rb_time_interval(timeout);
1503 tv = &tv_storage;
1504 }
1505
1506 int ready = rb_thread_io_wait(th, fptr, RB_NUM2INT(events), tv);
1507
1508 if (ready < 0) {
1509 rb_sys_fail(0);
1510 }
1511
1512 // Not sure if this is necessary:
1513 rb_io_check_closed(fptr);
1514
1515 if (ready) {
1516 return RB_INT2NUM(ready);
1517 }
1518 else {
1519 return Qfalse;
1520 }
1521}
1522
1523static VALUE
1524io_from_fd(int fd)
1525{
1526 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1527}
1528
1529static int
1530io_wait_for_single_fd(int fd, int events, struct timeval *timeout, rb_thread_t *th, VALUE scheduler)
1531{
1532 if (scheduler != Qnil) {
1533 return RTEST(
1534 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1535 );
1536 }
1537
1538 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1539}
1540
1541int
1543{
1544 io_fd_check_closed(f);
1545
1546 rb_thread_t *th = GET_THREAD();
1548
1549 switch (errno) {
1550 case EINTR:
1551#if defined(ERESTART)
1552 case ERESTART:
1553#endif
1555 return TRUE;
1556
1557 case EAGAIN:
1558#if EWOULDBLOCK != EAGAIN
1559 case EWOULDBLOCK:
1560#endif
1561 if (scheduler != Qnil) {
1562 return RTEST(
1563 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1564 );
1565 }
1566 else {
1567 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL, th, scheduler);
1568 }
1569 return TRUE;
1570
1571 default:
1572 return FALSE;
1573 }
1574}
1575
1576int
1578{
1579 io_fd_check_closed(f);
1580
1581 rb_thread_t *th = GET_THREAD();
1583
1584 switch (errno) {
1585 case EINTR:
1586#if defined(ERESTART)
1587 case ERESTART:
1588#endif
1589 /*
1590 * In old Linux, several special files under /proc and /sys don't handle
1591 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1592 * Otherwise, we face nasty hang up. Sigh.
1593 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1594 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1595 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1596 * Then rb_thread_check_ints() is enough.
1597 */
1599 return TRUE;
1600
1601 case EAGAIN:
1602#if EWOULDBLOCK != EAGAIN
1603 case EWOULDBLOCK:
1604#endif
1605 if (scheduler != Qnil) {
1606 return RTEST(
1607 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1608 );
1609 }
1610 else {
1611 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL, th, scheduler);
1612 }
1613 return TRUE;
1614
1615 default:
1616 return FALSE;
1617 }
1618}
1619
1620int
1621rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1622{
1623 rb_thread_t *th = GET_THREAD();
1625 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1626}
1627
1628int
1630{
1631 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1632}
1633
1634int
1636{
1637 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1638}
1639
1640VALUE
1641rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1642{
1643 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1644 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1645 // instead relies on `read(-1) -> -1` which causes this code path. We then
1646 // check here whether the IO was in fact closed. Probably it's better to
1647 // check that `fptr->fd != -1` before using it in syscall.
1648 rb_io_check_closed(RFILE(io)->fptr);
1649
1650 switch (error) {
1651 // In old Linux, several special files under /proc and /sys don't handle
1652 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1653 // Otherwise, we face nasty hang up. Sigh.
1654 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1655 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1656 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1657 // Then rb_thread_check_ints() is enough.
1658 case EINTR:
1659#if defined(ERESTART)
1660 case ERESTART:
1661#endif
1662 // We might have pending interrupts since the previous syscall was interrupted:
1664
1665 // The operation was interrupted, so retry it immediately:
1666 return events;
1667
1668 case EAGAIN:
1669#if EWOULDBLOCK != EAGAIN
1670 case EWOULDBLOCK:
1671#endif
1672 // The operation would block, so wait for the specified events:
1673 return rb_io_wait(io, events, timeout);
1674
1675 default:
1676 // Non-specific error, no event is ready:
1677 return Qnil;
1678 }
1679}
1680
1681int
1683{
1684 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1685
1686 if (RTEST(result)) {
1687 return RB_NUM2INT(result);
1688 }
1689 else if (result == RUBY_Qfalse) {
1690 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1691 }
1692
1693 return 0;
1694}
1695
1696int
1698{
1699 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1700
1701 if (RTEST(result)) {
1702 return RB_NUM2INT(result);
1703 }
1704 else if (result == RUBY_Qfalse) {
1705 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1706 }
1707
1708 return 0;
1709}
1710
1711static void
1712make_writeconv(rb_io_t *fptr)
1713{
1714 if (!fptr->writeconv_initialized) {
1715 const char *senc, *denc;
1716 rb_encoding *enc;
1717 int ecflags;
1718 VALUE ecopts;
1719
1720 fptr->writeconv_initialized = 1;
1721
1723 ecopts = fptr->encs.ecopts;
1724
1725 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1726 /* no encoding conversion */
1727 fptr->writeconv_pre_ecflags = 0;
1728 fptr->writeconv_pre_ecopts = Qnil;
1729 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1730 if (!fptr->writeconv)
1731 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1733 }
1734 else {
1735 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1736 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1737 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1738 /* single conversion */
1739 fptr->writeconv_pre_ecflags = ecflags;
1740 fptr->writeconv_pre_ecopts = ecopts;
1741 fptr->writeconv = NULL;
1743 }
1744 else {
1745 /* double conversion */
1747 fptr->writeconv_pre_ecopts = ecopts;
1748 if (senc) {
1749 denc = rb_enc_name(enc);
1750 fptr->writeconv_asciicompat = rb_str_new2(senc);
1751 }
1752 else {
1753 senc = denc = "";
1754 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1755 }
1757 ecopts = fptr->encs.ecopts;
1758 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1759 if (!fptr->writeconv)
1760 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1761 }
1762 }
1763 }
1764}
1765
1766/* writing functions */
1768 rb_io_t *fptr;
1769 const char *ptr;
1770 long length;
1771};
1772
1774 VALUE io;
1775 VALUE str;
1776 int nosync;
1777};
1778
1779#ifdef HAVE_WRITEV
1780static ssize_t
1781io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1782{
1783 if (fptr->wbuf.len) {
1784 struct iovec iov[2];
1785
1786 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1787 iov[0].iov_len = fptr->wbuf.len;
1788 iov[1].iov_base = (void*)ptr;
1789 iov[1].iov_len = length;
1790
1791 ssize_t result = rb_writev_internal(fptr, iov, 2);
1792
1793 if (result < 0)
1794 return result;
1795
1796 if (result >= fptr->wbuf.len) {
1797 // We wrote more than the internal buffer:
1798 result -= fptr->wbuf.len;
1799 fptr->wbuf.off = 0;
1800 fptr->wbuf.len = 0;
1801 }
1802 else {
1803 // We only wrote less data than the internal buffer:
1804 fptr->wbuf.off += (int)result;
1805 fptr->wbuf.len -= (int)result;
1806
1807 result = 0;
1808 }
1809
1810 return result;
1811 }
1812 else {
1813 return rb_io_write_memory(fptr, ptr, length);
1814 }
1815}
1816#else
1817static ssize_t
1818io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1819{
1820 long remaining = length;
1821
1822 if (fptr->wbuf.len) {
1823 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1824 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1825 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1826 fptr->wbuf.off = 0;
1827 }
1828
1829 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1830 fptr->wbuf.len += (int)length;
1831
1832 // We copied the entire incoming data to the internal buffer:
1833 remaining = 0;
1834 }
1835
1836 // Flush the internal buffer:
1837 if (io_fflush(fptr) < 0) {
1838 return -1;
1839 }
1840
1841 // If all the data was buffered, we are done:
1842 if (remaining == 0) {
1843 return length;
1844 }
1845 }
1846
1847 // Otherwise, we should write the data directly:
1848 return rb_io_write_memory(fptr, ptr, length);
1849}
1850#endif
1851
1852static VALUE
1853io_binwrite_string(VALUE arg)
1854{
1855 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1856
1857 const char *ptr = p->ptr;
1858 size_t remaining = p->length;
1859
1860 while (remaining) {
1861 // Write as much as possible:
1862 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1863
1864 if (result == 0) {
1865 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1866 // should try again immediately.
1867 }
1868 else if (result > 0) {
1869 if ((size_t)result == remaining) break;
1870 ptr += result;
1871 remaining -= result;
1872 }
1873 // Wait for it to become writable:
1874 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1875 rb_io_check_closed(p->fptr);
1876 }
1877 else {
1878 // The error was unrelated to waiting for it to become writable, so we fail:
1879 return -1;
1880 }
1881 }
1882
1883 return p->length;
1884}
1885
1886inline static void
1887io_allocate_write_buffer(rb_io_t *fptr, int sync)
1888{
1889 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1890 fptr->wbuf.off = 0;
1891 fptr->wbuf.len = 0;
1892 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1893 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1894 }
1895
1896 if (NIL_P(fptr->write_lock)) {
1897 fptr->write_lock = rb_mutex_new();
1898 rb_mutex_allow_trap(fptr->write_lock, 1);
1899 }
1900}
1901
1902static inline int
1903io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1904{
1905 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1906 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1907 return 1;
1908
1909 // If the amount of data we want to write exceeds the internal buffer:
1910 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1911 return 1;
1912
1913 // Otherwise, we can append to the internal buffer:
1914 return 0;
1915}
1916
1917static long
1918io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1919{
1920 if (len <= 0) return len;
1921
1922 // Don't write anything if current thread has a pending interrupt:
1924
1925 io_allocate_write_buffer(fptr, !nosync);
1926
1927 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1928 struct binwrite_arg arg;
1929
1930 arg.fptr = fptr;
1931 arg.ptr = ptr;
1932 arg.length = len;
1933
1934 if (!NIL_P(fptr->write_lock)) {
1935 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1936 }
1937 else {
1938 return io_binwrite_string((VALUE)&arg);
1939 }
1940 }
1941 else {
1942 if (fptr->wbuf.off) {
1943 if (fptr->wbuf.len)
1944 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1945 fptr->wbuf.off = 0;
1946 }
1947
1948 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1949 fptr->wbuf.len += (int)len;
1950
1951 return len;
1952 }
1953}
1954
1955# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1956 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1957
1958#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1959 MODE_BTMODE(d, e, f) : \
1960 MODE_BTMODE(a, b, c))
1961
1962static VALUE
1963do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1964{
1965 if (NEED_WRITECONV(fptr)) {
1966 VALUE common_encoding = Qnil;
1967 SET_BINARY_MODE(fptr);
1968
1969 make_writeconv(fptr);
1970
1971 if (fptr->writeconv) {
1972#define fmode (fptr->mode)
1973 if (!NIL_P(fptr->writeconv_asciicompat))
1974 common_encoding = fptr->writeconv_asciicompat;
1975 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1976 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1977 rb_enc_name(rb_enc_get(str)));
1978 }
1979#undef fmode
1980 }
1981 else {
1982 if (fptr->encs.enc2)
1983 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1984 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1985 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1986 }
1987
1988 if (!NIL_P(common_encoding)) {
1989 str = rb_str_encode(str, common_encoding,
1991 *converted = 1;
1992 }
1993
1994 if (fptr->writeconv) {
1996 *converted = 1;
1997 }
1998 }
1999#if RUBY_CRLF_ENVIRONMENT
2000#define fmode (fptr->mode)
2001 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2002 if ((fptr->mode & FMODE_READABLE) &&
2004 setmode(fptr->fd, O_BINARY);
2005 }
2006 else {
2007 setmode(fptr->fd, O_TEXT);
2008 }
2009 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2010 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2011 rb_enc_name(rb_enc_get(str)));
2012 }
2013 }
2014#undef fmode
2015#endif
2016 return str;
2017}
2018
2019static long
2020io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
2021{
2022 int converted = 0;
2023 VALUE tmp;
2024 long n, len;
2025 const char *ptr;
2026
2027#ifdef _WIN32
2028 if (fptr->mode & FMODE_TTY) {
2029 long len = rb_w32_write_console(str, fptr->fd);
2030 if (len > 0) return len;
2031 }
2032#endif
2033
2034 str = do_writeconv(str, fptr, &converted);
2035 if (converted)
2036 OBJ_FREEZE(str);
2037
2038 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2039 RSTRING_GETMEM(tmp, ptr, len);
2040 n = io_binwrite(ptr, len, fptr, nosync);
2041 rb_str_tmp_frozen_release(str, tmp);
2042
2043 return n;
2044}
2045
2046ssize_t
2047rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2048{
2049 rb_io_t *fptr;
2050
2051 GetOpenFile(io, fptr);
2053 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2054}
2055
2056static VALUE
2057io_write(VALUE io, VALUE str, int nosync)
2058{
2059 rb_io_t *fptr;
2060 long n;
2061 VALUE tmp;
2062
2063 io = GetWriteIO(io);
2064 str = rb_obj_as_string(str);
2065 tmp = rb_io_check_io(io);
2066
2067 if (NIL_P(tmp)) {
2068 /* port is not IO, call write method for it. */
2069 return rb_funcall(io, id_write, 1, str);
2070 }
2071
2072 io = tmp;
2073 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2074
2075 GetOpenFile(io, fptr);
2077
2078 n = io_fwrite(str, fptr, nosync);
2079 if (n < 0L) rb_sys_fail_on_write(fptr);
2080
2081 return LONG2FIX(n);
2082}
2083
2084#ifdef HAVE_WRITEV
2085struct binwritev_arg {
2086 rb_io_t *fptr;
2087 struct iovec *iov;
2088 int iovcnt;
2089 size_t total;
2090};
2091
2092static VALUE
2093io_binwritev_internal(VALUE arg)
2094{
2095 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2096
2097 size_t remaining = p->total;
2098 size_t offset = 0;
2099
2100 rb_io_t *fptr = p->fptr;
2101 struct iovec *iov = p->iov;
2102 int iovcnt = p->iovcnt;
2103
2104 while (remaining) {
2105 long result = rb_writev_internal(fptr, iov, iovcnt);
2106
2107 if (result >= 0) {
2108 offset += result;
2109 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2110 if (offset < (size_t)fptr->wbuf.len) {
2111 fptr->wbuf.off += result;
2112 fptr->wbuf.len -= result;
2113 }
2114 else {
2115 offset -= (size_t)fptr->wbuf.len;
2116 fptr->wbuf.off = 0;
2117 fptr->wbuf.len = 0;
2118 }
2119 }
2120
2121 if (offset == p->total) {
2122 return p->total;
2123 }
2124
2125 while (result >= (ssize_t)iov->iov_len) {
2126 /* iovcnt > 0 */
2127 result -= iov->iov_len;
2128 iov->iov_len = 0;
2129 iov++;
2130
2131 if (!--iovcnt) {
2132 // I don't believe this code path can ever occur.
2133 return offset;
2134 }
2135 }
2136
2137 iov->iov_base = (char *)iov->iov_base + result;
2138 iov->iov_len -= result;
2139 }
2140 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2141 rb_io_check_closed(fptr);
2142 }
2143 else {
2144 return -1;
2145 }
2146 }
2147
2148 return offset;
2149}
2150
2151static long
2152io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2153{
2154 // Don't write anything if current thread has a pending interrupt:
2156
2157 if (iovcnt == 0) return 0;
2158
2159 size_t total = 0;
2160 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2161
2162 io_allocate_write_buffer(fptr, 1);
2163
2164 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2165 // The end of the buffered data:
2166 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2167
2168 if (offset + total <= (size_t)fptr->wbuf.capa) {
2169 for (int i = 1; i < iovcnt; i++) {
2170 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2171 offset += iov[i].iov_len;
2172 }
2173
2174 fptr->wbuf.len += total;
2175
2176 return total;
2177 }
2178 else {
2179 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2180 iov[0].iov_len = fptr->wbuf.len;
2181 }
2182 }
2183 else {
2184 // The first iov is reserved for the internal buffer, and it's empty.
2185 iov++;
2186
2187 if (!--iovcnt) {
2188 // If there are no other io vectors we are done.
2189 return 0;
2190 }
2191 }
2192
2193 struct binwritev_arg arg;
2194 arg.fptr = fptr;
2195 arg.iov = iov;
2196 arg.iovcnt = iovcnt;
2197 arg.total = total;
2198
2199 if (!NIL_P(fptr->write_lock)) {
2200 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2201 }
2202 else {
2203 return io_binwritev_internal((VALUE)&arg);
2204 }
2205}
2206
2207static long
2208io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2209{
2210 int i, converted, iovcnt = argc + 1;
2211 long n;
2212 VALUE v1, v2, str, tmp, *tmp_array;
2213 struct iovec *iov;
2214
2215 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2216 tmp_array = ALLOCV_N(VALUE, v2, argc);
2217
2218 for (i = 0; i < argc; i++) {
2219 str = rb_obj_as_string(argv[i]);
2220 converted = 0;
2221 str = do_writeconv(str, fptr, &converted);
2222
2223 if (converted)
2224 OBJ_FREEZE(str);
2225
2226 tmp = rb_str_tmp_frozen_acquire(str);
2227 tmp_array[i] = tmp;
2228
2229 /* iov[0] is reserved for buffer of fptr */
2230 iov[i+1].iov_base = RSTRING_PTR(tmp);
2231 iov[i+1].iov_len = RSTRING_LEN(tmp);
2232 }
2233
2234 n = io_binwritev(iov, iovcnt, fptr);
2235 if (v1) ALLOCV_END(v1);
2236
2237 for (i = 0; i < argc; i++) {
2238 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2239 }
2240
2241 if (v2) ALLOCV_END(v2);
2242
2243 return n;
2244}
2245
2246static int
2247iovcnt_ok(int iovcnt)
2248{
2249#ifdef IOV_MAX
2250 return iovcnt < IOV_MAX;
2251#else /* GNU/Hurd has writev, but no IOV_MAX */
2252 return 1;
2253#endif
2254}
2255#endif /* HAVE_WRITEV */
2256
2257static VALUE
2258io_writev(int argc, const VALUE *argv, VALUE io)
2259{
2260 rb_io_t *fptr;
2261 long n;
2262 VALUE tmp, total = INT2FIX(0);
2263 int i, cnt = 1;
2264
2265 io = GetWriteIO(io);
2266 tmp = rb_io_check_io(io);
2267
2268 if (NIL_P(tmp)) {
2269 /* port is not IO, call write method for it. */
2270 return rb_funcallv(io, id_write, argc, argv);
2271 }
2272
2273 io = tmp;
2274
2275 GetOpenFile(io, fptr);
2277
2278 for (i = 0; i < argc; i += cnt) {
2279#ifdef HAVE_WRITEV
2280 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2281 n = io_fwritev(cnt, &argv[i], fptr);
2282 }
2283 else
2284#endif
2285 {
2286 cnt = 1;
2287 /* sync at last item */
2288 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2289 }
2290
2291 if (n < 0L)
2292 rb_sys_fail_on_write(fptr);
2293
2294 total = rb_fix_plus(LONG2FIX(n), total);
2295 }
2296
2297 return total;
2298}
2299
2300/*
2301 * call-seq:
2302 * write(*objects) -> integer
2303 *
2304 * Writes each of the given +objects+ to +self+,
2305 * which must be opened for writing
2306 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2307 * returns the total number bytes written;
2308 * each of +objects+ that is not a string is converted via method +to_s+:
2309 *
2310 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2311 * $stdout.write('foo', :bar, 2, "\n") # => 8
2312 *
2313 * Output:
2314 *
2315 * Hello, World!
2316 * foobar2
2317 *
2318 * Related: IO#read.
2319 */
2320
2321static VALUE
2322io_write_m(int argc, VALUE *argv, VALUE io)
2323{
2324 if (argc != 1) {
2325 return io_writev(argc, argv, io);
2326 }
2327 else {
2328 VALUE str = argv[0];
2329 return io_write(io, str, 0);
2330 }
2331}
2332
2333VALUE
2334rb_io_write(VALUE io, VALUE str)
2335{
2336 return rb_funcallv(io, id_write, 1, &str);
2337}
2338
2339static VALUE
2340rb_io_writev(VALUE io, int argc, const VALUE *argv)
2341{
2342 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2343 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2344 VALUE klass = CLASS_OF(io);
2345 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2347 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2348 " which accepts just one argument",
2349 klass, sep
2350 );
2351 }
2352
2353 do rb_io_write(io, *argv++); while (--argc);
2354
2355 return Qnil;
2356 }
2357
2358 return rb_funcallv(io, id_write, argc, argv);
2359}
2360
2361/*
2362 * call-seq:
2363 * self << object -> self
2364 *
2365 * Writes the given +object+ to +self+,
2366 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2367 * returns +self+;
2368 * if +object+ is not a string, it is converted via method +to_s+:
2369 *
2370 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2371 * $stdout << 'foo' << :bar << 2 << "\n"
2372 *
2373 * Output:
2374 *
2375 * Hello, World!
2376 * foobar2
2377 *
2378 */
2379
2380
2381VALUE
2383{
2384 rb_io_write(io, str);
2385 return io;
2386}
2387
2388#ifdef HAVE_FSYNC
2389static VALUE
2390nogvl_fsync(void *ptr)
2391{
2392 rb_io_t *fptr = ptr;
2393
2394#ifdef _WIN32
2395 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2396 return 0;
2397#endif
2398 return (VALUE)fsync(fptr->fd);
2399}
2400#endif
2401
2402VALUE
2403rb_io_flush_raw(VALUE io, int sync)
2404{
2405 rb_io_t *fptr;
2406
2407 if (!RB_TYPE_P(io, T_FILE)) {
2408 return rb_funcall(io, id_flush, 0);
2409 }
2410
2411 io = GetWriteIO(io);
2412 GetOpenFile(io, fptr);
2413
2414 if (fptr->mode & FMODE_WRITABLE) {
2415 if (io_fflush(fptr) < 0)
2416 rb_sys_fail_on_write(fptr);
2417 }
2418 if (fptr->mode & FMODE_READABLE) {
2419 io_unread(fptr, true);
2420 }
2421
2422 return io;
2423}
2424
2425/*
2426 * call-seq:
2427 * flush -> self
2428 *
2429 * Flushes data buffered in +self+ to the operating system
2430 * (but does not necessarily flush data buffered in the operating system):
2431 *
2432 * $stdout.print 'no newline' # Not necessarily flushed.
2433 * $stdout.flush # Flushed.
2434 *
2435 */
2436
2437VALUE
2438rb_io_flush(VALUE io)
2439{
2440 return rb_io_flush_raw(io, 1);
2441}
2442
2443/*
2444 * call-seq:
2445 * tell -> integer
2446 *
2447 * Returns the current position (in bytes) in +self+
2448 * (see {Position}[rdoc-ref:IO@Position]):
2449 *
2450 * f = File.open('t.txt')
2451 * f.tell # => 0
2452 * f.gets # => "First line\n"
2453 * f.tell # => 12
2454 * f.close
2455 *
2456 * Related: IO#pos=, IO#seek.
2457 */
2458
2459static VALUE
2460rb_io_tell(VALUE io)
2461{
2462 rb_io_t *fptr;
2463 rb_off_t pos;
2464
2465 GetOpenFile(io, fptr);
2466 pos = io_tell(fptr);
2467 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2468 pos -= fptr->rbuf.len;
2469 return OFFT2NUM(pos);
2470}
2471
2472static VALUE
2473rb_io_seek(VALUE io, VALUE offset, int whence)
2474{
2475 rb_io_t *fptr;
2476 rb_off_t pos;
2477
2478 pos = NUM2OFFT(offset);
2479 GetOpenFile(io, fptr);
2480 pos = io_seek(fptr, pos, whence);
2481 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2482
2483 return INT2FIX(0);
2484}
2485
2486static int
2487interpret_seek_whence(VALUE vwhence)
2488{
2489 if (vwhence == sym_SET)
2490 return SEEK_SET;
2491 if (vwhence == sym_CUR)
2492 return SEEK_CUR;
2493 if (vwhence == sym_END)
2494 return SEEK_END;
2495#ifdef SEEK_DATA
2496 if (vwhence == sym_DATA)
2497 return SEEK_DATA;
2498#endif
2499#ifdef SEEK_HOLE
2500 if (vwhence == sym_HOLE)
2501 return SEEK_HOLE;
2502#endif
2503 return NUM2INT(vwhence);
2504}
2505
2506/*
2507 * call-seq:
2508 * seek(offset, whence = IO::SEEK_SET) -> 0
2509 *
2510 * Seeks to the position given by integer +offset+
2511 * (see {Position}[rdoc-ref:IO@Position])
2512 * and constant +whence+, which is one of:
2513 *
2514 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2515 * Repositions the stream to its current position plus the given +offset+:
2516 *
2517 * f = File.open('t.txt')
2518 * f.tell # => 0
2519 * f.seek(20, :CUR) # => 0
2520 * f.tell # => 20
2521 * f.seek(-10, :CUR) # => 0
2522 * f.tell # => 10
2523 * f.close
2524 *
2525 * - +:END+ or <tt>IO::SEEK_END</tt>:
2526 * Repositions the stream to its end plus the given +offset+:
2527 *
2528 * f = File.open('t.txt')
2529 * f.tell # => 0
2530 * f.seek(0, :END) # => 0 # Repositions to stream end.
2531 * f.tell # => 52
2532 * f.seek(-20, :END) # => 0
2533 * f.tell # => 32
2534 * f.seek(-40, :END) # => 0
2535 * f.tell # => 12
2536 * f.close
2537 *
2538 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2539 * Repositions the stream to the given +offset+:
2540 *
2541 * f = File.open('t.txt')
2542 * f.tell # => 0
2543 * f.seek(20, :SET) # => 0
2544 * f.tell # => 20
2545 * f.seek(40, :SET) # => 0
2546 * f.tell # => 40
2547 * f.close
2548 *
2549 * Related: IO#pos=, IO#tell.
2550 *
2551 */
2552
2553static VALUE
2554rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2555{
2556 VALUE offset, ptrname;
2557 int whence = SEEK_SET;
2558
2559 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2560 whence = interpret_seek_whence(ptrname);
2561 }
2562
2563 return rb_io_seek(io, offset, whence);
2564}
2565
2566/*
2567 * call-seq:
2568 * pos = new_position -> new_position
2569 *
2570 * Seeks to the given +new_position+ (in bytes);
2571 * see {Position}[rdoc-ref:IO@Position]:
2572 *
2573 * f = File.open('t.txt')
2574 * f.tell # => 0
2575 * f.pos = 20 # => 20
2576 * f.tell # => 20
2577 * f.close
2578 *
2579 * Related: IO#seek, IO#tell.
2580 *
2581 */
2582
2583static VALUE
2584rb_io_set_pos(VALUE io, VALUE offset)
2585{
2586 rb_io_t *fptr;
2587 rb_off_t pos;
2588
2589 pos = NUM2OFFT(offset);
2590 GetOpenFile(io, fptr);
2591 pos = io_seek(fptr, pos, SEEK_SET);
2592 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2593
2594 return OFFT2NUM(pos);
2595}
2596
2597static void clear_readconv(rb_io_t *fptr);
2598
2599/*
2600 * call-seq:
2601 * rewind -> 0
2602 *
2603 * Repositions the stream to its beginning,
2604 * setting both the position and the line number to zero;
2605 * see {Position}[rdoc-ref:IO@Position]
2606 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2607 *
2608 * f = File.open('t.txt')
2609 * f.tell # => 0
2610 * f.lineno # => 0
2611 * f.gets # => "First line\n"
2612 * f.tell # => 12
2613 * f.lineno # => 1
2614 * f.rewind # => 0
2615 * f.tell # => 0
2616 * f.lineno # => 0
2617 * f.close
2618 *
2619 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2620 *
2621 */
2622
2623static VALUE
2624rb_io_rewind(VALUE io)
2625{
2626 rb_io_t *fptr;
2627
2628 GetOpenFile(io, fptr);
2629 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2630 if (io == ARGF.current_file) {
2631 ARGF.lineno -= fptr->lineno;
2632 }
2633 fptr->lineno = 0;
2634 if (fptr->readconv) {
2635 clear_readconv(fptr);
2636 }
2637
2638 return INT2FIX(0);
2639}
2640
2641static int
2642fptr_wait_readable(rb_io_t *fptr)
2643{
2644 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2645
2646 if (result)
2647 rb_io_check_closed(fptr);
2648
2649 return result;
2650}
2651
2652static int
2653io_fillbuf(rb_io_t *fptr)
2654{
2655 ssize_t r;
2656
2657 if (fptr->rbuf.ptr == NULL) {
2658 fptr->rbuf.off = 0;
2659 fptr->rbuf.len = 0;
2660 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2661 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2662 }
2663 if (fptr->rbuf.len == 0) {
2664 retry:
2665 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2666
2667 if (r < 0) {
2668 if (fptr_wait_readable(fptr))
2669 goto retry;
2670
2671 int e = errno;
2672 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2673 if (!NIL_P(fptr->pathv)) {
2674 rb_str_append(path, fptr->pathv);
2675 }
2676
2677 rb_syserr_fail_path(e, path);
2678 }
2679 if (r > 0) rb_io_check_closed(fptr);
2680 fptr->rbuf.off = 0;
2681 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2682 if (r == 0)
2683 return -1; /* EOF */
2684 }
2685 return 0;
2686}
2687
2688/*
2689 * call-seq:
2690 * eof -> true or false
2691 *
2692 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2693 * see {Position}[rdoc-ref:IO@Position]:
2694 *
2695 * f = File.open('t.txt')
2696 * f.eof # => false
2697 * f.seek(0, :END) # => 0
2698 * f.eof # => true
2699 * f.close
2700 *
2701 * Raises an exception unless the stream is opened for reading;
2702 * see {Mode}[rdoc-ref:File@Access+Modes].
2703 *
2704 * If +self+ is a stream such as pipe or socket, this method
2705 * blocks until the other end sends some data or closes it:
2706 *
2707 * r, w = IO.pipe
2708 * Thread.new { sleep 1; w.close }
2709 * r.eof? # => true # After 1-second wait.
2710 *
2711 * r, w = IO.pipe
2712 * Thread.new { sleep 1; w.puts "a" }
2713 * r.eof? # => false # After 1-second wait.
2714 *
2715 * r, w = IO.pipe
2716 * r.eof? # blocks forever
2717 *
2718 * Note that this method reads data to the input byte buffer. So
2719 * IO#sysread may not behave as you intend with IO#eof?, unless you
2720 * call IO#rewind first (which is not available for some streams).
2721 */
2722
2723VALUE
2725{
2726 rb_io_t *fptr;
2727
2728 GetOpenFile(io, fptr);
2730
2731 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2732 if (READ_DATA_PENDING(fptr)) return Qfalse;
2733 READ_CHECK(fptr);
2734#if RUBY_CRLF_ENVIRONMENT
2735 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2736 return RBOOL(eof(fptr->fd));
2737 }
2738#endif
2739 return RBOOL(io_fillbuf(fptr) < 0);
2740}
2741
2742/*
2743 * call-seq:
2744 * sync -> true or false
2745 *
2746 * Returns the current sync mode of the stream.
2747 * When sync mode is true, all output is immediately flushed to the underlying
2748 * operating system and is not buffered by Ruby internally. See also #fsync.
2749 *
2750 * f = File.open('t.tmp', 'w')
2751 * f.sync # => false
2752 * f.sync = true
2753 * f.sync # => true
2754 * f.close
2755 *
2756 */
2757
2758static VALUE
2759rb_io_sync(VALUE io)
2760{
2761 rb_io_t *fptr;
2762
2763 io = GetWriteIO(io);
2764 GetOpenFile(io, fptr);
2765 return RBOOL(fptr->mode & FMODE_SYNC);
2766}
2767
2768#ifdef HAVE_FSYNC
2769
2770/*
2771 * call-seq:
2772 * sync = boolean -> boolean
2773 *
2774 * Sets the _sync_ _mode_ for the stream to the given value;
2775 * returns the given value.
2776 *
2777 * Values for the sync mode:
2778 *
2779 * - +true+: All output is immediately flushed to the
2780 * underlying operating system and is not buffered internally.
2781 * - +false+: Output may be buffered internally.
2782 *
2783 * Example;
2784 *
2785 * f = File.open('t.tmp', 'w')
2786 * f.sync # => false
2787 * f.sync = true
2788 * f.sync # => true
2789 * f.close
2790 *
2791 * Related: IO#fsync.
2792 *
2793 */
2794
2795static VALUE
2796rb_io_set_sync(VALUE io, VALUE sync)
2797{
2798 rb_io_t *fptr;
2799
2800 io = GetWriteIO(io);
2801 GetOpenFile(io, fptr);
2802 if (RTEST(sync)) {
2803 fptr->mode |= FMODE_SYNC;
2804 }
2805 else {
2806 fptr->mode &= ~FMODE_SYNC;
2807 }
2808 return sync;
2809}
2810
2811/*
2812 * call-seq:
2813 * fsync -> 0
2814 *
2815 * Immediately writes to disk all data buffered in the stream,
2816 * via the operating system's <tt>fsync(2)</tt>.
2817
2818 * Note this difference:
2819 *
2820 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2821 * but does not guarantee that the operating system actually writes the data to disk.
2822 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2823 * and that data is written to disk.
2824 *
2825 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2826 *
2827 */
2828
2829static VALUE
2830rb_io_fsync(VALUE io)
2831{
2832 rb_io_t *fptr;
2833
2834 io = GetWriteIO(io);
2835 GetOpenFile(io, fptr);
2836
2837 if (io_fflush(fptr) < 0)
2838 rb_sys_fail_on_write(fptr);
2839
2840 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2841 rb_sys_fail_path(fptr->pathv);
2842
2843 return INT2FIX(0);
2844}
2845#else
2846# define rb_io_fsync rb_f_notimplement
2847# define rb_io_sync rb_f_notimplement
2848static VALUE
2849rb_io_set_sync(VALUE io, VALUE sync)
2850{
2853}
2854#endif
2855
2856#ifdef HAVE_FDATASYNC
2857static VALUE
2858nogvl_fdatasync(void *ptr)
2859{
2860 rb_io_t *fptr = ptr;
2861
2862#ifdef _WIN32
2863 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2864 return 0;
2865#endif
2866 return (VALUE)fdatasync(fptr->fd);
2867}
2868
2869/*
2870 * call-seq:
2871 * fdatasync -> 0
2872 *
2873 * Immediately writes to disk all data buffered in the stream,
2874 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2875 * otherwise via <tt>fsync(2)</tt>, if supported;
2876 * otherwise raises an exception.
2877 *
2878 */
2879
2880static VALUE
2881rb_io_fdatasync(VALUE io)
2882{
2883 rb_io_t *fptr;
2884
2885 io = GetWriteIO(io);
2886 GetOpenFile(io, fptr);
2887
2888 if (io_fflush(fptr) < 0)
2889 rb_sys_fail_on_write(fptr);
2890
2891 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2892 return INT2FIX(0);
2893
2894 /* fall back */
2895 return rb_io_fsync(io);
2896}
2897#else
2898#define rb_io_fdatasync rb_io_fsync
2899#endif
2900
2901/*
2902 * call-seq:
2903 * fileno -> integer
2904 *
2905 * Returns the integer file descriptor for the stream:
2906 *
2907 * $stdin.fileno # => 0
2908 * $stdout.fileno # => 1
2909 * $stderr.fileno # => 2
2910 * File.open('t.txt').fileno # => 10
2911 * f.close
2912 *
2913 */
2914
2915static VALUE
2916rb_io_fileno(VALUE io)
2917{
2918 rb_io_t *fptr = RFILE(io)->fptr;
2919 int fd;
2920
2921 rb_io_check_closed(fptr);
2922 fd = fptr->fd;
2923 return INT2FIX(fd);
2924}
2925
2926int
2928{
2929 if (RB_TYPE_P(io, T_FILE)) {
2930 rb_io_t *fptr = RFILE(io)->fptr;
2931 rb_io_check_closed(fptr);
2932 return fptr->fd;
2933 }
2934 else {
2935 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2936 if (!UNDEF_P(fileno)) {
2937 return RB_NUM2INT(fileno);
2938 }
2939 }
2940
2941 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2942
2944}
2945
2946int
2947rb_io_mode(VALUE io)
2948{
2949 rb_io_t *fptr;
2950 GetOpenFile(io, fptr);
2951 return fptr->mode;
2952}
2953
2954/*
2955 * call-seq:
2956 * pid -> integer or nil
2957 *
2958 * Returns the process ID of a child process associated with the stream,
2959 * which will have been set by IO#popen, or +nil+ if the stream was not
2960 * created by IO#popen:
2961 *
2962 * pipe = IO.popen("-")
2963 * if pipe
2964 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2965 * else
2966 * $stderr.puts "In child, pid is #{$$}"
2967 * end
2968 *
2969 * Output:
2970 *
2971 * In child, pid is 26209
2972 * In parent, child pid is 26209
2973 *
2974 */
2975
2976static VALUE
2977rb_io_pid(VALUE io)
2978{
2979 rb_io_t *fptr;
2980
2981 GetOpenFile(io, fptr);
2982 if (!fptr->pid)
2983 return Qnil;
2984 return PIDT2NUM(fptr->pid);
2985}
2986
2987/*
2988 * call-seq:
2989 * path -> string or nil
2990 *
2991 * Returns the path associated with the IO, or +nil+ if there is no path
2992 * associated with the IO. It is not guaranteed that the path exists on
2993 * the filesystem.
2994 *
2995 * $stdin.path # => "<STDIN>"
2996 *
2997 * File.open("testfile") {|f| f.path} # => "testfile"
2998 */
2999
3000VALUE
3002{
3003 rb_io_t *fptr = RFILE(io)->fptr;
3004
3005 if (!fptr)
3006 return Qnil;
3007
3008 return rb_obj_dup(fptr->pathv);
3009}
3010
3011/*
3012 * call-seq:
3013 * inspect -> string
3014 *
3015 * Returns a string representation of +self+:
3016 *
3017 * f = File.open('t.txt')
3018 * f.inspect # => "#<File:t.txt>"
3019 * f.close
3020 *
3021 */
3022
3023static VALUE
3024rb_io_inspect(VALUE obj)
3025{
3026 rb_io_t *fptr;
3027 VALUE result;
3028 static const char closed[] = " (closed)";
3029
3030 fptr = RFILE(obj)->fptr;
3031 if (!fptr) return rb_any_to_s(obj);
3032 result = rb_str_new_cstr("#<");
3033 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3034 rb_str_cat2(result, ":");
3035 if (NIL_P(fptr->pathv)) {
3036 if (fptr->fd < 0) {
3037 rb_str_cat(result, closed+1, strlen(closed)-1);
3038 }
3039 else {
3040 rb_str_catf(result, "fd %d", fptr->fd);
3041 }
3042 }
3043 else {
3044 rb_str_append(result, fptr->pathv);
3045 if (fptr->fd < 0) {
3046 rb_str_cat(result, closed, strlen(closed));
3047 }
3048 }
3049 return rb_str_cat2(result, ">");
3050}
3051
3052/*
3053 * call-seq:
3054 * to_io -> self
3055 *
3056 * Returns +self+.
3057 *
3058 */
3059
3060static VALUE
3061rb_io_to_io(VALUE io)
3062{
3063 return io;
3064}
3065
3066/* reading functions */
3067static long
3068read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3069{
3070 int n;
3071
3072 n = READ_DATA_PENDING_COUNT(fptr);
3073 if (n <= 0) return 0;
3074 if (n > len) n = (int)len;
3075 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3076 fptr->rbuf.off += n;
3077 fptr->rbuf.len -= n;
3078 return n;
3079}
3080
3081static long
3082io_bufread(char *ptr, long len, rb_io_t *fptr)
3083{
3084 long offset = 0;
3085 long n = len;
3086 long c;
3087
3088 if (READ_DATA_PENDING(fptr) == 0) {
3089 while (n > 0) {
3090 again:
3091 rb_io_check_closed(fptr);
3092 c = rb_io_read_memory(fptr, ptr+offset, n);
3093 if (c == 0) break;
3094 if (c < 0) {
3095 if (fptr_wait_readable(fptr))
3096 goto again;
3097 return -1;
3098 }
3099 offset += c;
3100 if ((n -= c) <= 0) break;
3101 }
3102 return len - n;
3103 }
3104
3105 while (n > 0) {
3106 c = read_buffered_data(ptr+offset, n, fptr);
3107 if (c > 0) {
3108 offset += c;
3109 if ((n -= c) <= 0) break;
3110 }
3111 rb_io_check_closed(fptr);
3112 if (io_fillbuf(fptr) < 0) {
3113 break;
3114 }
3115 }
3116 return len - n;
3117}
3118
3119static int io_setstrbuf(VALUE *str, long len);
3120
3122 char *str_ptr;
3123 long len;
3124 rb_io_t *fptr;
3125};
3126
3127static VALUE
3128bufread_call(VALUE arg)
3129{
3130 struct bufread_arg *p = (struct bufread_arg *)arg;
3131 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3132 return Qundef;
3133}
3134
3135static long
3136io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3137{
3138 long len;
3139 struct bufread_arg arg;
3140
3141 io_setstrbuf(&str, offset + size);
3142 arg.str_ptr = RSTRING_PTR(str) + offset;
3143 arg.len = size;
3144 arg.fptr = fptr;
3145 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3146 len = arg.len;
3147 if (len < 0) rb_sys_fail_path(fptr->pathv);
3148 return len;
3149}
3150
3151static long
3152remain_size(rb_io_t *fptr)
3153{
3154 struct stat st;
3155 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3156 rb_off_t pos;
3157
3158 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3159#if defined(__HAIKU__)
3160 && (st.st_dev > 3)
3161#endif
3162 )
3163 {
3164 if (io_fflush(fptr) < 0)
3165 rb_sys_fail_on_write(fptr);
3166 pos = lseek(fptr->fd, 0, SEEK_CUR);
3167 if (st.st_size >= pos && pos >= 0) {
3168 siz += st.st_size - pos;
3169 if (siz > LONG_MAX) {
3170 rb_raise(rb_eIOError, "file too big for single read");
3171 }
3172 }
3173 }
3174 else {
3175 siz += BUFSIZ;
3176 }
3177 return (long)siz;
3178}
3179
3180static VALUE
3181io_enc_str(VALUE str, rb_io_t *fptr)
3182{
3183 rb_enc_associate(str, io_read_encoding(fptr));
3184 return str;
3185}
3186
3187static void
3188make_readconv(rb_io_t *fptr, int size)
3189{
3190 if (!fptr->readconv) {
3191 int ecflags;
3192 VALUE ecopts;
3193 const char *sname, *dname;
3195 ecopts = fptr->encs.ecopts;
3196 if (fptr->encs.enc2) {
3197 sname = rb_enc_name(fptr->encs.enc2);
3198 dname = rb_enc_name(io_read_encoding(fptr));
3199 }
3200 else {
3201 sname = dname = "";
3202 }
3203 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3204 if (!fptr->readconv)
3205 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3206 fptr->cbuf.off = 0;
3207 fptr->cbuf.len = 0;
3208 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3209 fptr->cbuf.capa = size;
3210 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3211 }
3212}
3213
3214#define MORE_CHAR_SUSPENDED Qtrue
3215#define MORE_CHAR_FINISHED Qnil
3216static VALUE
3217fill_cbuf(rb_io_t *fptr, int ec_flags)
3218{
3219 const unsigned char *ss, *sp, *se;
3220 unsigned char *ds, *dp, *de;
3222 int putbackable;
3223 int cbuf_len0;
3224 VALUE exc;
3225
3226 ec_flags |= ECONV_PARTIAL_INPUT;
3227
3228 if (fptr->cbuf.len == fptr->cbuf.capa)
3229 return MORE_CHAR_SUSPENDED; /* cbuf full */
3230 if (fptr->cbuf.len == 0)
3231 fptr->cbuf.off = 0;
3232 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3233 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3234 fptr->cbuf.off = 0;
3235 }
3236
3237 cbuf_len0 = fptr->cbuf.len;
3238
3239 while (1) {
3240 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3241 se = sp + fptr->rbuf.len;
3242 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3243 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3244 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3245 fptr->rbuf.off += (int)(sp - ss);
3246 fptr->rbuf.len -= (int)(sp - ss);
3247 fptr->cbuf.len += (int)(dp - ds);
3248
3249 putbackable = rb_econv_putbackable(fptr->readconv);
3250 if (putbackable) {
3251 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3252 fptr->rbuf.off -= putbackable;
3253 fptr->rbuf.len += putbackable;
3254 }
3255
3256 exc = rb_econv_make_exception(fptr->readconv);
3257 if (!NIL_P(exc))
3258 return exc;
3259
3260 if (cbuf_len0 != fptr->cbuf.len)
3261 return MORE_CHAR_SUSPENDED;
3262
3263 if (res == econv_finished) {
3264 return MORE_CHAR_FINISHED;
3265 }
3266
3267 if (res == econv_source_buffer_empty) {
3268 if (fptr->rbuf.len == 0) {
3269 READ_CHECK(fptr);
3270 if (io_fillbuf(fptr) < 0) {
3271 if (!fptr->readconv) {
3272 return MORE_CHAR_FINISHED;
3273 }
3274 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3275 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3276 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3277 fptr->cbuf.len += (int)(dp - ds);
3279 break;
3280 }
3281 }
3282 }
3283 }
3284 if (cbuf_len0 != fptr->cbuf.len)
3285 return MORE_CHAR_SUSPENDED;
3286
3287 return MORE_CHAR_FINISHED;
3288}
3289
3290static VALUE
3291more_char(rb_io_t *fptr)
3292{
3293 VALUE v;
3294 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3295 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3296 rb_exc_raise(v);
3297 return v;
3298}
3299
3300static VALUE
3301io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3302{
3303 VALUE str = Qnil;
3304 if (strp) {
3305 str = *strp;
3306 if (NIL_P(str)) {
3307 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3308 }
3309 else {
3310 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3311 }
3312 rb_enc_associate(str, fptr->encs.enc);
3313 }
3314 fptr->cbuf.off += len;
3315 fptr->cbuf.len -= len;
3316 /* xxx: set coderange */
3317 if (fptr->cbuf.len == 0)
3318 fptr->cbuf.off = 0;
3319 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3320 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3321 fptr->cbuf.off = 0;
3322 }
3323 return str;
3324}
3325
3326static int
3327io_setstrbuf(VALUE *str, long len)
3328{
3329 if (NIL_P(*str)) {
3330 *str = rb_str_new(0, len);
3331 return TRUE;
3332 }
3333 else {
3334 VALUE s = StringValue(*str);
3335 rb_str_modify(s);
3336
3337 long clen = RSTRING_LEN(s);
3338 if (clen >= len) {
3339 return FALSE;
3340 }
3341 len -= clen;
3342 }
3343 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3345 }
3346 return FALSE;
3347}
3348
3349#define MAX_REALLOC_GAP 4096
3350static void
3351io_shrink_read_string(VALUE str, long n)
3352{
3353 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3354 rb_str_resize(str, n);
3355 }
3356}
3357
3358static void
3359io_set_read_length(VALUE str, long n, int shrinkable)
3360{
3361 if (RSTRING_LEN(str) != n) {
3362 rb_str_modify(str);
3363 rb_str_set_len(str, n);
3364 if (shrinkable) io_shrink_read_string(str, n);
3365 }
3366}
3367
3368static VALUE
3369read_all(rb_io_t *fptr, long siz, VALUE str)
3370{
3371 long bytes;
3372 long n;
3373 long pos;
3374 rb_encoding *enc;
3375 int cr;
3376 int shrinkable;
3377
3378 if (NEED_READCONV(fptr)) {
3379 int first = !NIL_P(str);
3380 SET_BINARY_MODE(fptr);
3381 shrinkable = io_setstrbuf(&str,0);
3382 make_readconv(fptr, 0);
3383 while (1) {
3384 VALUE v;
3385 if (fptr->cbuf.len) {
3386 if (first) rb_str_set_len(str, first = 0);
3387 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3388 }
3389 v = fill_cbuf(fptr, 0);
3390 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3391 if (fptr->cbuf.len) {
3392 if (first) rb_str_set_len(str, first = 0);
3393 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3394 }
3395 rb_exc_raise(v);
3396 }
3397 if (v == MORE_CHAR_FINISHED) {
3398 clear_readconv(fptr);
3399 if (first) rb_str_set_len(str, first = 0);
3400 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3401 return io_enc_str(str, fptr);
3402 }
3403 }
3404 }
3405
3406 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3407 bytes = 0;
3408 pos = 0;
3409
3410 enc = io_read_encoding(fptr);
3411 cr = 0;
3412
3413 if (siz == 0) siz = BUFSIZ;
3414 shrinkable = io_setstrbuf(&str, siz);
3415 for (;;) {
3416 READ_CHECK(fptr);
3417 n = io_fread(str, bytes, siz - bytes, fptr);
3418 if (n == 0 && bytes == 0) {
3419 rb_str_set_len(str, 0);
3420 break;
3421 }
3422 bytes += n;
3423 rb_str_set_len(str, bytes);
3424 if (cr != ENC_CODERANGE_BROKEN)
3425 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3426 if (bytes < siz) break;
3427 siz += BUFSIZ;
3428
3429 size_t capa = rb_str_capacity(str);
3430 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3431 if (capa < BUFSIZ) {
3432 capa = BUFSIZ;
3433 }
3434 else if (capa > IO_MAX_BUFFER_GROWTH) {
3435 capa = IO_MAX_BUFFER_GROWTH;
3436 }
3438 }
3439 }
3440 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3441 str = io_enc_str(str, fptr);
3442 ENC_CODERANGE_SET(str, cr);
3443 return str;
3444}
3445
3446void
3448{
3449 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3450 rb_sys_fail_path(fptr->pathv);
3451 }
3452}
3453
3454static VALUE
3455io_read_memory_call(VALUE arg)
3456{
3457 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3458
3459 VALUE scheduler = rb_fiber_scheduler_current();
3460 if (scheduler != Qnil) {
3461 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3462
3463 if (!UNDEF_P(result)) {
3464 // This is actually returned as a pseudo-VALUE and later cast to a long:
3466 }
3467 }
3468
3469 if (iis->nonblock) {
3470 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3471 }
3472 else {
3473 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3474 }
3475}
3476
3477static long
3478io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3479{
3480 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3481}
3482
3483#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3484
3485static VALUE
3486io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3487{
3488 rb_io_t *fptr;
3489 VALUE length, str;
3490 long n, len;
3491 struct io_internal_read_struct iis;
3492 int shrinkable;
3493
3494 rb_scan_args(argc, argv, "11", &length, &str);
3495
3496 if ((len = NUM2LONG(length)) < 0) {
3497 rb_raise(rb_eArgError, "negative length %ld given", len);
3498 }
3499
3500 shrinkable = io_setstrbuf(&str, len);
3501
3502 GetOpenFile(io, fptr);
3504
3505 if (len == 0) {
3506 io_set_read_length(str, 0, shrinkable);
3507 return str;
3508 }
3509
3510 if (!nonblock)
3511 READ_CHECK(fptr);
3512 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3513 if (n <= 0) {
3514 again:
3515 if (nonblock) {
3516 rb_io_set_nonblock(fptr);
3517 }
3518 io_setstrbuf(&str, len);
3519 iis.th = rb_thread_current();
3520 iis.fptr = fptr;
3521 iis.nonblock = nonblock;
3522 iis.fd = fptr->fd;
3523 iis.buf = RSTRING_PTR(str);
3524 iis.capa = len;
3525 iis.timeout = NULL;
3526 n = io_read_memory_locktmp(str, &iis);
3527 if (n < 0) {
3528 int e = errno;
3529 if (!nonblock && fptr_wait_readable(fptr))
3530 goto again;
3531 if (nonblock && (io_again_p(e))) {
3532 if (no_exception)
3533 return sym_wait_readable;
3534 else
3535 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3536 e, "read would block");
3537 }
3538 rb_syserr_fail_path(e, fptr->pathv);
3539 }
3540 }
3541 io_set_read_length(str, n, shrinkable);
3542
3543 if (n == 0)
3544 return Qnil;
3545 else
3546 return str;
3547}
3548
3549/*
3550 * call-seq:
3551 * readpartial(maxlen) -> string
3552 * readpartial(maxlen, out_string) -> out_string
3553 *
3554 * Reads up to +maxlen+ bytes from the stream;
3555 * returns a string (either a new string or the given +out_string+).
3556 * Its encoding is:
3557 *
3558 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3559 * - ASCII-8BIT, otherwise.
3560 *
3561 * - Contains +maxlen+ bytes from the stream, if available.
3562 * - Otherwise contains all available bytes, if any available.
3563 * - Otherwise is an empty string.
3564 *
3565 * With the single non-negative integer argument +maxlen+ given,
3566 * returns a new string:
3567 *
3568 * f = File.new('t.txt')
3569 * f.readpartial(20) # => "First line\nSecond l"
3570 * f.readpartial(20) # => "ine\n\nFourth line\n"
3571 * f.readpartial(20) # => "Fifth line\n"
3572 * f.readpartial(20) # Raises EOFError.
3573 * f.close
3574 *
3575 * With both argument +maxlen+ and string argument +out_string+ given,
3576 * returns modified +out_string+:
3577 *
3578 * f = File.new('t.txt')
3579 * s = 'foo'
3580 * f.readpartial(20, s) # => "First line\nSecond l"
3581 * s = 'bar'
3582 * f.readpartial(0, s) # => ""
3583 * f.close
3584 *
3585 * This method is useful for a stream such as a pipe, a socket, or a tty.
3586 * It blocks only when no data is immediately available.
3587 * This means that it blocks only when _all_ of the following are true:
3588 *
3589 * - The byte buffer in the stream is empty.
3590 * - The content of the stream is empty.
3591 * - The stream is not at EOF.
3592 *
3593 * When blocked, the method waits for either more data or EOF on the stream:
3594 *
3595 * - If more data is read, the method returns the data.
3596 * - If EOF is reached, the method raises EOFError.
3597 *
3598 * When not blocked, the method responds immediately:
3599 *
3600 * - Returns data from the buffer if there is any.
3601 * - Otherwise returns data from the stream if there is any.
3602 * - Otherwise raises EOFError if the stream has reached EOF.
3603 *
3604 * Note that this method is similar to sysread. The differences are:
3605 *
3606 * - If the byte buffer is not empty, read from the byte buffer
3607 * instead of "sysread for buffered IO (IOError)".
3608 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3609 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3610 * readpartial retries the system call.
3611 *
3612 * The latter means that readpartial is non-blocking-flag insensitive.
3613 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3614 * if the fd is blocking mode.
3615 *
3616 * Examples:
3617 *
3618 * # # Returned Buffer Content Pipe Content
3619 * r, w = IO.pipe #
3620 * w << 'abc' # "" "abc".
3621 * r.readpartial(4096) # => "abc" "" ""
3622 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3623 *
3624 * # # Returned Buffer Content Pipe Content
3625 * r, w = IO.pipe #
3626 * w << 'abc' # "" "abc"
3627 * w.close # "" "abc" EOF
3628 * r.readpartial(4096) # => "abc" "" EOF
3629 * r.readpartial(4096) # raises EOFError
3630 *
3631 * # # Returned Buffer Content Pipe Content
3632 * r, w = IO.pipe #
3633 * w << "abc\ndef\n" # "" "abc\ndef\n"
3634 * r.gets # => "abc\n" "def\n" ""
3635 * w << "ghi\n" # "def\n" "ghi\n"
3636 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3637 * r.readpartial(4096) # => "ghi\n" "" ""
3638 *
3639 */
3640
3641static VALUE
3642io_readpartial(int argc, VALUE *argv, VALUE io)
3643{
3644 VALUE ret;
3645
3646 ret = io_getpartial(argc, argv, io, Qnil, 0);
3647 if (NIL_P(ret))
3648 rb_eof_error();
3649 return ret;
3650}
3651
3652static VALUE
3653io_nonblock_eof(int no_exception)
3654{
3655 if (!no_exception) {
3656 rb_eof_error();
3657 }
3658 return Qnil;
3659}
3660
3661/* :nodoc: */
3662static VALUE
3663io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3664{
3665 rb_io_t *fptr;
3666 long n, len;
3667 struct io_internal_read_struct iis;
3668 int shrinkable;
3669
3670 if ((len = NUM2LONG(length)) < 0) {
3671 rb_raise(rb_eArgError, "negative length %ld given", len);
3672 }
3673
3674 shrinkable = io_setstrbuf(&str, len);
3675 rb_bool_expected(ex, "exception", TRUE);
3676
3677 GetOpenFile(io, fptr);
3679
3680 if (len == 0) {
3681 io_set_read_length(str, 0, shrinkable);
3682 return str;
3683 }
3684
3685 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3686 if (n <= 0) {
3687 rb_fd_set_nonblock(fptr->fd);
3688 shrinkable |= io_setstrbuf(&str, len);
3689 iis.fptr = fptr;
3690 iis.nonblock = 1;
3691 iis.fd = fptr->fd;
3692 iis.buf = RSTRING_PTR(str);
3693 iis.capa = len;
3694 iis.timeout = NULL;
3695 n = io_read_memory_locktmp(str, &iis);
3696 if (n < 0) {
3697 int e = errno;
3698 if (io_again_p(e)) {
3699 if (!ex) return sym_wait_readable;
3700 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3701 e, "read would block");
3702 }
3703 rb_syserr_fail_path(e, fptr->pathv);
3704 }
3705 }
3706 io_set_read_length(str, n, shrinkable);
3707
3708 if (n == 0) {
3709 if (!ex) return Qnil;
3710 rb_eof_error();
3711 }
3712
3713 return str;
3714}
3715
3716/* :nodoc: */
3717static VALUE
3718io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3719{
3720 rb_io_t *fptr;
3721 long n;
3722
3723 if (!RB_TYPE_P(str, T_STRING))
3724 str = rb_obj_as_string(str);
3725 rb_bool_expected(ex, "exception", TRUE);
3726
3727 io = GetWriteIO(io);
3728 GetOpenFile(io, fptr);
3730
3731 if (io_fflush(fptr) < 0)
3732 rb_sys_fail_on_write(fptr);
3733
3734 rb_fd_set_nonblock(fptr->fd);
3735 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3736 RB_GC_GUARD(str);
3737
3738 if (n < 0) {
3739 int e = errno;
3740 if (io_again_p(e)) {
3741 if (!ex) {
3742 return sym_wait_writable;
3743 }
3744 else {
3745 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3746 }
3747 }
3748 rb_syserr_fail_path(e, fptr->pathv);
3749 }
3750
3751 return LONG2FIX(n);
3752}
3753
3754/*
3755 * call-seq:
3756 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3757 *
3758 * Reads bytes from the stream; the stream must be opened for reading
3759 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3760 *
3761 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3762 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3763 *
3764 * Returns a string (either a new string or the given +out_string+)
3765 * containing the bytes read.
3766 * The encoding of the string depends on both +maxLen+ and +out_string+:
3767 *
3768 * - +maxlen+ is +nil+: uses internal encoding of +self+
3769 * (regardless of whether +out_string+ was given).
3770 * - +maxlen+ not +nil+:
3771 *
3772 * - +out_string+ given: encoding of +out_string+ not modified.
3773 * - +out_string+ not given: ASCII-8BIT is used.
3774 *
3775 * <b>Without Argument +out_string+</b>
3776 *
3777 * When argument +out_string+ is omitted,
3778 * the returned value is a new string:
3779 *
3780 * f = File.new('t.txt')
3781 * f.read
3782 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3783 * f.rewind
3784 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3785 * f.read(30) # => "rth line\r\nFifth line\r\n"
3786 * f.read(30) # => nil
3787 * f.close
3788 *
3789 * If +maxlen+ is zero, returns an empty string.
3790 *
3791 * <b> With Argument +out_string+</b>
3792 *
3793 * When argument +out_string+ is given,
3794 * the returned value is +out_string+, whose content is replaced:
3795 *
3796 * f = File.new('t.txt')
3797 * s = 'foo' # => "foo"
3798 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3799 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3800 * f.rewind
3801 * s = 'bar'
3802 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3803 * s # => "First line\r\nSecond line\r\n\r\nFou"
3804 * s = 'baz'
3805 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3806 * s # => "rth line\r\nFifth line\r\n"
3807 * s = 'bat'
3808 * f.read(30, s) # => nil
3809 * s # => ""
3810 * f.close
3811 *
3812 * Note that this method behaves like the fread() function in C.
3813 * This means it retries to invoke read(2) system calls to read data
3814 * with the specified maxlen (or until EOF).
3815 *
3816 * This behavior is preserved even if the stream is in non-blocking mode.
3817 * (This method is non-blocking-flag insensitive as other methods.)
3818 *
3819 * If you need the behavior like a single read(2) system call,
3820 * consider #readpartial, #read_nonblock, and #sysread.
3821 *
3822 * Related: IO#write.
3823 */
3824
3825static VALUE
3826io_read(int argc, VALUE *argv, VALUE io)
3827{
3828 rb_io_t *fptr;
3829 long n, len;
3830 VALUE length, str;
3831 int shrinkable;
3832#if RUBY_CRLF_ENVIRONMENT
3833 int previous_mode;
3834#endif
3835
3836 rb_scan_args(argc, argv, "02", &length, &str);
3837
3838 if (NIL_P(length)) {
3839 GetOpenFile(io, fptr);
3841 return read_all(fptr, remain_size(fptr), str);
3842 }
3843 len = NUM2LONG(length);
3844 if (len < 0) {
3845 rb_raise(rb_eArgError, "negative length %ld given", len);
3846 }
3847
3848 shrinkable = io_setstrbuf(&str,len);
3849
3850 GetOpenFile(io, fptr);
3852 if (len == 0) {
3853 io_set_read_length(str, 0, shrinkable);
3854 return str;
3855 }
3856
3857 READ_CHECK(fptr);
3858#if RUBY_CRLF_ENVIRONMENT
3859 previous_mode = set_binary_mode_with_seek_cur(fptr);
3860#endif
3861 n = io_fread(str, 0, len, fptr);
3862 io_set_read_length(str, n, shrinkable);
3863#if RUBY_CRLF_ENVIRONMENT
3864 if (previous_mode == O_TEXT) {
3865 setmode(fptr->fd, O_TEXT);
3866 }
3867#endif
3868 if (n == 0) return Qnil;
3869
3870 return str;
3871}
3872
3873static void
3874rscheck(const char *rsptr, long rslen, VALUE rs)
3875{
3876 if (!rs) return;
3877 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3878 rb_raise(rb_eRuntimeError, "rs modified");
3879}
3880
3881static const char *
3882search_delim(const char *p, long len, int delim, rb_encoding *enc)
3883{
3884 if (rb_enc_mbminlen(enc) == 1) {
3885 p = memchr(p, delim, len);
3886 if (p) return p + 1;
3887 }
3888 else {
3889 const char *end = p + len;
3890 while (p < end) {
3891 int r = rb_enc_precise_mbclen(p, end, enc);
3892 if (!MBCLEN_CHARFOUND_P(r)) {
3893 p += rb_enc_mbminlen(enc);
3894 continue;
3895 }
3896 int n = MBCLEN_CHARFOUND_LEN(r);
3897 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3898 return p + n;
3899 }
3900 p += n;
3901 }
3902 }
3903 return NULL;
3904}
3905
3906static int
3907appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3908{
3909 VALUE str = *strp;
3910 long limit = *lp;
3911
3912 if (NEED_READCONV(fptr)) {
3913 SET_BINARY_MODE(fptr);
3914 make_readconv(fptr, 0);
3915 do {
3916 const char *p, *e;
3917 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3918 if (searchlen) {
3919 p = READ_CHAR_PENDING_PTR(fptr);
3920 if (0 < limit && limit < searchlen)
3921 searchlen = (int)limit;
3922 e = search_delim(p, searchlen, delim, enc);
3923 if (e) {
3924 int len = (int)(e-p);
3925 if (NIL_P(str))
3926 *strp = str = rb_str_new(p, len);
3927 else
3928 rb_str_buf_cat(str, p, len);
3929 fptr->cbuf.off += len;
3930 fptr->cbuf.len -= len;
3931 limit -= len;
3932 *lp = limit;
3933 return delim;
3934 }
3935
3936 if (NIL_P(str))
3937 *strp = str = rb_str_new(p, searchlen);
3938 else
3939 rb_str_buf_cat(str, p, searchlen);
3940 fptr->cbuf.off += searchlen;
3941 fptr->cbuf.len -= searchlen;
3942 limit -= searchlen;
3943
3944 if (limit == 0) {
3945 *lp = limit;
3946 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3947 }
3948 }
3949 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3950 clear_readconv(fptr);
3951 *lp = limit;
3952 return EOF;
3953 }
3954
3955 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3956 do {
3957 long pending = READ_DATA_PENDING_COUNT(fptr);
3958 if (pending > 0) {
3959 const char *p = READ_DATA_PENDING_PTR(fptr);
3960 const char *e;
3961 long last;
3962
3963 if (limit > 0 && pending > limit) pending = limit;
3964 e = search_delim(p, pending, delim, enc);
3965 if (e) pending = e - p;
3966 if (!NIL_P(str)) {
3967 last = RSTRING_LEN(str);
3968 rb_str_resize(str, last + pending);
3969 }
3970 else {
3971 last = 0;
3972 *strp = str = rb_str_buf_new(pending);
3973 rb_str_set_len(str, pending);
3974 }
3975 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3976 limit -= pending;
3977 *lp = limit;
3978 if (e) return delim;
3979 if (limit == 0)
3980 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3981 }
3982 READ_CHECK(fptr);
3983 } while (io_fillbuf(fptr) >= 0);
3984 *lp = limit;
3985 return EOF;
3986}
3987
3988static inline int
3989swallow(rb_io_t *fptr, int term)
3990{
3991 if (NEED_READCONV(fptr)) {
3992 rb_encoding *enc = io_read_encoding(fptr);
3993 int needconv = rb_enc_mbminlen(enc) != 1;
3994 SET_BINARY_MODE(fptr);
3995 make_readconv(fptr, 0);
3996 do {
3997 size_t cnt;
3998 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3999 const char *p = READ_CHAR_PENDING_PTR(fptr);
4000 int i;
4001 if (!needconv) {
4002 if (*p != term) return TRUE;
4003 i = (int)cnt;
4004 while (--i && *++p == term);
4005 }
4006 else {
4007 const char *e = p + cnt;
4008 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
4009 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4010 i = (int)(e - p);
4011 }
4012 io_shift_cbuf(fptr, (int)cnt - i, NULL);
4013 }
4014 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4015 return FALSE;
4016 }
4017
4018 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4019 do {
4020 size_t cnt;
4021 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4022 char buf[1024];
4023 const char *p = READ_DATA_PENDING_PTR(fptr);
4024 int i;
4025 if (cnt > sizeof buf) cnt = sizeof buf;
4026 if (*p != term) return TRUE;
4027 i = (int)cnt;
4028 while (--i && *++p == term);
4029 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4030 rb_sys_fail_path(fptr->pathv);
4031 }
4032 READ_CHECK(fptr);
4033 } while (io_fillbuf(fptr) == 0);
4034 return FALSE;
4035}
4036
4037static VALUE
4038rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4039{
4040 VALUE str = Qnil;
4041 int len = 0;
4042 long pos = 0;
4043 int cr = 0;
4044
4045 do {
4046 int pending = READ_DATA_PENDING_COUNT(fptr);
4047
4048 if (pending > 0) {
4049 const char *p = READ_DATA_PENDING_PTR(fptr);
4050 const char *e;
4051 int chomplen = 0;
4052
4053 e = memchr(p, '\n', pending);
4054 if (e) {
4055 pending = (int)(e - p + 1);
4056 if (chomp) {
4057 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4058 }
4059 }
4060 if (NIL_P(str)) {
4061 str = rb_str_new(p, pending - chomplen);
4062 fptr->rbuf.off += pending;
4063 fptr->rbuf.len -= pending;
4064 }
4065 else {
4066 rb_str_resize(str, len + pending - chomplen);
4067 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4068 fptr->rbuf.off += chomplen;
4069 fptr->rbuf.len -= chomplen;
4070 if (pending == 1 && chomplen == 1 && len > 0) {
4071 if (RSTRING_PTR(str)[len-1] == '\r') {
4072 rb_str_resize(str, --len);
4073 break;
4074 }
4075 }
4076 }
4077 len += pending - chomplen;
4078 if (cr != ENC_CODERANGE_BROKEN)
4079 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4080 if (e) break;
4081 }
4082 READ_CHECK(fptr);
4083 } while (io_fillbuf(fptr) >= 0);
4084 if (NIL_P(str)) return Qnil;
4085
4086 str = io_enc_str(str, fptr);
4087 ENC_CODERANGE_SET(str, cr);
4088 fptr->lineno++;
4089
4090 return str;
4091}
4092
4094 VALUE io;
4095 VALUE rs;
4096 long limit;
4097 unsigned int chomp: 1;
4098};
4099
4100static void
4101extract_getline_opts(VALUE opts, struct getline_arg *args)
4102{
4103 int chomp = FALSE;
4104 if (!NIL_P(opts)) {
4105 static ID kwds[1];
4106 VALUE vchomp;
4107 if (!kwds[0]) {
4108 kwds[0] = rb_intern_const("chomp");
4109 }
4110 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4111 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4112 }
4113 args->chomp = chomp;
4114}
4115
4116static void
4117extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4118{
4119 VALUE rs = rb_rs, lim = Qnil;
4120
4121 if (argc == 1) {
4122 VALUE tmp = Qnil;
4123
4124 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4125 rs = tmp;
4126 }
4127 else {
4128 lim = argv[0];
4129 }
4130 }
4131 else if (2 <= argc) {
4132 rs = argv[0], lim = argv[1];
4133 if (!NIL_P(rs))
4134 StringValue(rs);
4135 }
4136 args->rs = rs;
4137 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4138}
4139
4140static void
4141check_getline_args(VALUE *rsp, long *limit, VALUE io)
4142{
4143 rb_io_t *fptr;
4144 VALUE rs = *rsp;
4145
4146 if (!NIL_P(rs)) {
4147 rb_encoding *enc_rs, *enc_io;
4148
4149 GetOpenFile(io, fptr);
4150 enc_rs = rb_enc_get(rs);
4151 enc_io = io_read_encoding(fptr);
4152 if (enc_io != enc_rs &&
4153 (!is_ascii_string(rs) ||
4154 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4155 if (rs == rb_default_rs) {
4156 rs = rb_enc_str_new(0, 0, enc_io);
4157 rb_str_buf_cat_ascii(rs, "\n");
4158 *rsp = rs;
4159 }
4160 else {
4161 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4162 rb_enc_name(enc_io),
4163 rb_enc_name(enc_rs));
4164 }
4165 }
4166 }
4167}
4168
4169static void
4170prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4171{
4172 VALUE opts;
4173 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4174 extract_getline_args(argc, argv, args);
4175 extract_getline_opts(opts, args);
4176 check_getline_args(&args->rs, &args->limit, io);
4177}
4178
4179static VALUE
4180rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4181{
4182 VALUE str = Qnil;
4183 int nolimit = 0;
4184 rb_encoding *enc;
4185
4187 if (NIL_P(rs) && limit < 0) {
4188 str = read_all(fptr, 0, Qnil);
4189 if (RSTRING_LEN(str) == 0) return Qnil;
4190 }
4191 else if (limit == 0) {
4192 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4193 }
4194 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4195 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4196 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4197 return rb_io_getline_fast(fptr, enc, chomp);
4198 }
4199 else {
4200 int c, newline = -1;
4201 const char *rsptr = 0;
4202 long rslen = 0;
4203 int rspara = 0;
4204 int extra_limit = 16;
4205 int chomp_cr = chomp;
4206
4207 SET_BINARY_MODE(fptr);
4208 enc = io_read_encoding(fptr);
4209
4210 if (!NIL_P(rs)) {
4211 rslen = RSTRING_LEN(rs);
4212 if (rslen == 0) {
4213 rsptr = "\n\n";
4214 rslen = 2;
4215 rspara = 1;
4216 swallow(fptr, '\n');
4217 rs = 0;
4218 if (!rb_enc_asciicompat(enc)) {
4219 rs = rb_usascii_str_new(rsptr, rslen);
4220 rs = rb_str_conv_enc(rs, 0, enc);
4221 OBJ_FREEZE(rs);
4222 rsptr = RSTRING_PTR(rs);
4223 rslen = RSTRING_LEN(rs);
4224 }
4225 newline = '\n';
4226 }
4227 else if (rb_enc_mbminlen(enc) == 1) {
4228 rsptr = RSTRING_PTR(rs);
4229 newline = (unsigned char)rsptr[rslen - 1];
4230 }
4231 else {
4232 rs = rb_str_conv_enc(rs, 0, enc);
4233 rsptr = RSTRING_PTR(rs);
4234 const char *e = rsptr + rslen;
4235 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4236 int n;
4237 newline = rb_enc_codepoint_len(last, e, &n, enc);
4238 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4239 }
4240 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4241 }
4242
4243 /* MS - Optimization */
4244 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4245 const char *s, *p, *pp, *e;
4246
4247 if (c == newline) {
4248 if (RSTRING_LEN(str) < rslen) continue;
4249 s = RSTRING_PTR(str);
4250 e = RSTRING_END(str);
4251 p = e - rslen;
4252 if (!at_char_boundary(s, p, e, enc)) continue;
4253 if (!rspara) rscheck(rsptr, rslen, rs);
4254 if (memcmp(p, rsptr, rslen) == 0) {
4255 if (chomp) {
4256 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4257 rb_str_set_len(str, p - s);
4258 }
4259 break;
4260 }
4261 }
4262 if (limit == 0) {
4263 s = RSTRING_PTR(str);
4264 p = RSTRING_END(str);
4265 pp = rb_enc_prev_char(s, p, p, enc);
4266 if (extra_limit && pp &&
4267 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4268 /* relax the limit while incomplete character.
4269 * extra_limit limits the relax length */
4270 limit = 1;
4271 extra_limit--;
4272 }
4273 else {
4274 nolimit = 1;
4275 break;
4276 }
4277 }
4278 }
4279
4280 if (rspara && c != EOF)
4281 swallow(fptr, '\n');
4282 if (!NIL_P(str))
4283 str = io_enc_str(str, fptr);
4284 }
4285
4286 if (!NIL_P(str) && !nolimit) {
4287 fptr->lineno++;
4288 }
4289
4290 return str;
4291}
4292
4293static VALUE
4294rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4295{
4296 rb_io_t *fptr;
4297 int old_lineno, new_lineno;
4298 VALUE str;
4299
4300 GetOpenFile(io, fptr);
4301 old_lineno = fptr->lineno;
4302 str = rb_io_getline_0(rs, limit, chomp, fptr);
4303 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4304 if (io == ARGF.current_file) {
4305 ARGF.lineno += new_lineno - old_lineno;
4306 ARGF.last_lineno = ARGF.lineno;
4307 }
4308 else {
4309 ARGF.last_lineno = new_lineno;
4310 }
4311 }
4312
4313 return str;
4314}
4315
4316static VALUE
4317rb_io_getline(int argc, VALUE *argv, VALUE io)
4318{
4319 struct getline_arg args;
4320
4321 prepare_getline_args(argc, argv, &args, io);
4322 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4323}
4324
4325VALUE
4327{
4328 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4329}
4330
4331VALUE
4332rb_io_gets_limit_internal(VALUE io, long limit)
4333{
4334 rb_io_t *fptr;
4335 GetOpenFile(io, fptr);
4336 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4337}
4338
4339VALUE
4340rb_io_gets_internal(VALUE io)
4341{
4342 return rb_io_gets_limit_internal(io, -1);
4343}
4344
4345/*
4346 * call-seq:
4347 * gets(sep = $/, chomp: false) -> string or nil
4348 * gets(limit, chomp: false) -> string or nil
4349 * gets(sep, limit, chomp: false) -> string or nil
4350 *
4351 * Reads and returns a line from the stream;
4352 * assigns the return value to <tt>$_</tt>.
4353 * See {Line IO}[rdoc-ref:IO@Line+IO].
4354 *
4355 * With no arguments given, returns the next line
4356 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4357 *
4358 * f = File.open('t.txt')
4359 * f.gets # => "First line\n"
4360 * $_ # => "First line\n"
4361 * f.gets # => "\n"
4362 * f.gets # => "Fourth line\n"
4363 * f.gets # => "Fifth line\n"
4364 * f.gets # => nil
4365 * f.close
4366 *
4367 * With only string argument +sep+ given,
4368 * returns the next line as determined by line separator +sep+,
4369 * or +nil+ if none;
4370 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4371 *
4372 * f = File.new('t.txt')
4373 * f.gets('l') # => "First l"
4374 * f.gets('li') # => "ine\nSecond li"
4375 * f.gets('lin') # => "ne\n\nFourth lin"
4376 * f.gets # => "e\n"
4377 * f.close
4378 *
4379 * The two special values for +sep+ are honored:
4380 *
4381 * f = File.new('t.txt')
4382 * # Get all.
4383 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4384 * f.rewind
4385 * # Get paragraph (up to two line separators).
4386 * f.gets('') # => "First line\nSecond line\n\n"
4387 * f.close
4388 *
4389 * With only integer argument +limit+ given,
4390 * limits the number of bytes in the line;
4391 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4392 *
4393 * # No more than one line.
4394 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4395 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4396 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4397 *
4398 * With arguments +sep+ and +limit+ given,
4399 * combines the two behaviors
4400 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4401 *
4402 * Optional keyword argument +chomp+ specifies whether line separators
4403 * are to be omitted:
4404 *
4405 * f = File.open('t.txt')
4406 * # Chomp the lines.
4407 * f.gets(chomp: true) # => "First line"
4408 * f.gets(chomp: true) # => "Second line"
4409 * f.gets(chomp: true) # => ""
4410 * f.gets(chomp: true) # => "Fourth line"
4411 * f.gets(chomp: true) # => "Fifth line"
4412 * f.gets(chomp: true) # => nil
4413 * f.close
4414 *
4415 */
4416
4417static VALUE
4418rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4419{
4420 VALUE str;
4421
4422 str = rb_io_getline(argc, argv, io);
4423 rb_lastline_set(str);
4424
4425 return str;
4426}
4427
4428/*
4429 * call-seq:
4430 * lineno -> integer
4431 *
4432 * Returns the current line number for the stream;
4433 * see {Line Number}[rdoc-ref:IO@Line+Number].
4434 *
4435 */
4436
4437static VALUE
4438rb_io_lineno(VALUE io)
4439{
4440 rb_io_t *fptr;
4441
4442 GetOpenFile(io, fptr);
4444 return INT2NUM(fptr->lineno);
4445}
4446
4447/*
4448 * call-seq:
4449 * lineno = integer -> integer
4450 *
4451 * Sets and returns the line number for the stream;
4452 * see {Line Number}[rdoc-ref:IO@Line+Number].
4453 *
4454 */
4455
4456static VALUE
4457rb_io_set_lineno(VALUE io, VALUE lineno)
4458{
4459 rb_io_t *fptr;
4460
4461 GetOpenFile(io, fptr);
4463 fptr->lineno = NUM2INT(lineno);
4464 return lineno;
4465}
4466
4467/* :nodoc: */
4468static VALUE
4469io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4470{
4471 long limit = -1;
4472 if (NIL_P(lim)) {
4473 VALUE tmp = Qnil;
4474 // If sep is specified, but it's not a string and not nil, then assume
4475 // it's the limit (it should be an integer)
4476 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4477 // If the user has specified a non-nil / non-string value
4478 // for the separator, we assume it's the limit and set the
4479 // separator to default: rb_rs.
4480 lim = sep;
4481 limit = NUM2LONG(lim);
4482 sep = rb_rs;
4483 }
4484 else {
4485 sep = tmp;
4486 }
4487 }
4488 else {
4489 if (!NIL_P(sep)) StringValue(sep);
4490 limit = NUM2LONG(lim);
4491 }
4492
4493 check_getline_args(&sep, &limit, io);
4494
4495 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4496 rb_lastline_set_up(line, 1);
4497
4498 if (NIL_P(line)) {
4499 rb_eof_error();
4500 }
4501 return line;
4502}
4503
4504static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4505
4506/*
4507 * call-seq:
4508 * readlines(sep = $/, chomp: false) -> array
4509 * readlines(limit, chomp: false) -> array
4510 * readlines(sep, limit, chomp: false) -> array
4511 *
4512 * Reads and returns all remaining line from the stream;
4513 * does not modify <tt>$_</tt>.
4514 * See {Line IO}[rdoc-ref:IO@Line+IO].
4515 *
4516 * With no arguments given, returns lines
4517 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4518 *
4519 * f = File.new('t.txt')
4520 * f.readlines
4521 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4522 * f.readlines # => []
4523 * f.close
4524 *
4525 * With only string argument +sep+ given,
4526 * returns lines as determined by line separator +sep+,
4527 * or +nil+ if none;
4528 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4529 *
4530 * f = File.new('t.txt')
4531 * f.readlines('li')
4532 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4533 * f.close
4534 *
4535 * The two special values for +sep+ are honored:
4536 *
4537 * f = File.new('t.txt')
4538 * # Get all into one string.
4539 * f.readlines(nil)
4540 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4541 * # Get paragraphs (up to two line separators).
4542 * f.rewind
4543 * f.readlines('')
4544 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4545 * f.close
4546 *
4547 * With only integer argument +limit+ given,
4548 * limits the number of bytes in each line;
4549 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4550 *
4551 * f = File.new('t.txt')
4552 * f.readlines(8)
4553 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4554 * f.close
4555 *
4556 * With arguments +sep+ and +limit+ given,
4557 * combines the two behaviors
4558 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4559 *
4560 * Optional keyword argument +chomp+ specifies whether line separators
4561 * are to be omitted:
4562 *
4563 * f = File.new('t.txt')
4564 * f.readlines(chomp: true)
4565 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4566 * f.close
4567 *
4568 */
4569
4570static VALUE
4571rb_io_readlines(int argc, VALUE *argv, VALUE io)
4572{
4573 struct getline_arg args;
4574
4575 prepare_getline_args(argc, argv, &args, io);
4576 return io_readlines(&args, io);
4577}
4578
4579static VALUE
4580io_readlines(const struct getline_arg *arg, VALUE io)
4581{
4582 VALUE line, ary;
4583
4584 if (arg->limit == 0)
4585 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4586 ary = rb_ary_new();
4587 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4588 rb_ary_push(ary, line);
4589 }
4590 return ary;
4591}
4592
4593/*
4594 * call-seq:
4595 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4596 * each_line(limit, chomp: false) {|line| ... } -> self
4597 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4598 * each_line -> enumerator
4599 *
4600 * Calls the block with each remaining line read from the stream;
4601 * returns +self+.
4602 * Does nothing if already at end-of-stream;
4603 * See {Line IO}[rdoc-ref:IO@Line+IO].
4604 *
4605 * With no arguments given, reads lines
4606 * as determined by line separator <tt>$/</tt>:
4607 *
4608 * f = File.new('t.txt')
4609 * f.each_line {|line| p line }
4610 * f.each_line {|line| fail 'Cannot happen' }
4611 * f.close
4612 *
4613 * Output:
4614 *
4615 * "First line\n"
4616 * "Second line\n"
4617 * "\n"
4618 * "Fourth line\n"
4619 * "Fifth line\n"
4620 *
4621 * With only string argument +sep+ given,
4622 * reads lines as determined by line separator +sep+;
4623 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4624 *
4625 * f = File.new('t.txt')
4626 * f.each_line('li') {|line| p line }
4627 * f.close
4628 *
4629 * Output:
4630 *
4631 * "First li"
4632 * "ne\nSecond li"
4633 * "ne\n\nFourth li"
4634 * "ne\nFifth li"
4635 * "ne\n"
4636 *
4637 * The two special values for +sep+ are honored:
4638 *
4639 * f = File.new('t.txt')
4640 * # Get all into one string.
4641 * f.each_line(nil) {|line| p line }
4642 * f.close
4643 *
4644 * Output:
4645 *
4646 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4647 *
4648 * f.rewind
4649 * # Get paragraphs (up to two line separators).
4650 * f.each_line('') {|line| p line }
4651 *
4652 * Output:
4653 *
4654 * "First line\nSecond line\n\n"
4655 * "Fourth line\nFifth line\n"
4656 *
4657 * With only integer argument +limit+ given,
4658 * limits the number of bytes in each line;
4659 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4660 *
4661 * f = File.new('t.txt')
4662 * f.each_line(8) {|line| p line }
4663 * f.close
4664 *
4665 * Output:
4666 *
4667 * "First li"
4668 * "ne\n"
4669 * "Second l"
4670 * "ine\n"
4671 * "\n"
4672 * "Fourth l"
4673 * "ine\n"
4674 * "Fifth li"
4675 * "ne\n"
4676 *
4677 * With arguments +sep+ and +limit+ given,
4678 * combines the two behaviors
4679 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4680 *
4681 * Optional keyword argument +chomp+ specifies whether line separators
4682 * are to be omitted:
4683 *
4684 * f = File.new('t.txt')
4685 * f.each_line(chomp: true) {|line| p line }
4686 * f.close
4687 *
4688 * Output:
4689 *
4690 * "First line"
4691 * "Second line"
4692 * ""
4693 * "Fourth line"
4694 * "Fifth line"
4695 *
4696 * Returns an Enumerator if no block is given.
4697 */
4698
4699static VALUE
4700rb_io_each_line(int argc, VALUE *argv, VALUE io)
4701{
4702 VALUE str;
4703 struct getline_arg args;
4704
4705 RETURN_ENUMERATOR(io, argc, argv);
4706 prepare_getline_args(argc, argv, &args, io);
4707 if (args.limit == 0)
4708 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4709 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4710 rb_yield(str);
4711 }
4712 return io;
4713}
4714
4715/*
4716 * call-seq:
4717 * each_byte {|byte| ... } -> self
4718 * each_byte -> enumerator
4719 *
4720 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4721 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4722 *
4723 * f = File.new('t.rus')
4724 * a = []
4725 * f.each_byte {|b| a << b }
4726 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4727 * f.close
4728 *
4729 * Returns an Enumerator if no block is given.
4730 *
4731 * Related: IO#each_char, IO#each_codepoint.
4732 *
4733 */
4734
4735static VALUE
4736rb_io_each_byte(VALUE io)
4737{
4738 rb_io_t *fptr;
4739
4740 RETURN_ENUMERATOR(io, 0, 0);
4741 GetOpenFile(io, fptr);
4742
4743 do {
4744 while (fptr->rbuf.len > 0) {
4745 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4746 fptr->rbuf.len--;
4747 rb_yield(INT2FIX(*p & 0xff));
4749 errno = 0;
4750 }
4751 READ_CHECK(fptr);
4752 } while (io_fillbuf(fptr) >= 0);
4753 return io;
4754}
4755
4756static VALUE
4757io_getc(rb_io_t *fptr, rb_encoding *enc)
4758{
4759 int r, n, cr = 0;
4760 VALUE str;
4761
4762 if (NEED_READCONV(fptr)) {
4763 rb_encoding *read_enc = io_read_encoding(fptr);
4764
4765 str = Qnil;
4766 SET_BINARY_MODE(fptr);
4767 make_readconv(fptr, 0);
4768
4769 while (1) {
4770 if (fptr->cbuf.len) {
4771 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4772 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4773 read_enc);
4774 if (!MBCLEN_NEEDMORE_P(r))
4775 break;
4776 if (fptr->cbuf.len == fptr->cbuf.capa) {
4777 rb_raise(rb_eIOError, "too long character");
4778 }
4779 }
4780
4781 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4782 if (fptr->cbuf.len == 0) {
4783 clear_readconv(fptr);
4784 return Qnil;
4785 }
4786 /* return an unit of an incomplete character just before EOF */
4787 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4788 fptr->cbuf.off += 1;
4789 fptr->cbuf.len -= 1;
4790 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4792 return str;
4793 }
4794 }
4795 if (MBCLEN_INVALID_P(r)) {
4796 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4797 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4798 read_enc);
4799 io_shift_cbuf(fptr, r, &str);
4801 }
4802 else {
4803 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4805 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4806 ISASCII(RSTRING_PTR(str)[0])) {
4807 cr = ENC_CODERANGE_7BIT;
4808 }
4809 }
4810 str = io_enc_str(str, fptr);
4811 ENC_CODERANGE_SET(str, cr);
4812 return str;
4813 }
4814
4815 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4816 if (io_fillbuf(fptr) < 0) {
4817 return Qnil;
4818 }
4819 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4820 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4821 fptr->rbuf.off += 1;
4822 fptr->rbuf.len -= 1;
4823 cr = ENC_CODERANGE_7BIT;
4824 }
4825 else {
4826 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4827 if (MBCLEN_CHARFOUND_P(r) &&
4828 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4829 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4830 fptr->rbuf.off += n;
4831 fptr->rbuf.len -= n;
4833 }
4834 else if (MBCLEN_NEEDMORE_P(r)) {
4835 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4836 fptr->rbuf.len = 0;
4837 getc_needmore:
4838 if (io_fillbuf(fptr) != -1) {
4839 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4840 fptr->rbuf.off++;
4841 fptr->rbuf.len--;
4842 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4843 if (MBCLEN_NEEDMORE_P(r)) {
4844 goto getc_needmore;
4845 }
4846 else if (MBCLEN_CHARFOUND_P(r)) {
4848 }
4849 }
4850 }
4851 else {
4852 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4853 fptr->rbuf.off++;
4854 fptr->rbuf.len--;
4855 }
4856 }
4857 if (!cr) cr = ENC_CODERANGE_BROKEN;
4858 str = io_enc_str(str, fptr);
4859 ENC_CODERANGE_SET(str, cr);
4860 return str;
4861}
4862
4863/*
4864 * call-seq:
4865 * each_char {|c| ... } -> self
4866 * each_char -> enumerator
4867 *
4868 * Calls the given block with each character in the stream; returns +self+.
4869 * See {Character IO}[rdoc-ref:IO@Character+IO].
4870 *
4871 * f = File.new('t.rus')
4872 * a = []
4873 * f.each_char {|c| a << c.ord }
4874 * a # => [1090, 1077, 1089, 1090]
4875 * f.close
4876 *
4877 * Returns an Enumerator if no block is given.
4878 *
4879 * Related: IO#each_byte, IO#each_codepoint.
4880 *
4881 */
4882
4883static VALUE
4884rb_io_each_char(VALUE io)
4885{
4886 rb_io_t *fptr;
4887 rb_encoding *enc;
4888 VALUE c;
4889
4890 RETURN_ENUMERATOR(io, 0, 0);
4891 GetOpenFile(io, fptr);
4893
4894 enc = io_input_encoding(fptr);
4895 READ_CHECK(fptr);
4896 while (!NIL_P(c = io_getc(fptr, enc))) {
4897 rb_yield(c);
4898 }
4899 return io;
4900}
4901
4902/*
4903 * call-seq:
4904 * each_codepoint {|c| ... } -> self
4905 * each_codepoint -> enumerator
4906 *
4907 * Calls the given block with each codepoint in the stream; returns +self+:
4908 *
4909 * f = File.new('t.rus')
4910 * a = []
4911 * f.each_codepoint {|c| a << c }
4912 * a # => [1090, 1077, 1089, 1090]
4913 * f.close
4914 *
4915 * Returns an Enumerator if no block is given.
4916 *
4917 * Related: IO#each_byte, IO#each_char.
4918 *
4919 */
4920
4921static VALUE
4922rb_io_each_codepoint(VALUE io)
4923{
4924 rb_io_t *fptr;
4925 rb_encoding *enc;
4926 unsigned int c;
4927 int r, n;
4928
4929 RETURN_ENUMERATOR(io, 0, 0);
4930 GetOpenFile(io, fptr);
4932
4933 READ_CHECK(fptr);
4934 enc = io_read_encoding(fptr);
4935 if (NEED_READCONV(fptr)) {
4936 SET_BINARY_MODE(fptr);
4937 r = 1; /* no invalid char yet */
4938 for (;;) {
4939 make_readconv(fptr, 0);
4940 for (;;) {
4941 if (fptr->cbuf.len) {
4942 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4943 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4944 enc);
4945 if (!MBCLEN_NEEDMORE_P(r))
4946 break;
4947 if (fptr->cbuf.len == fptr->cbuf.capa) {
4948 rb_raise(rb_eIOError, "too long character");
4949 }
4950 }
4951 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4952 clear_readconv(fptr);
4953 if (!MBCLEN_CHARFOUND_P(r)) {
4954 goto invalid;
4955 }
4956 return io;
4957 }
4958 }
4959 if (MBCLEN_INVALID_P(r)) {
4960 goto invalid;
4961 }
4962 n = MBCLEN_CHARFOUND_LEN(r);
4963 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4964 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4965 enc);
4966 fptr->cbuf.off += n;
4967 fptr->cbuf.len -= n;
4968 rb_yield(UINT2NUM(c));
4970 }
4971 }
4972 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4973 while (io_fillbuf(fptr) >= 0) {
4974 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4975 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4976 if (MBCLEN_CHARFOUND_P(r) &&
4977 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4978 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4979 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4980 fptr->rbuf.off += n;
4981 fptr->rbuf.len -= n;
4982 rb_yield(UINT2NUM(c));
4983 }
4984 else if (MBCLEN_INVALID_P(r)) {
4985 goto invalid;
4986 }
4987 else if (MBCLEN_NEEDMORE_P(r)) {
4988 char cbuf[8], *p = cbuf;
4989 int more = MBCLEN_NEEDMORE_LEN(r);
4990 if (more > numberof(cbuf)) goto invalid;
4991 more += n = fptr->rbuf.len;
4992 if (more > numberof(cbuf)) goto invalid;
4993 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4994 (p += n, (more -= n) > 0)) {
4995 if (io_fillbuf(fptr) < 0) goto invalid;
4996 if ((n = fptr->rbuf.len) > more) n = more;
4997 }
4998 r = rb_enc_precise_mbclen(cbuf, p, enc);
4999 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
5000 c = rb_enc_codepoint(cbuf, p, enc);
5001 rb_yield(UINT2NUM(c));
5002 }
5003 else {
5004 continue;
5005 }
5007 }
5008 return io;
5009
5010 invalid:
5011 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
5013}
5014
5015/*
5016 * call-seq:
5017 * getc -> character or nil
5018 *
5019 * Reads and returns the next 1-character string from the stream;
5020 * returns +nil+ if already at end-of-stream.
5021 * See {Character IO}[rdoc-ref:IO@Character+IO].
5022 *
5023 * f = File.open('t.txt')
5024 * f.getc # => "F"
5025 * f.close
5026 * f = File.open('t.rus')
5027 * f.getc.ord # => 1090
5028 * f.close
5029 *
5030 * Related: IO#readchar (may raise EOFError).
5031 *
5032 */
5033
5034static VALUE
5035rb_io_getc(VALUE io)
5036{
5037 rb_io_t *fptr;
5038 rb_encoding *enc;
5039
5040 GetOpenFile(io, fptr);
5042
5043 enc = io_input_encoding(fptr);
5044 READ_CHECK(fptr);
5045 return io_getc(fptr, enc);
5046}
5047
5048/*
5049 * call-seq:
5050 * readchar -> string
5051 *
5052 * Reads and returns the next 1-character string from the stream;
5053 * raises EOFError if already at end-of-stream.
5054 * See {Character IO}[rdoc-ref:IO@Character+IO].
5055 *
5056 * f = File.open('t.txt')
5057 * f.readchar # => "F"
5058 * f.close
5059 * f = File.open('t.rus')
5060 * f.readchar.ord # => 1090
5061 * f.close
5062 *
5063 * Related: IO#getc (will not raise EOFError).
5064 *
5065 */
5066
5067static VALUE
5068rb_io_readchar(VALUE io)
5069{
5070 VALUE c = rb_io_getc(io);
5071
5072 if (NIL_P(c)) {
5073 rb_eof_error();
5074 }
5075 return c;
5076}
5077
5078/*
5079 * call-seq:
5080 * getbyte -> integer or nil
5081 *
5082 * Reads and returns the next byte (in range 0..255) from the stream;
5083 * returns +nil+ if already at end-of-stream.
5084 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5085 *
5086 * f = File.open('t.txt')
5087 * f.getbyte # => 70
5088 * f.close
5089 * f = File.open('t.rus')
5090 * f.getbyte # => 209
5091 * f.close
5092 *
5093 * Related: IO#readbyte (may raise EOFError).
5094 */
5095
5096VALUE
5098{
5099 rb_io_t *fptr;
5100 int c;
5101
5102 GetOpenFile(io, fptr);
5104 READ_CHECK(fptr);
5105 VALUE r_stdout = rb_ractor_stdout();
5106 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5107 rb_io_t *ofp;
5108 GetOpenFile(r_stdout, ofp);
5109 if (ofp->mode & FMODE_TTY) {
5110 rb_io_flush(r_stdout);
5111 }
5112 }
5113 if (io_fillbuf(fptr) < 0) {
5114 return Qnil;
5115 }
5116 fptr->rbuf.off++;
5117 fptr->rbuf.len--;
5118 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5119 return INT2FIX(c & 0xff);
5120}
5121
5122/*
5123 * call-seq:
5124 * readbyte -> integer
5125 *
5126 * Reads and returns the next byte (in range 0..255) from the stream;
5127 * raises EOFError if already at end-of-stream.
5128 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5129 *
5130 * f = File.open('t.txt')
5131 * f.readbyte # => 70
5132 * f.close
5133 * f = File.open('t.rus')
5134 * f.readbyte # => 209
5135 * f.close
5136 *
5137 * Related: IO#getbyte (will not raise EOFError).
5138 *
5139 */
5140
5141static VALUE
5142rb_io_readbyte(VALUE io)
5143{
5144 VALUE c = rb_io_getbyte(io);
5145
5146 if (NIL_P(c)) {
5147 rb_eof_error();
5148 }
5149 return c;
5150}
5151
5152/*
5153 * call-seq:
5154 * ungetbyte(integer) -> nil
5155 * ungetbyte(string) -> nil
5156 *
5157 * Pushes back ("unshifts") the given data onto the stream's buffer,
5158 * placing the data so that it is next to be read; returns +nil+.
5159 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5160 *
5161 * Note that:
5162 *
5163 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5164 * - Calling #rewind on the stream discards the pushed-back data.
5165 *
5166 * When argument +integer+ is given, uses only its low-order byte:
5167 *
5168 * File.write('t.tmp', '012')
5169 * f = File.open('t.tmp')
5170 * f.ungetbyte(0x41) # => nil
5171 * f.read # => "A012"
5172 * f.rewind
5173 * f.ungetbyte(0x4243) # => nil
5174 * f.read # => "C012"
5175 * f.close
5176 *
5177 * When argument +string+ is given, uses all bytes:
5178 *
5179 * File.write('t.tmp', '012')
5180 * f = File.open('t.tmp')
5181 * f.ungetbyte('A') # => nil
5182 * f.read # => "A012"
5183 * f.rewind
5184 * f.ungetbyte('BCDE') # => nil
5185 * f.read # => "BCDE012"
5186 * f.close
5187 *
5188 */
5189
5190VALUE
5192{
5193 rb_io_t *fptr;
5194
5195 GetOpenFile(io, fptr);
5197 switch (TYPE(b)) {
5198 case T_NIL:
5199 return Qnil;
5200 case T_FIXNUM:
5201 case T_BIGNUM: ;
5202 VALUE v = rb_int_modulo(b, INT2FIX(256));
5203 unsigned char c = NUM2INT(v) & 0xFF;
5204 b = rb_str_new((const char *)&c, 1);
5205 break;
5206 default:
5207 StringValue(b);
5208 }
5209 io_ungetbyte(b, fptr);
5210 return Qnil;
5211}
5212
5213/*
5214 * call-seq:
5215 * ungetc(integer) -> nil
5216 * ungetc(string) -> nil
5217 *
5218 * Pushes back ("unshifts") the given data onto the stream's buffer,
5219 * placing the data so that it is next to be read; returns +nil+.
5220 * See {Character IO}[rdoc-ref:IO@Character+IO].
5221 *
5222 * Note that:
5223 *
5224 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5225 * - Calling #rewind on the stream discards the pushed-back data.
5226 *
5227 * When argument +integer+ is given, interprets the integer as a character:
5228 *
5229 * File.write('t.tmp', '012')
5230 * f = File.open('t.tmp')
5231 * f.ungetc(0x41) # => nil
5232 * f.read # => "A012"
5233 * f.rewind
5234 * f.ungetc(0x0442) # => nil
5235 * f.getc.ord # => 1090
5236 * f.close
5237 *
5238 * When argument +string+ is given, uses all characters:
5239 *
5240 * File.write('t.tmp', '012')
5241 * f = File.open('t.tmp')
5242 * f.ungetc('A') # => nil
5243 * f.read # => "A012"
5244 * f.rewind
5245 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5246 * f.getc.ord # => 1090
5247 * f.getc.ord # => 1077
5248 * f.getc.ord # => 1089
5249 * f.getc.ord # => 1090
5250 * f.close
5251 *
5252 */
5253
5254VALUE
5256{
5257 rb_io_t *fptr;
5258 long len;
5259
5260 GetOpenFile(io, fptr);
5262 if (FIXNUM_P(c)) {
5263 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5264 }
5265 else if (RB_BIGNUM_TYPE_P(c)) {
5266 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5267 }
5268 else {
5269 StringValue(c);
5270 }
5271 if (NEED_READCONV(fptr)) {
5272 SET_BINARY_MODE(fptr);
5273 len = RSTRING_LEN(c);
5274#if SIZEOF_LONG > SIZEOF_INT
5275 if (len > INT_MAX)
5276 rb_raise(rb_eIOError, "ungetc failed");
5277#endif
5278 make_readconv(fptr, (int)len);
5279 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5280 rb_raise(rb_eIOError, "ungetc failed");
5281 if (fptr->cbuf.off < len) {
5282 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5283 fptr->cbuf.ptr+fptr->cbuf.off,
5284 char, fptr->cbuf.len);
5285 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5286 }
5287 fptr->cbuf.off -= (int)len;
5288 fptr->cbuf.len += (int)len;
5289 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5290 }
5291 else {
5292 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5293 io_ungetbyte(c, fptr);
5294 }
5295 return Qnil;
5296}
5297
5298/*
5299 * call-seq:
5300 * isatty -> true or false
5301 *
5302 * Returns +true+ if the stream is associated with a terminal device (tty),
5303 * +false+ otherwise:
5304 *
5305 * f = File.new('t.txt').isatty #=> false
5306 * f.close
5307 * f = File.new('/dev/tty').isatty #=> true
5308 * f.close
5309 *
5310 */
5311
5312static VALUE
5313rb_io_isatty(VALUE io)
5314{
5315 rb_io_t *fptr;
5316
5317 GetOpenFile(io, fptr);
5318 return RBOOL(isatty(fptr->fd) != 0);
5319}
5320
5321#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5322/*
5323 * call-seq:
5324 * close_on_exec? -> true or false
5325 *
5326 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5327 *
5328 * f = File.open('t.txt')
5329 * f.close_on_exec? # => true
5330 * f.close_on_exec = false
5331 * f.close_on_exec? # => false
5332 * f.close
5333 *
5334 */
5335
5336static VALUE
5337rb_io_close_on_exec_p(VALUE io)
5338{
5339 rb_io_t *fptr;
5340 VALUE write_io;
5341 int fd, ret;
5342
5343 write_io = GetWriteIO(io);
5344 if (io != write_io) {
5345 GetOpenFile(write_io, fptr);
5346 if (fptr && 0 <= (fd = fptr->fd)) {
5347 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5348 if (!(ret & FD_CLOEXEC)) return Qfalse;
5349 }
5350 }
5351
5352 GetOpenFile(io, fptr);
5353 if (fptr && 0 <= (fd = fptr->fd)) {
5354 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5355 if (!(ret & FD_CLOEXEC)) return Qfalse;
5356 }
5357 return Qtrue;
5358}
5359#else
5360#define rb_io_close_on_exec_p rb_f_notimplement
5361#endif
5362
5363#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5364/*
5365 * call-seq:
5366 * self.close_on_exec = bool -> true or false
5367 *
5368 * Sets a close-on-exec flag.
5369 *
5370 * f = File.open(File::NULL)
5371 * f.close_on_exec = true
5372 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5373 * f.closed? #=> false
5374 *
5375 * Ruby sets close-on-exec flags of all file descriptors by default
5376 * since Ruby 2.0.0.
5377 * So you don't need to set by yourself.
5378 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5379 * if another thread use fork() and exec() (via system() method for example).
5380 * If you really needs file descriptor inheritance to child process,
5381 * use spawn()'s argument such as fd=>fd.
5382 */
5383
5384static VALUE
5385rb_io_set_close_on_exec(VALUE io, VALUE arg)
5386{
5387 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5388 rb_io_t *fptr;
5389 VALUE write_io;
5390 int fd, ret;
5391
5392 write_io = GetWriteIO(io);
5393 if (io != write_io) {
5394 GetOpenFile(write_io, fptr);
5395 if (fptr && 0 <= (fd = fptr->fd)) {
5396 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5397 if ((ret & FD_CLOEXEC) != flag) {
5398 ret = (ret & ~FD_CLOEXEC) | flag;
5399 ret = fcntl(fd, F_SETFD, ret);
5400 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5401 }
5402 }
5403
5404 }
5405
5406 GetOpenFile(io, fptr);
5407 if (fptr && 0 <= (fd = fptr->fd)) {
5408 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5409 if ((ret & FD_CLOEXEC) != flag) {
5410 ret = (ret & ~FD_CLOEXEC) | flag;
5411 ret = fcntl(fd, F_SETFD, ret);
5412 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5413 }
5414 }
5415 return Qnil;
5416}
5417#else
5418#define rb_io_set_close_on_exec rb_f_notimplement
5419#endif
5420
5421#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5422#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5423
5424static VALUE
5425finish_writeconv(rb_io_t *fptr, int noalloc)
5426{
5427 unsigned char *ds, *dp, *de;
5429
5430 if (!fptr->wbuf.ptr) {
5431 unsigned char buf[1024];
5432
5434 while (res == econv_destination_buffer_full) {
5435 ds = dp = buf;
5436 de = buf + sizeof(buf);
5437 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5438 while (dp-ds) {
5439 size_t remaining = dp-ds;
5440 long result = rb_io_write_memory(fptr, ds, remaining);
5441
5442 if (result > 0) {
5443 ds += result;
5444 if ((size_t)result == remaining) break;
5445 }
5446 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5447 if (fptr->fd < 0)
5448 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5449 }
5450 else {
5451 return noalloc ? Qtrue : INT2NUM(errno);
5452 }
5453 }
5454 if (res == econv_invalid_byte_sequence ||
5455 res == econv_incomplete_input ||
5457 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5458 }
5459 }
5460
5461 return Qnil;
5462 }
5463
5465 while (res == econv_destination_buffer_full) {
5466 if (fptr->wbuf.len == fptr->wbuf.capa) {
5467 if (io_fflush(fptr) < 0) {
5468 return noalloc ? Qtrue : INT2NUM(errno);
5469 }
5470 }
5471
5472 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5473 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5474 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5475 fptr->wbuf.len += (int)(dp - ds);
5476 if (res == econv_invalid_byte_sequence ||
5477 res == econv_incomplete_input ||
5479 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5480 }
5481 }
5482 return Qnil;
5483}
5484
5486 rb_io_t *fptr;
5487 int noalloc;
5488};
5489
5490static VALUE
5491finish_writeconv_sync(VALUE arg)
5492{
5493 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5494 return finish_writeconv(p->fptr, p->noalloc);
5495}
5496
5497static void*
5498nogvl_close(void *ptr)
5499{
5500 int *fd = ptr;
5501
5502 return (void*)(intptr_t)close(*fd);
5503}
5504
5505static int
5506maygvl_close(int fd, int keepgvl)
5507{
5508 if (keepgvl)
5509 return close(fd);
5510
5511 /*
5512 * close() may block for certain file types (NFS, SO_LINGER sockets,
5513 * inotify), so let other threads run.
5514 */
5515 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5516}
5517
5518static void*
5519nogvl_fclose(void *ptr)
5520{
5521 FILE *file = ptr;
5522
5523 return (void*)(intptr_t)fclose(file);
5524}
5525
5526static int
5527maygvl_fclose(FILE *file, int keepgvl)
5528{
5529 if (keepgvl)
5530 return fclose(file);
5531
5532 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5533}
5534
5535static void free_io_buffer(rb_io_buffer_t *buf);
5536
5537static void
5538fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5539{
5540 VALUE error = Qnil;
5541 int fd = fptr->fd;
5542 FILE *stdio_file = fptr->stdio_file;
5543 int mode = fptr->mode;
5544
5545 if (fptr->writeconv) {
5546 if (!NIL_P(fptr->write_lock) && !noraise) {
5547 struct finish_writeconv_arg arg;
5548 arg.fptr = fptr;
5549 arg.noalloc = noraise;
5550 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5551 }
5552 else {
5553 error = finish_writeconv(fptr, noraise);
5554 }
5555 }
5556 if (fptr->wbuf.len) {
5557 if (noraise) {
5558 io_flush_buffer_sync(fptr);
5559 }
5560 else {
5561 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5562 error = INT2NUM(errno);
5563 }
5564 }
5565 }
5566
5567 int done = 0;
5568
5569 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5570 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5571 done = 1;
5572 }
5573
5574 fptr->fd = -1;
5575 fptr->stdio_file = 0;
5577
5578 // Wait for blocking operations to ensure they do not hit EBADF:
5579 rb_thread_io_close_wait(fptr);
5580
5581 if (!done && stdio_file) {
5582 // stdio_file is deallocated anyway even if fclose failed.
5583 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5584 if (!noraise) {
5585 error = INT2NUM(errno);
5586 }
5587 }
5588
5589 done = 1;
5590 }
5591
5592 VALUE scheduler = rb_fiber_scheduler_current();
5593 if (!done && fd >= 0 && scheduler != Qnil) {
5594 VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
5595
5596 if (!UNDEF_P(result)) {
5597 done = RTEST(result);
5598 }
5599 }
5600
5601 if (!done && fd >= 0) {
5602 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5603 // We assumes it is closed.
5604
5605 keepgvl |= !(mode & FMODE_WRITABLE);
5606 keepgvl |= noraise;
5607 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5608 if (!noraise) {
5609 error = INT2NUM(errno);
5610 }
5611 }
5612
5613 done = 1;
5614 }
5615
5616 if (!NIL_P(error) && !noraise) {
5617 if (RB_INTEGER_TYPE_P(error))
5618 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5619 else
5620 rb_exc_raise(error);
5621 }
5622}
5623
5624static void
5625fptr_finalize(rb_io_t *fptr, int noraise)
5626{
5627 fptr_finalize_flush(fptr, noraise, FALSE);
5628 free_io_buffer(&fptr->rbuf);
5629 free_io_buffer(&fptr->wbuf);
5630 clear_codeconv(fptr);
5631}
5632
5633static void
5634rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5635{
5636 if (fptr->finalize) {
5637 (*fptr->finalize)(fptr, noraise);
5638 }
5639 else {
5640 fptr_finalize(fptr, noraise);
5641 }
5642}
5643
5644static void
5645free_io_buffer(rb_io_buffer_t *buf)
5646{
5647 if (buf->ptr) {
5648 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5649 buf->ptr = NULL;
5650 }
5651}
5652
5653static void
5654clear_readconv(rb_io_t *fptr)
5655{
5656 if (fptr->readconv) {
5657 rb_econv_close(fptr->readconv);
5658 fptr->readconv = NULL;
5659 }
5660 free_io_buffer(&fptr->cbuf);
5661}
5662
5663static void
5664clear_writeconv(rb_io_t *fptr)
5665{
5666 if (fptr->writeconv) {
5668 fptr->writeconv = NULL;
5669 }
5670 fptr->writeconv_initialized = 0;
5671}
5672
5673static void
5674clear_codeconv(rb_io_t *fptr)
5675{
5676 clear_readconv(fptr);
5677 clear_writeconv(fptr);
5678}
5679
5680static void
5681rb_io_fptr_cleanup_all(rb_io_t *fptr)
5682{
5683 fptr->pathv = Qnil;
5684 if (0 <= fptr->fd)
5685 rb_io_fptr_cleanup(fptr, TRUE);
5686 fptr->write_lock = Qnil;
5687 free_io_buffer(&fptr->rbuf);
5688 free_io_buffer(&fptr->wbuf);
5689 clear_codeconv(fptr);
5690}
5691
5692int
5694{
5695 if (!io) return 0;
5696 rb_io_fptr_cleanup_all(io);
5697 free(io);
5698
5699 return 1;
5700}
5701
5702size_t
5703rb_io_memsize(const rb_io_t *io)
5704{
5705 size_t size = sizeof(rb_io_t);
5706 size += io->rbuf.capa;
5707 size += io->wbuf.capa;
5708 size += io->cbuf.capa;
5709 if (io->readconv) size += rb_econv_memsize(io->readconv);
5710 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5711
5712 struct rb_io_blocking_operation *blocking_operation = 0;
5713
5714 // 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.
5715 rb_serial_t fork_generation = GET_VM()->fork_gen;
5716 if (io->fork_generation == fork_generation) {
5717 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5718 size += sizeof(struct rb_io_blocking_operation);
5719 }
5720 }
5721
5722 return size;
5723}
5724
5725#ifdef _WIN32
5726/* keep GVL while closing to prevent crash on Windows */
5727# define KEEPGVL TRUE
5728#else
5729# define KEEPGVL FALSE
5730#endif
5731
5732static rb_io_t *
5733io_close_fptr(VALUE io)
5734{
5735 rb_io_t *fptr;
5736 VALUE write_io;
5737 rb_io_t *write_fptr;
5738
5739 write_io = GetWriteIO(io);
5740 if (io != write_io) {
5741 write_fptr = RFILE(write_io)->fptr;
5742 if (write_fptr && 0 <= write_fptr->fd) {
5743 rb_io_fptr_cleanup(write_fptr, TRUE);
5744 }
5745 }
5746
5747 fptr = RFILE(io)->fptr;
5748 if (!fptr) return 0;
5749 if (fptr->fd < 0) return 0;
5750
5751 // This guards against multiple threads closing the same IO object:
5752 if (rb_thread_io_close_interrupt(fptr)) {
5753 /* calls close(fptr->fd): */
5754 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5755 }
5756
5757 rb_io_fptr_cleanup(fptr, FALSE);
5758 return fptr;
5759}
5760
5761static void
5762fptr_waitpid(rb_io_t *fptr, int nohang)
5763{
5764 int status;
5765 if (fptr->pid) {
5766 rb_last_status_clear();
5767 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5768 fptr->pid = 0;
5769 }
5770}
5771
5772VALUE
5774{
5775 rb_io_t *fptr = io_close_fptr(io);
5776 if (fptr) fptr_waitpid(fptr, 0);
5777 return Qnil;
5778}
5779
5780/*
5781 * call-seq:
5782 * close -> nil
5783 *
5784 * Closes the stream for both reading and writing
5785 * if open for either or both; returns +nil+.
5786 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5787 *
5788 * If the stream is open for writing, flushes any buffered writes
5789 * to the operating system before closing.
5790 *
5791 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5792 * (child exit status).
5793 *
5794 * It is not an error to close an IO object that has already been closed.
5795 * It just returns nil.
5796 *
5797 * Example:
5798 *
5799 * IO.popen('ruby', 'r+') do |pipe|
5800 * puts pipe.closed?
5801 * pipe.close
5802 * puts $?
5803 * puts pipe.closed?
5804 * end
5805 *
5806 * Output:
5807 *
5808 * false
5809 * pid 13760 exit 0
5810 * true
5811 *
5812 * Related: IO#close_read, IO#close_write, IO#closed?.
5813 */
5814
5815static VALUE
5816rb_io_close_m(VALUE io)
5817{
5818 rb_io_t *fptr = rb_io_get_fptr(io);
5819 if (fptr->fd < 0) {
5820 return Qnil;
5821 }
5822 rb_io_close(io);
5823 return Qnil;
5824}
5825
5826static VALUE
5827io_call_close(VALUE io)
5828{
5829 rb_check_funcall(io, rb_intern("close"), 0, 0);
5830 return io;
5831}
5832
5833static VALUE
5834ignore_closed_stream(VALUE io, VALUE exc)
5835{
5836 enum {mesg_len = sizeof(closed_stream)-1};
5837 VALUE mesg = rb_attr_get(exc, idMesg);
5838 if (!RB_TYPE_P(mesg, T_STRING) ||
5839 RSTRING_LEN(mesg) != mesg_len ||
5840 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5841 rb_exc_raise(exc);
5842 }
5843 return io;
5844}
5845
5846static VALUE
5847io_close(VALUE io)
5848{
5849 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5850 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5851 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5852 rb_eIOError, (VALUE)0);
5853 return io;
5854}
5855
5856/*
5857 * call-seq:
5858 * closed? -> true or false
5859 *
5860 * Returns +true+ if the stream is closed for both reading and writing,
5861 * +false+ otherwise.
5862 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5863 *
5864 * IO.popen('ruby', 'r+') do |pipe|
5865 * puts pipe.closed?
5866 * pipe.close_read
5867 * puts pipe.closed?
5868 * pipe.close_write
5869 * puts pipe.closed?
5870 * end
5871 *
5872 * Output:
5873 *
5874 * false
5875 * false
5876 * true
5877 *
5878 * Related: IO#close_read, IO#close_write, IO#close.
5879 */
5880VALUE
5882{
5883 rb_io_t *fptr;
5884 VALUE write_io;
5885 rb_io_t *write_fptr;
5886
5887 write_io = GetWriteIO(io);
5888 if (io != write_io) {
5889 write_fptr = RFILE(write_io)->fptr;
5890 if (write_fptr && 0 <= write_fptr->fd) {
5891 return Qfalse;
5892 }
5893 }
5894
5895 fptr = rb_io_get_fptr(io);
5896 return RBOOL(0 > fptr->fd);
5897}
5898
5899/*
5900 * call-seq:
5901 * close_read -> nil
5902 *
5903 * Closes the stream for reading if open for reading;
5904 * returns +nil+.
5905 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5906 *
5907 * If the stream was opened by IO.popen and is also closed for writing,
5908 * sets global variable <tt>$?</tt> (child exit status).
5909 *
5910 * Example:
5911 *
5912 * IO.popen('ruby', 'r+') do |pipe|
5913 * puts pipe.closed?
5914 * pipe.close_write
5915 * puts pipe.closed?
5916 * pipe.close_read
5917 * puts $?
5918 * puts pipe.closed?
5919 * end
5920 *
5921 * Output:
5922 *
5923 * false
5924 * false
5925 * pid 14748 exit 0
5926 * true
5927 *
5928 * Related: IO#close, IO#close_write, IO#closed?.
5929 */
5930
5931static VALUE
5932rb_io_close_read(VALUE io)
5933{
5934 rb_io_t *fptr;
5935 VALUE write_io;
5936
5937 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5938 if (fptr->fd < 0) return Qnil;
5939 if (is_socket(fptr->fd, fptr->pathv)) {
5940#ifndef SHUT_RD
5941# define SHUT_RD 0
5942#endif
5943 if (shutdown(fptr->fd, SHUT_RD) < 0)
5944 rb_sys_fail_path(fptr->pathv);
5945 fptr->mode &= ~FMODE_READABLE;
5946 if (!(fptr->mode & FMODE_WRITABLE))
5947 return rb_io_close(io);
5948 return Qnil;
5949 }
5950
5951 write_io = GetWriteIO(io);
5952 if (io != write_io) {
5953 rb_io_t *wfptr;
5954 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5955 wfptr->pid = fptr->pid;
5956 fptr->pid = 0;
5957 RFILE(io)->fptr = wfptr;
5958 /* bind to write_io temporarily to get rid of memory/fd leak */
5959 fptr->tied_io_for_writing = 0;
5960 RFILE(write_io)->fptr = fptr;
5961 rb_io_fptr_cleanup(fptr, FALSE);
5962 /* should not finalize fptr because another thread may be reading it */
5963 return Qnil;
5964 }
5965
5966 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5967 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5968 }
5969 return rb_io_close(io);
5970}
5971
5972/*
5973 * call-seq:
5974 * close_write -> nil
5975 *
5976 * Closes the stream for writing if open for writing;
5977 * returns +nil+.
5978 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5979 *
5980 * Flushes any buffered writes to the operating system before closing.
5981 *
5982 * If the stream was opened by IO.popen and is also closed for reading,
5983 * sets global variable <tt>$?</tt> (child exit status).
5984 *
5985 * IO.popen('ruby', 'r+') do |pipe|
5986 * puts pipe.closed?
5987 * pipe.close_read
5988 * puts pipe.closed?
5989 * pipe.close_write
5990 * puts $?
5991 * puts pipe.closed?
5992 * end
5993 *
5994 * Output:
5995 *
5996 * false
5997 * false
5998 * pid 15044 exit 0
5999 * true
6000 *
6001 * Related: IO#close, IO#close_read, IO#closed?.
6002 */
6003
6004static VALUE
6005rb_io_close_write(VALUE io)
6006{
6007 rb_io_t *fptr;
6008 VALUE write_io;
6009
6010 write_io = GetWriteIO(io);
6011 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6012 if (fptr->fd < 0) return Qnil;
6013 if (is_socket(fptr->fd, fptr->pathv)) {
6014#ifndef SHUT_WR
6015# define SHUT_WR 1
6016#endif
6017 if (shutdown(fptr->fd, SHUT_WR) < 0)
6018 rb_sys_fail_path(fptr->pathv);
6019 fptr->mode &= ~FMODE_WRITABLE;
6020 if (!(fptr->mode & FMODE_READABLE))
6021 return rb_io_close(write_io);
6022 return Qnil;
6023 }
6024
6025 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6026 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6027 }
6028
6029 if (io != write_io) {
6030 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6031 fptr->tied_io_for_writing = 0;
6032 }
6033 rb_io_close(write_io);
6034 return Qnil;
6035}
6036
6037/*
6038 * call-seq:
6039 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6040 *
6041 * Behaves like IO#seek, except that it:
6042 *
6043 * - Uses low-level system functions.
6044 * - Returns the new position.
6045 *
6046 */
6047
6048static VALUE
6049rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6050{
6051 VALUE offset, ptrname;
6052 int whence = SEEK_SET;
6053 rb_io_t *fptr;
6054 rb_off_t pos;
6055
6056 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6057 whence = interpret_seek_whence(ptrname);
6058 }
6059 pos = NUM2OFFT(offset);
6060 GetOpenFile(io, fptr);
6061 if ((fptr->mode & FMODE_READABLE) &&
6062 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6063 rb_raise(rb_eIOError, "sysseek for buffered IO");
6064 }
6065 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6066 rb_warn("sysseek for buffered IO");
6067 }
6068 errno = 0;
6069 pos = lseek(fptr->fd, pos, whence);
6070 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6071
6072 return OFFT2NUM(pos);
6073}
6074
6075/*
6076 * call-seq:
6077 * syswrite(object) -> integer
6078 *
6079 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6080 * returns the number bytes written.
6081 * If +object+ is not a string is converted via method to_s:
6082 *
6083 * f = File.new('t.tmp', 'w')
6084 * f.syswrite('foo') # => 3
6085 * f.syswrite(30) # => 2
6086 * f.syswrite(:foo) # => 3
6087 * f.close
6088 *
6089 * This methods should not be used with other stream-writer methods.
6090 *
6091 */
6092
6093static VALUE
6094rb_io_syswrite(VALUE io, VALUE str)
6095{
6096 VALUE tmp;
6097 rb_io_t *fptr;
6098 long n, len;
6099 const char *ptr;
6100
6101 if (!RB_TYPE_P(str, T_STRING))
6102 str = rb_obj_as_string(str);
6103
6104 io = GetWriteIO(io);
6105 GetOpenFile(io, fptr);
6107
6108 if (fptr->wbuf.len) {
6109 rb_warn("syswrite for buffered IO");
6110 }
6111
6112 tmp = rb_str_tmp_frozen_acquire(str);
6113 RSTRING_GETMEM(tmp, ptr, len);
6114 n = rb_io_write_memory(fptr, ptr, len);
6115 if (n < 0) rb_sys_fail_path(fptr->pathv);
6116 rb_str_tmp_frozen_release(str, tmp);
6117
6118 return LONG2FIX(n);
6119}
6120
6121/*
6122 * call-seq:
6123 * sysread(maxlen) -> string
6124 * sysread(maxlen, out_string) -> string
6125 *
6126 * Behaves like IO#readpartial, except that it uses low-level system functions.
6127 *
6128 * This method should not be used with other stream-reader methods.
6129 *
6130 */
6131
6132static VALUE
6133rb_io_sysread(int argc, VALUE *argv, VALUE io)
6134{
6135 VALUE len, str;
6136 rb_io_t *fptr;
6137 long n, ilen;
6138 struct io_internal_read_struct iis;
6139 int shrinkable;
6140
6141 rb_scan_args(argc, argv, "11", &len, &str);
6142 ilen = NUM2LONG(len);
6143
6144 shrinkable = io_setstrbuf(&str, ilen);
6145 if (ilen == 0) return str;
6146
6147 GetOpenFile(io, fptr);
6149
6150 if (READ_DATA_BUFFERED(fptr)) {
6151 rb_raise(rb_eIOError, "sysread for buffered IO");
6152 }
6153
6154 rb_io_check_closed(fptr);
6155
6156 io_setstrbuf(&str, ilen);
6157 iis.th = rb_thread_current();
6158 iis.fptr = fptr;
6159 iis.nonblock = 0;
6160 iis.fd = fptr->fd;
6161 iis.buf = RSTRING_PTR(str);
6162 iis.capa = ilen;
6163 iis.timeout = NULL;
6164 n = io_read_memory_locktmp(str, &iis);
6165
6166 if (n < 0) {
6167 rb_sys_fail_path(fptr->pathv);
6168 }
6169
6170 io_set_read_length(str, n, shrinkable);
6171
6172 if (n == 0 && ilen > 0) {
6173 rb_eof_error();
6174 }
6175
6176 return str;
6177}
6178
6180 struct rb_io *io;
6181 int fd;
6182 void *buf;
6183 size_t count;
6184 rb_off_t offset;
6185};
6186
6187static VALUE
6188internal_pread_func(void *_arg)
6189{
6190 struct prdwr_internal_arg *arg = _arg;
6191
6192 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6193}
6194
6195static VALUE
6196pread_internal_call(VALUE _arg)
6197{
6198 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6199
6200 VALUE scheduler = rb_fiber_scheduler_current();
6201 if (scheduler != Qnil) {
6202 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6203
6204 if (!UNDEF_P(result)) {
6206 }
6207 }
6208
6209 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6210}
6211
6212/*
6213 * call-seq:
6214 * pread(maxlen, offset) -> string
6215 * pread(maxlen, offset, out_string) -> string
6216 *
6217 * Behaves like IO#readpartial, except that it:
6218 *
6219 * - Reads at the given +offset+ (in bytes).
6220 * - Disregards, and does not modify, the stream's position
6221 * (see {Position}[rdoc-ref:IO@Position]).
6222 * - Bypasses any user space buffering in the stream.
6223 *
6224 * Because this method does not disturb the stream's state
6225 * (its position, in particular), +pread+ allows multiple threads and processes
6226 * to use the same \IO object for reading at various offsets.
6227 *
6228 * f = File.open('t.txt')
6229 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6230 * f.pos # => 52
6231 * # Read 12 bytes at offset 0.
6232 * f.pread(12, 0) # => "First line\n"
6233 * # Read 9 bytes at offset 8.
6234 * f.pread(9, 8) # => "ne\nSecon"
6235 * f.close
6236 *
6237 * Not available on some platforms.
6238 *
6239 */
6240static VALUE
6241rb_io_pread(int argc, VALUE *argv, VALUE io)
6242{
6243 VALUE len, offset, str;
6244 rb_io_t *fptr;
6245 ssize_t n;
6246 struct prdwr_internal_arg arg;
6247 int shrinkable;
6248
6249 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6250 arg.count = NUM2SIZET(len);
6251 arg.offset = NUM2OFFT(offset);
6252
6253 shrinkable = io_setstrbuf(&str, (long)arg.count);
6254 if (arg.count == 0) return str;
6255 arg.buf = RSTRING_PTR(str);
6256
6257 GetOpenFile(io, fptr);
6259
6260 arg.io = fptr;
6261 arg.fd = fptr->fd;
6262 rb_io_check_closed(fptr);
6263
6264 rb_str_locktmp(str);
6265 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6266
6267 if (n < 0) {
6268 rb_sys_fail_path(fptr->pathv);
6269 }
6270 io_set_read_length(str, n, shrinkable);
6271 if (n == 0 && arg.count > 0) {
6272 rb_eof_error();
6273 }
6274
6275 return str;
6276}
6277
6278static VALUE
6279internal_pwrite_func(void *_arg)
6280{
6281 struct prdwr_internal_arg *arg = _arg;
6282
6283 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6284}
6285
6286static VALUE
6287pwrite_internal_call(VALUE _arg)
6288{
6289 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6290
6291 VALUE scheduler = rb_fiber_scheduler_current();
6292 if (scheduler != Qnil) {
6293 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6294
6295 if (!UNDEF_P(result)) {
6297 }
6298 }
6299
6300 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
6301}
6302
6303/*
6304 * call-seq:
6305 * pwrite(object, offset) -> integer
6306 *
6307 * Behaves like IO#write, except that it:
6308 *
6309 * - Writes at the given +offset+ (in bytes).
6310 * - Disregards, and does not modify, the stream's position
6311 * (see {Position}[rdoc-ref:IO@Position]).
6312 * - Bypasses any user space buffering in the stream.
6313 *
6314 * Because this method does not disturb the stream's state
6315 * (its position, in particular), +pwrite+ allows multiple threads and processes
6316 * to use the same \IO object for writing at various offsets.
6317 *
6318 * f = File.open('t.tmp', 'w+')
6319 * # Write 6 bytes at offset 3.
6320 * f.pwrite('ABCDEF', 3) # => 6
6321 * f.rewind
6322 * f.read # => "\u0000\u0000\u0000ABCDEF"
6323 * f.close
6324 *
6325 * Not available on some platforms.
6326 *
6327 */
6328static VALUE
6329rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6330{
6331 rb_io_t *fptr;
6332 ssize_t n;
6333 struct prdwr_internal_arg arg;
6334 VALUE tmp;
6335
6336 if (!RB_TYPE_P(str, T_STRING))
6337 str = rb_obj_as_string(str);
6338
6339 arg.offset = NUM2OFFT(offset);
6340
6341 io = GetWriteIO(io);
6342 GetOpenFile(io, fptr);
6344
6345 arg.io = fptr;
6346 arg.fd = fptr->fd;
6347
6348 tmp = rb_str_tmp_frozen_acquire(str);
6349 arg.buf = RSTRING_PTR(tmp);
6350 arg.count = (size_t)RSTRING_LEN(tmp);
6351
6352 n = (ssize_t)pwrite_internal_call((VALUE)&arg);
6353 if (n < 0) rb_sys_fail_path(fptr->pathv);
6354 rb_str_tmp_frozen_release(str, tmp);
6355
6356 return SSIZET2NUM(n);
6357}
6358
6359VALUE
6361{
6362 rb_io_t *fptr;
6363
6364 GetOpenFile(io, fptr);
6365 if (fptr->readconv)
6367 if (fptr->writeconv)
6369 fptr->mode |= FMODE_BINMODE;
6370 fptr->mode &= ~FMODE_TEXTMODE;
6372#ifdef O_BINARY
6373 if (!fptr->readconv) {
6374 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6375 }
6376 else {
6377 setmode(fptr->fd, O_BINARY);
6378 }
6379#endif
6380 return io;
6381}
6382
6383static void
6384io_ascii8bit_binmode(rb_io_t *fptr)
6385{
6386 if (fptr->readconv) {
6387 rb_econv_close(fptr->readconv);
6388 fptr->readconv = NULL;
6389 }
6390 if (fptr->writeconv) {
6392 fptr->writeconv = NULL;
6393 }
6394 fptr->mode |= FMODE_BINMODE;
6395 fptr->mode &= ~FMODE_TEXTMODE;
6396 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6397
6398 fptr->encs.enc = rb_ascii8bit_encoding();
6399 fptr->encs.enc2 = NULL;
6400 fptr->encs.ecflags = 0;
6401 fptr->encs.ecopts = Qnil;
6402 clear_codeconv(fptr);
6403}
6404
6405VALUE
6407{
6408 rb_io_t *fptr;
6409
6410 GetOpenFile(io, fptr);
6411 io_ascii8bit_binmode(fptr);
6412
6413 return io;
6414}
6415
6416/*
6417 * call-seq:
6418 * binmode -> self
6419 *
6420 * Sets the stream's data mode as binary
6421 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6422 *
6423 * A stream's data mode may not be changed from binary to text.
6424 *
6425 */
6426
6427static VALUE
6428rb_io_binmode_m(VALUE io)
6429{
6430 VALUE write_io;
6431
6433
6434 write_io = GetWriteIO(io);
6435 if (write_io != io)
6436 rb_io_ascii8bit_binmode(write_io);
6437 return io;
6438}
6439
6440/*
6441 * call-seq:
6442 * binmode? -> true or false
6443 *
6444 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6445 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6446 *
6447 */
6448static VALUE
6449rb_io_binmode_p(VALUE io)
6450{
6451 rb_io_t *fptr;
6452 GetOpenFile(io, fptr);
6453 return RBOOL(fptr->mode & FMODE_BINMODE);
6454}
6455
6456static const char*
6457rb_io_fmode_modestr(enum rb_io_mode fmode)
6458{
6459 if (fmode & FMODE_APPEND) {
6460 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6461 return MODE_BTMODE("a+", "ab+", "at+");
6462 }
6463 return MODE_BTMODE("a", "ab", "at");
6464 }
6465 switch (fmode & FMODE_READWRITE) {
6466 default:
6467 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6468 case FMODE_READABLE:
6469 return MODE_BTMODE("r", "rb", "rt");
6470 case FMODE_WRITABLE:
6471 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6472 case FMODE_READWRITE:
6473 if (fmode & FMODE_CREATE) {
6474 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6475 }
6476 return MODE_BTMODE("r+", "rb+", "rt+");
6477 }
6478}
6479
6480static const char bom_prefix[] = "bom|";
6481static const char utf_prefix[] = "utf-";
6482enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6483enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6484
6485static int
6486io_encname_bom_p(const char *name, long len)
6487{
6488 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6489}
6490
6491enum rb_io_mode
6492rb_io_modestr_fmode(const char *modestr)
6493{
6494 enum rb_io_mode fmode = 0;
6495 const char *m = modestr, *p = NULL;
6496
6497 switch (*m++) {
6498 case 'r':
6499 fmode |= FMODE_READABLE;
6500 break;
6501 case 'w':
6503 break;
6504 case 'a':
6506 break;
6507 default:
6508 goto error;
6509 }
6510
6511 while (*m) {
6512 switch (*m++) {
6513 case 'b':
6514 fmode |= FMODE_BINMODE;
6515 break;
6516 case 't':
6517 fmode |= FMODE_TEXTMODE;
6518 break;
6519 case '+':
6520 fmode |= FMODE_READWRITE;
6521 break;
6522 case 'x':
6523 if (modestr[0] != 'w')
6524 goto error;
6525 fmode |= FMODE_EXCL;
6526 break;
6527 default:
6528 goto error;
6529 case ':':
6530 p = strchr(m, ':');
6531 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6532 fmode |= FMODE_SETENC_BY_BOM;
6533 goto finished;
6534 }
6535 }
6536
6537 finished:
6538 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6539 goto error;
6540
6541 return fmode;
6542
6543 error:
6544 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6546}
6547
6548int
6550{
6551 enum rb_io_mode fmode = 0;
6552
6553 switch (oflags & O_ACCMODE) {
6554 case O_RDONLY:
6555 fmode = FMODE_READABLE;
6556 break;
6557 case O_WRONLY:
6558 fmode = FMODE_WRITABLE;
6559 break;
6560 case O_RDWR:
6561 fmode = FMODE_READWRITE;
6562 break;
6563 }
6564
6565 if (oflags & O_APPEND) {
6566 fmode |= FMODE_APPEND;
6567 }
6568 if (oflags & O_TRUNC) {
6569 fmode |= FMODE_TRUNC;
6570 }
6571 if (oflags & O_CREAT) {
6572 fmode |= FMODE_CREATE;
6573 }
6574 if (oflags & O_EXCL) {
6575 fmode |= FMODE_EXCL;
6576 }
6577#ifdef O_BINARY
6578 if (oflags & O_BINARY) {
6579 fmode |= FMODE_BINMODE;
6580 }
6581#endif
6582
6583 return fmode;
6584}
6585
6586static int
6587rb_io_fmode_oflags(enum rb_io_mode fmode)
6588{
6589 int oflags = 0;
6590
6591 switch (fmode & FMODE_READWRITE) {
6592 case FMODE_READABLE:
6593 oflags |= O_RDONLY;
6594 break;
6595 case FMODE_WRITABLE:
6596 oflags |= O_WRONLY;
6597 break;
6598 case FMODE_READWRITE:
6599 oflags |= O_RDWR;
6600 break;
6601 }
6602
6603 if (fmode & FMODE_APPEND) {
6604 oflags |= O_APPEND;
6605 }
6606 if (fmode & FMODE_TRUNC) {
6607 oflags |= O_TRUNC;
6608 }
6609 if (fmode & FMODE_CREATE) {
6610 oflags |= O_CREAT;
6611 }
6612 if (fmode & FMODE_EXCL) {
6613 oflags |= O_EXCL;
6614 }
6615#ifdef O_BINARY
6616 if (fmode & FMODE_BINMODE) {
6617 oflags |= O_BINARY;
6618 }
6619#endif
6620
6621 return oflags;
6622}
6623
6624int
6625rb_io_modestr_oflags(const char *modestr)
6626{
6627 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6628}
6629
6630static const char*
6631rb_io_oflags_modestr(int oflags)
6632{
6633#ifdef O_BINARY
6634# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6635#else
6636# define MODE_BINARY(a,b) (a)
6637#endif
6638 int accmode;
6639 if (oflags & O_EXCL) {
6640 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6641 }
6642 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6643 if (oflags & O_APPEND) {
6644 if (accmode == O_WRONLY) {
6645 return MODE_BINARY("a", "ab");
6646 }
6647 if (accmode == O_RDWR) {
6648 return MODE_BINARY("a+", "ab+");
6649 }
6650 }
6651 switch (accmode) {
6652 default:
6653 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6654 case O_RDONLY:
6655 return MODE_BINARY("r", "rb");
6656 case O_WRONLY:
6657 return MODE_BINARY("w", "wb");
6658 case O_RDWR:
6659 if (oflags & O_TRUNC) {
6660 return MODE_BINARY("w+", "wb+");
6661 }
6662 return MODE_BINARY("r+", "rb+");
6663 }
6664}
6665
6666/*
6667 * Convert external/internal encodings to enc/enc2
6668 * NULL => use default encoding
6669 * Qnil => no encoding specified (internal only)
6670 */
6671static void
6672rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6673{
6674 int default_ext = 0;
6675
6676 if (ext == NULL) {
6678 default_ext = 1;
6679 }
6680 if (rb_is_ascii8bit_enc(ext)) {
6681 /* If external is ASCII-8BIT, no transcoding */
6682 intern = NULL;
6683 }
6684 else if (intern == NULL) {
6686 }
6687 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6688 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6689 /* No internal encoding => use external + no transcoding */
6690 *enc = (default_ext && intern != ext) ? NULL : ext;
6691 *enc2 = NULL;
6692 }
6693 else {
6694 *enc = intern;
6695 *enc2 = ext;
6696 }
6697}
6698
6699static void
6700unsupported_encoding(const char *name, rb_encoding *enc)
6701{
6702 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6703}
6704
6705static void
6706parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6707 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6708{
6709 const char *p;
6710 char encname[ENCODING_MAXNAMELEN+1];
6711 int idx, idx2;
6712 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6713 rb_encoding *ext_enc, *int_enc;
6714 long len;
6715
6716 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6717
6718 p = strrchr(estr, ':');
6719 len = p ? (p++ - estr) : (long)strlen(estr);
6720 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6721 estr += bom_prefix_len;
6722 len -= bom_prefix_len;
6723 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6724 fmode |= FMODE_SETENC_BY_BOM;
6725 }
6726 else {
6727 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6728 fmode &= ~FMODE_SETENC_BY_BOM;
6729 }
6730 }
6731 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6732 idx = -1;
6733 }
6734 else {
6735 if (p) {
6736 memcpy(encname, estr, len);
6737 encname[len] = '\0';
6738 estr = encname;
6739 }
6740 idx = rb_enc_find_index(estr);
6741 }
6742 if (fmode_p) *fmode_p = fmode;
6743
6744 if (idx >= 0)
6745 ext_enc = rb_enc_from_index(idx);
6746 else {
6747 if (idx != -2)
6748 unsupported_encoding(estr, estr_enc);
6749 ext_enc = NULL;
6750 }
6751
6752 int_enc = NULL;
6753 if (p) {
6754 if (*p == '-' && *(p+1) == '\0') {
6755 /* Special case - "-" => no transcoding */
6756 int_enc = (rb_encoding *)Qnil;
6757 }
6758 else {
6759 idx2 = rb_enc_find_index(p);
6760 if (idx2 < 0)
6761 unsupported_encoding(p, estr_enc);
6762 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6763 int_enc = (rb_encoding *)Qnil;
6764 }
6765 else
6766 int_enc = rb_enc_from_index(idx2);
6767 }
6768 }
6769
6770 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6771}
6772
6773int
6774rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6775{
6776 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6777 int extracted = 0;
6778 rb_encoding *extencoding = NULL;
6779 rb_encoding *intencoding = NULL;
6780
6781 if (!NIL_P(opt)) {
6782 VALUE v;
6783 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6784 if (v != Qnil) encoding = v;
6785 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6786 if (v != Qnil) extenc = v;
6787 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6788 if (!UNDEF_P(v)) intenc = v;
6789 }
6790 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6791 if (!NIL_P(ruby_verbose)) {
6792 int idx = rb_to_encoding_index(encoding);
6793 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6794 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6795 encoding, UNDEF_P(extenc) ? "internal" : "external");
6796 }
6797 encoding = Qnil;
6798 }
6799 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6800 extencoding = rb_to_encoding(extenc);
6801 }
6802 if (!UNDEF_P(intenc)) {
6803 if (NIL_P(intenc)) {
6804 /* internal_encoding: nil => no transcoding */
6805 intencoding = (rb_encoding *)Qnil;
6806 }
6807 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6808 char *p = StringValueCStr(tmp);
6809
6810 if (*p == '-' && *(p+1) == '\0') {
6811 /* Special case - "-" => no transcoding */
6812 intencoding = (rb_encoding *)Qnil;
6813 }
6814 else {
6815 intencoding = rb_to_encoding(intenc);
6816 }
6817 }
6818 else {
6819 intencoding = rb_to_encoding(intenc);
6820 }
6821 if (extencoding == intencoding) {
6822 intencoding = (rb_encoding *)Qnil;
6823 }
6824 }
6825 if (!NIL_P(encoding)) {
6826 extracted = 1;
6827 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6828 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6829 enc_p, enc2_p, fmode_p);
6830 }
6831 else {
6832 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6833 }
6834 }
6835 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6836 extracted = 1;
6837 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6838 }
6839 return extracted;
6840}
6841
6842static void
6843validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6844{
6845 enum rb_io_mode fmode = *fmode_p;
6846
6847 if ((fmode & FMODE_READABLE) &&
6848 !enc2 &&
6849 !(fmode & FMODE_BINMODE) &&
6850 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6851 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6852
6853 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6854 rb_raise(rb_eArgError, "newline decorator with binary mode");
6855 }
6856 if (!(fmode & FMODE_BINMODE) &&
6857 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6858 fmode |= FMODE_TEXTMODE;
6859 *fmode_p = fmode;
6860 }
6861#if !DEFAULT_TEXTMODE
6862 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6863 fmode &= ~FMODE_TEXTMODE;
6864 *fmode_p = fmode;
6865 }
6866#endif
6867}
6868
6869static void
6870extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
6871{
6872 if (!NIL_P(opthash)) {
6873 VALUE v;
6874 v = rb_hash_aref(opthash, sym_textmode);
6875 if (!NIL_P(v)) {
6876 if (*fmode & FMODE_TEXTMODE)
6877 rb_raise(rb_eArgError, "textmode specified twice");
6878 if (*fmode & FMODE_BINMODE)
6879 rb_raise(rb_eArgError, "both textmode and binmode specified");
6880 if (RTEST(v))
6881 *fmode |= FMODE_TEXTMODE;
6882 }
6883 v = rb_hash_aref(opthash, sym_binmode);
6884 if (!NIL_P(v)) {
6885 if (*fmode & FMODE_BINMODE)
6886 rb_raise(rb_eArgError, "binmode specified twice");
6887 if (*fmode & FMODE_TEXTMODE)
6888 rb_raise(rb_eArgError, "both textmode and binmode specified");
6889 if (RTEST(v))
6890 *fmode |= FMODE_BINMODE;
6891 }
6892
6893 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6894 rb_raise(rb_eArgError, "both textmode and binmode specified");
6895 }
6896}
6897
6898void
6899rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6900 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
6901{
6902 VALUE vmode;
6903 int oflags;
6904 enum rb_io_mode fmode;
6905 rb_encoding *enc, *enc2;
6906 int ecflags;
6907 VALUE ecopts;
6908 int has_enc = 0, has_vmode = 0;
6909 VALUE intmode;
6910
6911 vmode = *vmode_p;
6912
6913 /* Set to defaults */
6914 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6915
6916 vmode_handle:
6917 if (NIL_P(vmode)) {
6918 fmode = FMODE_READABLE;
6919 oflags = O_RDONLY;
6920 }
6921 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6922 vmode = intmode;
6923 oflags = NUM2INT(intmode);
6924 fmode = rb_io_oflags_fmode(oflags);
6925 }
6926 else {
6927 const char *p;
6928
6929 StringValue(vmode);
6930 p = StringValueCStr(vmode);
6931 fmode = rb_io_modestr_fmode(p);
6932 oflags = rb_io_fmode_oflags(fmode);
6933 p = strchr(p, ':');
6934 if (p) {
6935 has_enc = 1;
6936 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6937 }
6938 else {
6939 rb_encoding *e;
6940
6941 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6942 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6943 }
6944 }
6945
6946 if (NIL_P(opthash)) {
6947 ecflags = (fmode & FMODE_READABLE) ?
6950#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6951 ecflags |= (fmode & FMODE_WRITABLE) ?
6952 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6953 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6954#endif
6955 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6956 ecopts = Qnil;
6957 if (fmode & FMODE_BINMODE) {
6958#ifdef O_BINARY
6959 oflags |= O_BINARY;
6960#endif
6961 if (!has_enc)
6962 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6963 }
6964#if DEFAULT_TEXTMODE
6965 else if (NIL_P(vmode)) {
6966 fmode |= DEFAULT_TEXTMODE;
6967 }
6968#endif
6969 }
6970 else {
6971 VALUE v;
6972 if (!has_vmode) {
6973 v = rb_hash_aref(opthash, sym_mode);
6974 if (!NIL_P(v)) {
6975 if (!NIL_P(vmode)) {
6976 rb_raise(rb_eArgError, "mode specified twice");
6977 }
6978 has_vmode = 1;
6979 vmode = v;
6980 goto vmode_handle;
6981 }
6982 }
6983 v = rb_hash_aref(opthash, sym_flags);
6984 if (!NIL_P(v)) {
6985 v = rb_to_int(v);
6986 oflags |= NUM2INT(v);
6987 vmode = INT2NUM(oflags);
6988 fmode = rb_io_oflags_fmode(oflags);
6989 }
6990 extract_binmode(opthash, &fmode);
6991 if (fmode & FMODE_BINMODE) {
6992#ifdef O_BINARY
6993 oflags |= O_BINARY;
6994#endif
6995 if (!has_enc)
6996 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6997 }
6998#if DEFAULT_TEXTMODE
6999 else if (NIL_P(vmode)) {
7000 fmode |= DEFAULT_TEXTMODE;
7001 }
7002#endif
7003 v = rb_hash_aref(opthash, sym_perm);
7004 if (!NIL_P(v)) {
7005 if (vperm_p) {
7006 if (!NIL_P(*vperm_p)) {
7007 rb_raise(rb_eArgError, "perm specified twice");
7008 }
7009 *vperm_p = v;
7010 }
7011 else {
7012 /* perm no use, just ignore */
7013 }
7014 }
7015 ecflags = (fmode & FMODE_READABLE) ?
7018#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7019 ecflags |= (fmode & FMODE_WRITABLE) ?
7020 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7021 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7022#endif
7023
7024 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7025 if (has_enc) {
7026 rb_raise(rb_eArgError, "encoding specified twice");
7027 }
7028 }
7029 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7030 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7031 }
7032
7033 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7034
7035 *vmode_p = vmode;
7036
7037 *oflags_p = oflags;
7038 *fmode_p = fmode;
7039 convconfig_p->enc = enc;
7040 convconfig_p->enc2 = enc2;
7041 convconfig_p->ecflags = ecflags;
7042 convconfig_p->ecopts = ecopts;
7043}
7044
7046 VALUE fname;
7047 int oflags;
7048 mode_t perm;
7049};
7050
7051static void *
7052sysopen_func(void *ptr)
7053{
7054 const struct sysopen_struct *data = ptr;
7055 const char *fname = RSTRING_PTR(data->fname);
7056 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7057}
7058
7059static inline int
7060rb_sysopen_internal(struct sysopen_struct *data)
7061{
7062 int fd;
7063 do {
7064 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7065 } while (fd < 0 && errno == EINTR);
7066 if (0 <= fd)
7067 rb_update_max_fd(fd);
7068 return fd;
7069}
7070
7071static int
7072rb_sysopen(VALUE fname, int oflags, mode_t perm)
7073{
7074 int fd = -1;
7075 struct sysopen_struct data;
7076
7077 data.fname = rb_str_encode_ospath(fname);
7078 StringValueCStr(data.fname);
7079 data.oflags = oflags;
7080 data.perm = perm;
7081
7082 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7083 rb_syserr_fail_path(first_errno, fname);
7084 }
7085 return fd;
7086}
7087
7088static inline FILE *
7089fdopen_internal(int fd, const char *modestr)
7090{
7091 FILE *file;
7092
7093#if defined(__sun)
7094 errno = 0;
7095#endif
7096 file = fdopen(fd, modestr);
7097 if (!file) {
7098#ifdef _WIN32
7099 if (errno == 0) errno = EINVAL;
7100#elif defined(__sun)
7101 if (errno == 0) errno = EMFILE;
7102#endif
7103 }
7104 return file;
7105}
7106
7107FILE *
7108rb_fdopen(int fd, const char *modestr)
7109{
7110 FILE *file = 0;
7111
7112 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7113 rb_syserr_fail(first_errno, 0);
7114 }
7115
7116 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7117#ifdef USE_SETVBUF
7118 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7119 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7120#endif
7121 return file;
7122}
7123
7124static int
7125io_check_tty(rb_io_t *fptr)
7126{
7127 int t = isatty(fptr->fd);
7128 if (t)
7129 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7130 return t;
7131}
7132
7133static VALUE rb_io_internal_encoding(VALUE);
7134static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7135
7136static int
7137io_strip_bom(VALUE io)
7138{
7139 VALUE b1, b2, b3, b4;
7140 rb_io_t *fptr;
7141
7142 GetOpenFile(io, fptr);
7143 if (!(fptr->mode & FMODE_READABLE)) return 0;
7144 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7145 switch (b1) {
7146 case INT2FIX(0xEF):
7147 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7148 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7149 if (b3 == INT2FIX(0xBF)) {
7150 return rb_utf8_encindex();
7151 }
7152 rb_io_ungetbyte(io, b3);
7153 }
7154 rb_io_ungetbyte(io, b2);
7155 break;
7156
7157 case INT2FIX(0xFE):
7158 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7159 if (b2 == INT2FIX(0xFF)) {
7160 return ENCINDEX_UTF_16BE;
7161 }
7162 rb_io_ungetbyte(io, b2);
7163 break;
7164
7165 case INT2FIX(0xFF):
7166 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7167 if (b2 == INT2FIX(0xFE)) {
7168 b3 = rb_io_getbyte(io);
7169 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7170 if (b4 == INT2FIX(0)) {
7171 return ENCINDEX_UTF_32LE;
7172 }
7173 rb_io_ungetbyte(io, b4);
7174 }
7175 rb_io_ungetbyte(io, b3);
7176 return ENCINDEX_UTF_16LE;
7177 }
7178 rb_io_ungetbyte(io, b2);
7179 break;
7180
7181 case INT2FIX(0):
7182 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7183 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7184 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7185 if (b4 == INT2FIX(0xFF)) {
7186 return ENCINDEX_UTF_32BE;
7187 }
7188 rb_io_ungetbyte(io, b4);
7189 }
7190 rb_io_ungetbyte(io, b3);
7191 }
7192 rb_io_ungetbyte(io, b2);
7193 break;
7194 }
7195 rb_io_ungetbyte(io, b1);
7196 return 0;
7197}
7198
7199static rb_encoding *
7200io_set_encoding_by_bom(VALUE io)
7201{
7202 int idx = io_strip_bom(io);
7203 rb_io_t *fptr;
7204 rb_encoding *extenc = NULL;
7205
7206 GetOpenFile(io, fptr);
7207 if (idx) {
7208 extenc = rb_enc_from_index(idx);
7209 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7210 rb_io_internal_encoding(io), Qnil);
7211 }
7212 else {
7213 fptr->encs.enc2 = NULL;
7214 }
7215 return extenc;
7216}
7217
7218static VALUE
7219rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7220 const struct rb_io_encoding *convconfig, mode_t perm)
7221{
7222 VALUE pathv;
7223 rb_io_t *fptr;
7224 struct rb_io_encoding cc;
7225 if (!convconfig) {
7226 /* Set to default encodings */
7227 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7228 cc.ecflags = 0;
7229 cc.ecopts = Qnil;
7230 convconfig = &cc;
7231 }
7232 validate_enc_binmode(&fmode, convconfig->ecflags,
7233 convconfig->enc, convconfig->enc2);
7234
7235 MakeOpenFile(io, fptr);
7236 fptr->mode = fmode;
7237 fptr->encs = *convconfig;
7238 pathv = rb_str_new_frozen(filename);
7239#ifdef O_TMPFILE
7240 if (!(oflags & O_TMPFILE)) {
7241 fptr->pathv = pathv;
7242 }
7243#else
7244 fptr->pathv = pathv;
7245#endif
7246 fptr->fd = rb_sysopen(pathv, oflags, perm);
7247 io_check_tty(fptr);
7248 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7249
7250 return io;
7251}
7252
7253static VALUE
7254rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7255{
7256 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7257 const char *p = strchr(modestr, ':');
7258 struct rb_io_encoding convconfig;
7259
7260 if (p) {
7261 parse_mode_enc(p+1, rb_usascii_encoding(),
7262 &convconfig.enc, &convconfig.enc2, &fmode);
7263 }
7264 else {
7265 rb_encoding *e;
7266 /* Set to default encodings */
7267
7268 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7269 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7270 }
7271
7272 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7275#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7276 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7277 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7278 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7279#endif
7280 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7281 convconfig.ecopts = Qnil;
7282
7283 return rb_file_open_generic(io, filename,
7284 rb_io_fmode_oflags(fmode),
7285 fmode,
7286 &convconfig,
7287 0666);
7288}
7289
7290VALUE
7291rb_file_open_str(VALUE fname, const char *modestr)
7292{
7293 FilePathValue(fname);
7294 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7295}
7296
7297VALUE
7298rb_file_open(const char *fname, const char *modestr)
7299{
7300 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7301}
7302
7303#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7304static struct pipe_list {
7305 rb_io_t *fptr;
7306 struct pipe_list *next;
7307} *pipe_list;
7308
7309static void
7310pipe_add_fptr(rb_io_t *fptr)
7311{
7312 struct pipe_list *list;
7313
7314 list = ALLOC(struct pipe_list);
7315 list->fptr = fptr;
7316 list->next = pipe_list;
7317 pipe_list = list;
7318}
7319
7320static void
7321pipe_del_fptr(rb_io_t *fptr)
7322{
7323 struct pipe_list **prev = &pipe_list;
7324 struct pipe_list *tmp;
7325
7326 while ((tmp = *prev) != 0) {
7327 if (tmp->fptr == fptr) {
7328 *prev = tmp->next;
7329 free(tmp);
7330 return;
7331 }
7332 prev = &tmp->next;
7333 }
7334}
7335
7336#if defined (_WIN32) || defined(__CYGWIN__)
7337static void
7338pipe_atexit(void)
7339{
7340 struct pipe_list *list = pipe_list;
7341 struct pipe_list *tmp;
7342
7343 while (list) {
7344 tmp = list->next;
7345 rb_io_fptr_finalize(list->fptr);
7346 list = tmp;
7347 }
7348}
7349#endif
7350
7351static void
7352pipe_finalize(rb_io_t *fptr, int noraise)
7353{
7354#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7355 int status = 0;
7356 if (fptr->stdio_file) {
7357 status = pclose(fptr->stdio_file);
7358 }
7359 fptr->fd = -1;
7360 fptr->stdio_file = 0;
7361 rb_last_status_set(status, fptr->pid);
7362#else
7363 fptr_finalize(fptr, noraise);
7364#endif
7365 pipe_del_fptr(fptr);
7366}
7367#endif
7368
7369static void
7370fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7371{
7372#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7373 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7374
7375 if (old_finalize == orig->finalize) return;
7376#endif
7377
7378 fptr->finalize = orig->finalize;
7379
7380#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7381 if (old_finalize != pipe_finalize) {
7382 struct pipe_list *list;
7383 for (list = pipe_list; list; list = list->next) {
7384 if (list->fptr == fptr) break;
7385 }
7386 if (!list) pipe_add_fptr(fptr);
7387 }
7388 else {
7389 pipe_del_fptr(fptr);
7390 }
7391#endif
7392}
7393
7394void
7396{
7398 fptr->mode |= FMODE_SYNC;
7399}
7400
7401void
7402rb_io_unbuffered(rb_io_t *fptr)
7403{
7404 rb_io_synchronized(fptr);
7405}
7406
7407int
7408rb_pipe(int *pipes)
7409{
7410 int ret;
7411 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7412 if (ret == 0) {
7413 rb_update_max_fd(pipes[0]);
7414 rb_update_max_fd(pipes[1]);
7415 }
7416 return ret;
7417}
7418
7419#ifdef _WIN32
7420#define HAVE_SPAWNV 1
7421#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7422#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7423#endif
7424
7425#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7426struct popen_arg {
7427 VALUE execarg_obj;
7428 struct rb_execarg *eargp;
7429 int modef;
7430 int pair[2];
7431 int write_pair[2];
7432};
7433#endif
7434
7435#ifdef HAVE_WORKING_FORK
7436# ifndef __EMSCRIPTEN__
7437static void
7438popen_redirect(struct popen_arg *p)
7439{
7440 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7441 close(p->write_pair[1]);
7442 if (p->write_pair[0] != 0) {
7443 dup2(p->write_pair[0], 0);
7444 close(p->write_pair[0]);
7445 }
7446 close(p->pair[0]);
7447 if (p->pair[1] != 1) {
7448 dup2(p->pair[1], 1);
7449 close(p->pair[1]);
7450 }
7451 }
7452 else if (p->modef & FMODE_READABLE) {
7453 close(p->pair[0]);
7454 if (p->pair[1] != 1) {
7455 dup2(p->pair[1], 1);
7456 close(p->pair[1]);
7457 }
7458 }
7459 else {
7460 close(p->pair[1]);
7461 if (p->pair[0] != 0) {
7462 dup2(p->pair[0], 0);
7463 close(p->pair[0]);
7464 }
7465 }
7466}
7467# endif
7468
7469#if defined(__linux__)
7470/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7471 * Since /proc may not be available, linux_get_maxfd is just a hint.
7472 * This function, linux_get_maxfd, must be async-signal-safe.
7473 * I.e. opendir() is not usable.
7474 *
7475 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7476 * However they are easy to re-implement in async-signal-safe manner.
7477 * (Also note that there is missing/memcmp.c.)
7478 */
7479static int
7480linux_get_maxfd(void)
7481{
7482 int fd;
7483 char buf[4096], *p, *np, *e;
7484 ssize_t ss;
7485 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7486 if (fd < 0) return fd;
7487 ss = read(fd, buf, sizeof(buf));
7488 if (ss < 0) goto err;
7489 p = buf;
7490 e = buf + ss;
7491 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7492 (np = memchr(p, '\n', e-p)) != NULL) {
7493 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7494 int fdsize;
7495 p += sizeof("FDSize:")-1;
7496 *np = '\0';
7497 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7498 close(fd);
7499 return fdsize;
7500 }
7501 p = np+1;
7502 }
7503 /* fall through */
7504
7505 err:
7506 close(fd);
7507 return (int)ss;
7508}
7509#endif
7510
7511/* This function should be async-signal-safe. */
7512void
7513rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7514{
7515#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7516 int fd, ret;
7517 int max = (int)max_file_descriptor;
7518# ifdef F_MAXFD
7519 /* F_MAXFD is available since NetBSD 2.0. */
7520 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7521 if (ret != -1)
7522 maxhint = max = ret;
7523# elif defined(__linux__)
7524 ret = linux_get_maxfd();
7525 if (maxhint < ret)
7526 maxhint = ret;
7527 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7528# endif
7529 if (max < maxhint)
7530 max = maxhint;
7531 for (fd = lowfd; fd <= max; fd++) {
7532 if (!NIL_P(noclose_fds) &&
7533 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7534 continue;
7535 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7536 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7537 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7538 }
7539# define CONTIGUOUS_CLOSED_FDS 20
7540 if (ret != -1) {
7541 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7542 max = fd + CONTIGUOUS_CLOSED_FDS;
7543 }
7544 }
7545#endif
7546}
7547
7548# ifndef __EMSCRIPTEN__
7549static int
7550popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7551{
7552 struct popen_arg *p = (struct popen_arg*)pp;
7553
7554 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7555}
7556# endif
7557#endif
7558
7559#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7560static VALUE
7561rb_execarg_fixup_v(VALUE execarg_obj)
7562{
7563 rb_execarg_parent_start(execarg_obj);
7564 return Qnil;
7565}
7566#else
7567char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7568#endif
7569
7570#ifndef __EMSCRIPTEN__
7571static VALUE
7572pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7573 const struct rb_io_encoding *convconfig)
7574{
7575 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7576 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7577 rb_pid_t pid = 0;
7578 rb_io_t *fptr;
7579 VALUE port;
7580 rb_io_t *write_fptr;
7581 VALUE write_port;
7582#if defined(HAVE_WORKING_FORK)
7583 int status;
7584 char errmsg[80] = { '\0' };
7585#endif
7586#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7587 int state;
7588 struct popen_arg arg;
7589#endif
7590 int e = 0;
7591#if defined(HAVE_SPAWNV)
7592# if defined(HAVE_SPAWNVE)
7593# define DO_SPAWN(cmd, args, envp) ((args) ? \
7594 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7595 spawne(P_NOWAIT, (cmd), (envp)))
7596# else
7597# define DO_SPAWN(cmd, args, envp) ((args) ? \
7598 spawnv(P_NOWAIT, (cmd), (args)) : \
7599 spawn(P_NOWAIT, (cmd)))
7600# endif
7601# if !defined(HAVE_WORKING_FORK)
7602 char **args = NULL;
7603# if defined(HAVE_SPAWNVE)
7604 char **envp = NULL;
7605# endif
7606# endif
7607#endif
7608#if !defined(HAVE_WORKING_FORK)
7609 struct rb_execarg sarg, *sargp = &sarg;
7610#endif
7611 FILE *fp = 0;
7612 int fd = -1;
7613 int write_fd = -1;
7614#if !defined(HAVE_WORKING_FORK)
7615 const char *cmd = 0;
7616
7617 if (prog)
7618 cmd = StringValueCStr(prog);
7619#endif
7620
7621#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7622 arg.execarg_obj = execarg_obj;
7623 arg.eargp = eargp;
7624 arg.modef = fmode;
7625 arg.pair[0] = arg.pair[1] = -1;
7626 arg.write_pair[0] = arg.write_pair[1] = -1;
7627# if !defined(HAVE_WORKING_FORK)
7628 if (eargp && !eargp->use_shell) {
7629 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7630 }
7631# endif
7632 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7634 if (rb_pipe(arg.write_pair) < 0)
7635 rb_sys_fail_str(prog);
7636 if (rb_pipe(arg.pair) < 0) {
7637 e = errno;
7638 close(arg.write_pair[0]);
7639 close(arg.write_pair[1]);
7640 rb_syserr_fail_str(e, prog);
7641 }
7642 if (eargp) {
7643 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7644 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7645 }
7646 break;
7647 case FMODE_READABLE:
7648 if (rb_pipe(arg.pair) < 0)
7649 rb_sys_fail_str(prog);
7650 if (eargp)
7651 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7652 break;
7653 case FMODE_WRITABLE:
7654 if (rb_pipe(arg.pair) < 0)
7655 rb_sys_fail_str(prog);
7656 if (eargp)
7657 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7658 break;
7659 default:
7660 rb_sys_fail_str(prog);
7661 }
7662 if (!NIL_P(execarg_obj)) {
7663 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7664 if (state) {
7665 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7666 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7667 if (0 <= arg.pair[0]) close(arg.pair[0]);
7668 if (0 <= arg.pair[1]) close(arg.pair[1]);
7669 rb_execarg_parent_end(execarg_obj);
7670 rb_jump_tag(state);
7671 }
7672
7673# if defined(HAVE_WORKING_FORK)
7674 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7675# else
7676 rb_execarg_run_options(eargp, sargp, NULL, 0);
7677# if defined(HAVE_SPAWNVE)
7678 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7679# endif
7680 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7681 /* exec failed */
7682 switch (e = errno) {
7683 case EAGAIN:
7684# if EWOULDBLOCK != EAGAIN
7685 case EWOULDBLOCK:
7686# endif
7687 rb_thread_sleep(1);
7688 continue;
7689 }
7690 break;
7691 }
7692 if (eargp)
7693 rb_execarg_run_options(sargp, NULL, NULL, 0);
7694# endif
7695 rb_execarg_parent_end(execarg_obj);
7696 }
7697 else {
7698# if defined(HAVE_WORKING_FORK)
7699 pid = rb_call_proc__fork();
7700 if (pid == 0) { /* child */
7701 popen_redirect(&arg);
7702 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7703 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7704 return Qnil;
7705 }
7706# else
7708# endif
7709 }
7710
7711 /* parent */
7712 if (pid < 0) {
7713# if defined(HAVE_WORKING_FORK)
7714 e = errno;
7715# endif
7716 close(arg.pair[0]);
7717 close(arg.pair[1]);
7719 close(arg.write_pair[0]);
7720 close(arg.write_pair[1]);
7721 }
7722# if defined(HAVE_WORKING_FORK)
7723 if (errmsg[0])
7724 rb_syserr_fail(e, errmsg);
7725# endif
7726 rb_syserr_fail_str(e, prog);
7727 }
7728 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7729 close(arg.pair[1]);
7730 fd = arg.pair[0];
7731 close(arg.write_pair[0]);
7732 write_fd = arg.write_pair[1];
7733 }
7734 else if (fmode & FMODE_READABLE) {
7735 close(arg.pair[1]);
7736 fd = arg.pair[0];
7737 }
7738 else {
7739 close(arg.pair[0]);
7740 fd = arg.pair[1];
7741 }
7742#else
7743 cmd = rb_execarg_commandline(eargp, &prog);
7744 if (!NIL_P(execarg_obj)) {
7745 rb_execarg_parent_start(execarg_obj);
7746 rb_execarg_run_options(eargp, sargp, NULL, 0);
7747 }
7748 fp = popen(cmd, modestr);
7749 e = errno;
7750 if (eargp) {
7751 rb_execarg_parent_end(execarg_obj);
7752 rb_execarg_run_options(sargp, NULL, NULL, 0);
7753 }
7754 if (!fp) rb_syserr_fail_path(e, prog);
7755 fd = fileno(fp);
7756#endif
7757
7758 port = io_alloc(rb_cIO);
7759 MakeOpenFile(port, fptr);
7760 fptr->fd = fd;
7761 fptr->stdio_file = fp;
7762 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7763 if (convconfig) {
7764 fptr->encs = *convconfig;
7765#if RUBY_CRLF_ENVIRONMENT
7768 }
7769#endif
7770 }
7771 else {
7772 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7774 }
7775#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7776 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7777 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7778 }
7779#endif
7780 }
7781 fptr->pid = pid;
7782
7783 if (0 <= write_fd) {
7784 write_port = io_alloc(rb_cIO);
7785 MakeOpenFile(write_port, write_fptr);
7786 write_fptr->fd = write_fd;
7787 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7788 fptr->mode &= ~FMODE_WRITABLE;
7789 fptr->tied_io_for_writing = write_port;
7790 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7791 }
7792
7793#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7794 fptr->finalize = pipe_finalize;
7795 pipe_add_fptr(fptr);
7796#endif
7797 return port;
7798}
7799#else
7800static VALUE
7801pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7802 const struct rb_io_encoding *convconfig)
7803{
7804 rb_raise(rb_eNotImpError, "popen() is not available");
7805}
7806#endif
7807
7808static int
7809is_popen_fork(VALUE prog)
7810{
7811 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7812#if !defined(HAVE_WORKING_FORK)
7813 rb_raise(rb_eNotImpError,
7814 "fork() function is unimplemented on this machine");
7815#else
7816 return TRUE;
7817#endif
7818 }
7819 return FALSE;
7820}
7821
7822static VALUE
7823pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
7824 const struct rb_io_encoding *convconfig)
7825{
7826 int argc = 1;
7827 VALUE *argv = &prog;
7828 VALUE execarg_obj = Qnil;
7829
7830 if (!is_popen_fork(prog))
7831 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7832 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7833}
7834
7835static VALUE
7836pipe_close(VALUE io)
7837{
7838 rb_io_t *fptr = io_close_fptr(io);
7839 if (fptr) {
7840 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7841 }
7842 return Qnil;
7843}
7844
7845static VALUE popen_finish(VALUE port, VALUE klass);
7846
7847/*
7848 * call-seq:
7849 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7850 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7851 *
7852 * Executes the given command +cmd+ as a subprocess
7853 * whose $stdin and $stdout are connected to a new stream +io+.
7854 *
7855 * This method has potential security vulnerabilities if called with untrusted input;
7856 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
7857 *
7858 * If no block is given, returns the new stream,
7859 * which depending on given +mode+ may be open for reading, writing, or both.
7860 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7861 *
7862 * If a block is given, the stream is passed to the block
7863 * (again, open for reading, writing, or both);
7864 * when the block exits, the stream is closed,
7865 * the block's value is returned,
7866 * and the global variable <tt>$?</tt> is set to the child's exit status.
7867 *
7868 * Optional argument +mode+ may be any valid \IO mode.
7869 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7870 *
7871 * Required argument +cmd+ determines which of the following occurs:
7872 *
7873 * - The process forks.
7874 * - A specified program runs in a shell.
7875 * - A specified program runs with specified arguments.
7876 * - A specified program runs with specified arguments and a specified +argv0+.
7877 *
7878 * Each of these is detailed below.
7879 *
7880 * The optional hash argument +env+ specifies name/value pairs that are to be added
7881 * to the environment variables for the subprocess:
7882 *
7883 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7884 * pipe.puts 'puts ENV["FOO"]'
7885 * pipe.close_write
7886 * pipe.gets
7887 * end => "bar\n"
7888 *
7889 * Optional keyword arguments +opts+ specify:
7890 *
7891 * - {Open options}[rdoc-ref:IO@Open+Options].
7892 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7893 * - Options for Kernel#spawn.
7894 *
7895 * <b>Forked Process</b>
7896 *
7897 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7898 * IO.popen('-') do |pipe|
7899 * if pipe
7900 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7901 * else
7902 * $stderr.puts "In child, pid is #{$$}\n"
7903 * end
7904 * end
7905 *
7906 * Output:
7907 *
7908 * In parent, child pid is 26253
7909 * In child, pid is 26253
7910 *
7911 * Note that this is not supported on all platforms.
7912 *
7913 * <b>Shell Subprocess</b>
7914 *
7915 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7916 * the program named +cmd+ is run as a shell command:
7917 *
7918 * IO.popen('uname') do |pipe|
7919 * pipe.readlines
7920 * end
7921 *
7922 * Output:
7923 *
7924 * ["Linux\n"]
7925 *
7926 * Another example:
7927 *
7928 * IO.popen('/bin/sh', 'r+') do |pipe|
7929 * pipe.puts('ls')
7930 * pipe.close_write
7931 * $stderr.puts pipe.readlines.size
7932 * end
7933 *
7934 * Output:
7935 *
7936 * 213
7937 *
7938 * <b>Program Subprocess</b>
7939 *
7940 * When argument +cmd+ is an array of strings,
7941 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7942 *
7943 * IO.popen(['du', '..', '.']) do |pipe|
7944 * $stderr.puts pipe.readlines.size
7945 * end
7946 *
7947 * Output:
7948 *
7949 * 1111
7950 *
7951 * <b>Program Subprocess with <tt>argv0</tt></b>
7952 *
7953 * When argument +cmd+ is an array whose first element is a 2-element string array
7954 * and whose remaining elements (if any) are strings:
7955 *
7956 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7957 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7958 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7959 *
7960 * Example (sets <tt>$0</tt> to 'foo'):
7961 *
7962 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7963 *
7964 * <b>Some Special Examples</b>
7965 *
7966 * # Set IO encoding.
7967 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7968 * euc_jp_string = nkf_io.read
7969 * }
7970 *
7971 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7972 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7973 * ls_result_with_error = io.read
7974 * end
7975 *
7976 * # Use mixture of spawn options and IO options.
7977 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7978 * ls_result_with_error = io.read
7979 * end
7980 *
7981 * f = IO.popen("uname")
7982 * p f.readlines
7983 * f.close
7984 * puts "Parent is #{Process.pid}"
7985 * IO.popen("date") {|f| puts f.gets }
7986 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7987 * p $?
7988 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7989 * f.puts "bar"; f.close_write; puts f.gets
7990 * }
7991 *
7992 * Output (from last section):
7993 *
7994 * ["Linux\n"]
7995 * Parent is 21346
7996 * Thu Jan 15 22:41:19 JST 2009
7997 * 21346 is here, f is #<IO:fd 3>
7998 * 21352 is here, f is nil
7999 * #<Process::Status: pid 21352 exit 0>
8000 * <foo>bar;zot;
8001 *
8002 * Raises exceptions that IO.pipe and Kernel.spawn raise.
8003 *
8004 */
8005
8006static VALUE
8007rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
8008{
8009 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
8010
8011 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8012 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8013 switch (argc) {
8014 case 2:
8015 pmode = argv[1];
8016 case 1:
8017 pname = argv[0];
8018 break;
8019 default:
8020 {
8021 int ex = !NIL_P(opt);
8022 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8023 }
8024 }
8025 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8026}
8027
8028VALUE
8029rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8030{
8031 const char *modestr;
8032 VALUE tmp, execarg_obj = Qnil;
8033 int oflags;
8034 enum rb_io_mode fmode;
8035 struct rb_io_encoding convconfig;
8036
8037 tmp = rb_check_array_type(pname);
8038 if (!NIL_P(tmp)) {
8039 long len = RARRAY_LEN(tmp);
8040#if SIZEOF_LONG > SIZEOF_INT
8041 if (len > INT_MAX) {
8042 rb_raise(rb_eArgError, "too many arguments");
8043 }
8044#endif
8045 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8046 RB_GC_GUARD(tmp);
8047 }
8048 else {
8049 StringValue(pname);
8050 execarg_obj = Qnil;
8051 if (!is_popen_fork(pname))
8052 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8053 }
8054 if (!NIL_P(execarg_obj)) {
8055 if (!NIL_P(opt))
8056 opt = rb_execarg_extract_options(execarg_obj, opt);
8057 if (!NIL_P(env))
8058 rb_execarg_setenv(execarg_obj, env);
8059 }
8060 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8061 modestr = rb_io_oflags_modestr(oflags);
8062
8063 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8064}
8065
8066static VALUE
8067popen_finish(VALUE port, VALUE klass)
8068{
8069 if (NIL_P(port)) {
8070 /* child */
8071 if (rb_block_given_p()) {
8072 rb_protect(rb_yield, Qnil, NULL);
8073 rb_io_flush(rb_ractor_stdout());
8074 rb_io_flush(rb_ractor_stderr());
8075 _exit(0);
8076 }
8077 return Qnil;
8078 }
8079 RBASIC_SET_CLASS(port, klass);
8080 if (rb_block_given_p()) {
8081 return rb_ensure(rb_yield, port, pipe_close, port);
8082 }
8083 return port;
8084}
8085
8086#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8087struct popen_writer_arg {
8088 char *const *argv;
8089 struct popen_arg popen;
8090};
8091
8092static int
8093exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8094{
8095 struct popen_writer_arg *pw = arg;
8096 pw->popen.modef = FMODE_WRITABLE;
8097 popen_redirect(&pw->popen);
8098 execv(pw->argv[0], pw->argv);
8099 strlcpy(errmsg, strerror(errno), buflen);
8100 return -1;
8101}
8102#endif
8103
8104FILE *
8105ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8106{
8107#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8108# ifdef HAVE_WORKING_FORK
8109 struct popen_writer_arg pw;
8110 int *const write_pair = pw.popen.pair;
8111# else
8112 int write_pair[2];
8113# endif
8114
8115#ifdef HAVE_PIPE2
8116 int result = pipe2(write_pair, O_CLOEXEC);
8117#else
8118 int result = pipe(write_pair);
8119#endif
8120
8121 *pid = -1;
8122 if (result == 0) {
8123# ifdef HAVE_WORKING_FORK
8124 pw.argv = argv;
8125 int status;
8126 char errmsg[80] = {'\0'};
8127 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8128# else
8129 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8130 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8131# endif
8132 close(write_pair[0]);
8133 if (*pid < 0) {
8134 close(write_pair[1]);
8135 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8136 }
8137 else {
8138 return fdopen(write_pair[1], "w");
8139 }
8140 }
8141#endif
8142 return NULL;
8143}
8144
8145static VALUE
8146rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8147{
8148 int oflags;
8149 enum rb_io_mode fmode;
8150 struct rb_io_encoding convconfig;
8151 mode_t perm;
8152
8153 FilePathValue(fname);
8154
8155 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8156 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8157
8158 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8159
8160 return io;
8161}
8162
8163/*
8164 * Document-method: File::open
8165 *
8166 * call-seq:
8167 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8168 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8169 *
8170 * Creates a new File object, via File.new with the given arguments.
8171 *
8172 * With no block given, returns the File object.
8173 *
8174 * With a block given, calls the block with the File object
8175 * and returns the block's value.
8176 *
8177 */
8178
8179/*
8180 * Document-method: IO::open
8181 *
8182 * call-seq:
8183 * IO.open(fd, mode = 'r', **opts) -> io
8184 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8185 *
8186 * Creates a new \IO object, via IO.new with the given arguments.
8187 *
8188 * With no block given, returns the \IO object.
8189 *
8190 * With a block given, calls the block with the \IO object
8191 * and returns the block's value.
8192 *
8193 */
8194
8195static VALUE
8196rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8197{
8199
8200 if (rb_block_given_p()) {
8201 return rb_ensure(rb_yield, io, io_close, io);
8202 }
8203
8204 return io;
8205}
8206
8207/*
8208 * call-seq:
8209 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8210 *
8211 * Opens the file at the given path with the given mode and permissions;
8212 * returns the integer file descriptor.
8213 *
8214 * If the file is to be readable, it must exist;
8215 * if the file is to be writable and does not exist,
8216 * it is created with the given permissions:
8217 *
8218 * File.write('t.tmp', '') # => 0
8219 * IO.sysopen('t.tmp') # => 8
8220 * IO.sysopen('t.tmp', 'w') # => 9
8221 *
8222 *
8223 */
8224
8225static VALUE
8226rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8227{
8228 VALUE fname, vmode, vperm;
8229 VALUE intmode;
8230 int oflags, fd;
8231 mode_t perm;
8232
8233 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8234 FilePathValue(fname);
8235
8236 if (NIL_P(vmode))
8237 oflags = O_RDONLY;
8238 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8239 oflags = NUM2INT(intmode);
8240 else {
8241 StringValue(vmode);
8242 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8243 }
8244 if (NIL_P(vperm)) perm = 0666;
8245 else perm = NUM2MODET(vperm);
8246
8247 RB_GC_GUARD(fname) = rb_str_new4(fname);
8248 fd = rb_sysopen(fname, oflags, perm);
8249 return INT2NUM(fd);
8250}
8251
8252/*
8253 * call-seq:
8254 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8255 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8256 *
8257 * Creates an IO object connected to the given file.
8258 *
8259 * With no block given, file stream is returned:
8260 *
8261 * open('t.txt') # => #<File:t.txt>
8262 *
8263 * With a block given, calls the block with the open file stream,
8264 * then closes the stream:
8265 *
8266 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8267 *
8268 * Output:
8269 *
8270 * #<File:t.txt>
8271 *
8272 * See File.open for details.
8273 *
8274 */
8275
8276static VALUE
8277rb_f_open(int argc, VALUE *argv, VALUE _)
8278{
8279 ID to_open = 0;
8280 int redirect = FALSE;
8281
8282 if (argc >= 1) {
8283 CONST_ID(to_open, "to_open");
8284 if (rb_respond_to(argv[0], to_open)) {
8285 redirect = TRUE;
8286 }
8287 else {
8288 VALUE tmp = argv[0];
8289 FilePathValue(tmp);
8290 if (NIL_P(tmp)) {
8291 redirect = TRUE;
8292 }
8293 else {
8294 argv[0] = tmp;
8295 }
8296 }
8297 }
8298 if (redirect) {
8299 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8300
8301 if (rb_block_given_p()) {
8302 return rb_ensure(rb_yield, io, io_close, io);
8303 }
8304 return io;
8305 }
8306 return rb_io_s_open(argc, argv, rb_cFile);
8307}
8308
8309static VALUE
8310rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8311 const struct rb_io_encoding *convconfig, mode_t perm)
8312{
8313 return rb_file_open_generic(io_alloc(klass), filename,
8314 oflags, fmode, convconfig, perm);
8315}
8316
8317static VALUE
8318rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8319{
8320 int oflags;
8321 enum rb_io_mode fmode;
8322 struct rb_io_encoding convconfig;
8323 mode_t perm;
8324
8325 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8326 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8327 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8328}
8329
8330static VALUE
8331io_reopen(VALUE io, VALUE nfile)
8332{
8333 rb_io_t *fptr, *orig;
8334 int fd, fd2;
8335 rb_off_t pos = 0;
8336
8337 nfile = rb_io_get_io(nfile);
8338 GetOpenFile(io, fptr);
8339 GetOpenFile(nfile, orig);
8340
8341 if (fptr == orig) return io;
8342 if (RUBY_IO_EXTERNAL_P(fptr)) {
8343 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8344 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8345 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8346 rb_raise(rb_eArgError,
8347 "%s can't change access mode from \"%s\" to \"%s\"",
8348 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8349 rb_io_fmode_modestr(orig->mode));
8350 }
8351 }
8352 if (fptr->mode & FMODE_WRITABLE) {
8353 if (io_fflush(fptr) < 0)
8354 rb_sys_fail_on_write(fptr);
8355 }
8356 else {
8357 flush_before_seek(fptr, true);
8358 }
8359 if (orig->mode & FMODE_READABLE) {
8360 pos = io_tell(orig);
8361 }
8362 if (orig->mode & FMODE_WRITABLE) {
8363 if (io_fflush(orig) < 0)
8364 rb_sys_fail_on_write(fptr);
8365 }
8366
8367 /* copy rb_io_t structure */
8368 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8369 fptr->encs = orig->encs;
8370 fptr->pid = orig->pid;
8371 fptr->lineno = orig->lineno;
8372 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8373 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8374 fptr_copy_finalizer(fptr, orig);
8375
8376 fd = fptr->fd;
8377 fd2 = orig->fd;
8378 if (fd != fd2) {
8379 // Interrupt all usage of the old file descriptor:
8380 rb_thread_io_close_interrupt(fptr);
8381 rb_thread_io_close_wait(fptr);
8382
8383 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8384 /* need to keep FILE objects of stdin, stdout and stderr */
8385 if (rb_cloexec_dup2(fd2, fd) < 0)
8386 rb_sys_fail_path(orig->pathv);
8387 rb_update_max_fd(fd);
8388 }
8389 else {
8390 fclose(fptr->stdio_file);
8391 fptr->stdio_file = 0;
8392 fptr->fd = -1;
8393 if (rb_cloexec_dup2(fd2, fd) < 0)
8394 rb_sys_fail_path(orig->pathv);
8395 rb_update_max_fd(fd);
8396 fptr->fd = fd;
8397 }
8398
8399 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8400 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8401 rb_sys_fail_path(fptr->pathv);
8402 }
8403 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8404 rb_sys_fail_path(orig->pathv);
8405 }
8406 }
8407 }
8408
8409 if (fptr->mode & FMODE_BINMODE) {
8410 rb_io_binmode(io);
8411 }
8412
8413 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8414 return io;
8415}
8416
8417#ifdef _WIN32
8418int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8419#else
8420static int
8421rb_freopen(VALUE fname, const char *mode, FILE *fp)
8422{
8423 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8424 RB_GC_GUARD(fname);
8425 return errno;
8426 }
8427 return 0;
8428}
8429#endif
8430
8431/*
8432 * call-seq:
8433 * reopen(other_io) -> self
8434 * reopen(path, mode = 'r', **opts) -> self
8435 *
8436 * Reassociates the stream with another stream,
8437 * which may be of a different class.
8438 * This method may be used to redirect an existing stream
8439 * to a new destination.
8440 *
8441 * With argument +other_io+ given, reassociates with that stream:
8442 *
8443 * # Redirect $stdin from a file.
8444 * f = File.open('t.txt')
8445 * $stdin.reopen(f)
8446 * f.close
8447 *
8448 * # Redirect $stdout to a file.
8449 * f = File.open('t.tmp', 'w')
8450 * $stdout.reopen(f)
8451 * f.close
8452 *
8453 * With argument +path+ given, reassociates with a new stream to that file path:
8454 *
8455 * $stdin.reopen('t.txt')
8456 * $stdout.reopen('t.tmp', 'w')
8457 *
8458 * Optional keyword arguments +opts+ specify:
8459 *
8460 * - {Open Options}[rdoc-ref:IO@Open+Options].
8461 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8462 *
8463 */
8464
8465static VALUE
8466rb_io_reopen(int argc, VALUE *argv, VALUE file)
8467{
8468 VALUE fname, nmode, opt;
8469 int oflags;
8470 rb_io_t *fptr;
8471
8472 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8473 VALUE tmp = rb_io_check_io(fname);
8474 if (!NIL_P(tmp)) {
8475 return io_reopen(file, tmp);
8476 }
8477 }
8478
8479 FilePathValue(fname);
8480 rb_io_taint_check(file);
8481 fptr = RFILE(file)->fptr;
8482 if (!fptr) {
8483 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8484 }
8485
8486 if (!NIL_P(nmode) || !NIL_P(opt)) {
8487 enum rb_io_mode fmode;
8488 struct rb_io_encoding convconfig;
8489
8490 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8491 if (RUBY_IO_EXTERNAL_P(fptr) &&
8492 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8493 (fptr->mode & FMODE_READWRITE)) {
8494 rb_raise(rb_eArgError,
8495 "%s can't change access mode from \"%s\" to \"%s\"",
8496 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8497 rb_io_fmode_modestr(fmode));
8498 }
8499 fptr->mode = fmode;
8500 fptr->encs = convconfig;
8501 }
8502 else {
8503 oflags = rb_io_fmode_oflags(fptr->mode);
8504 }
8505
8506 fptr->pathv = fname;
8507 if (fptr->fd < 0) {
8508 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8509 fptr->stdio_file = 0;
8510 return file;
8511 }
8512
8513 if (fptr->mode & FMODE_WRITABLE) {
8514 if (io_fflush(fptr) < 0)
8515 rb_sys_fail_on_write(fptr);
8516 }
8517 fptr->rbuf.off = fptr->rbuf.len = 0;
8518
8519 if (fptr->stdio_file) {
8520 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8521 rb_io_oflags_modestr(oflags),
8522 fptr->stdio_file);
8523 if (e) rb_syserr_fail_path(e, fptr->pathv);
8524 fptr->fd = fileno(fptr->stdio_file);
8525 rb_fd_fix_cloexec(fptr->fd);
8526#ifdef USE_SETVBUF
8527 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8528 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8529#endif
8530 if (fptr->stdio_file == stderr) {
8531 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8532 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8533 }
8534 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8535 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8536 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8537 }
8538 }
8539 else {
8540 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8541 int err = 0;
8542 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8543 err = errno;
8544 (void)close(tmpfd);
8545 if (err) {
8546 rb_syserr_fail_path(err, fptr->pathv);
8547 }
8548 }
8549
8550 return file;
8551}
8552
8553/* :nodoc: */
8554static VALUE
8555rb_io_init_copy(VALUE dest, VALUE io)
8556{
8557 rb_io_t *fptr, *orig;
8558 int fd;
8559 VALUE write_io;
8560 rb_off_t pos;
8561
8562 io = rb_io_get_io(io);
8563 if (!OBJ_INIT_COPY(dest, io)) return dest;
8564 GetOpenFile(io, orig);
8565 MakeOpenFile(dest, fptr);
8566
8567 rb_io_flush(io);
8568
8569 /* copy rb_io_t structure */
8570 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8571 fptr->encs = orig->encs;
8572 fptr->pid = orig->pid;
8573 fptr->lineno = orig->lineno;
8574 fptr->timeout = orig->timeout;
8575
8576 ccan_list_head_init(&fptr->blocking_operations);
8577 fptr->closing_ec = NULL;
8578 fptr->wakeup_mutex = Qnil;
8579 fptr->fork_generation = GET_VM()->fork_gen;
8580
8581 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8582 fptr_copy_finalizer(fptr, orig);
8583
8584 fd = ruby_dup(orig->fd);
8585 fptr->fd = fd;
8586 pos = io_tell(orig);
8587 if (0 <= pos)
8588 io_seek(fptr, pos, SEEK_SET);
8589 if (fptr->mode & FMODE_BINMODE) {
8590 rb_io_binmode(dest);
8591 }
8592
8593 write_io = GetWriteIO(io);
8594 if (io != write_io) {
8595 write_io = rb_obj_dup(write_io);
8596 fptr->tied_io_for_writing = write_io;
8597 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8598 }
8599
8600 return dest;
8601}
8602
8603/*
8604 * call-seq:
8605 * printf(format_string, *objects) -> nil
8606 *
8607 * Formats and writes +objects+ to the stream.
8608 *
8609 * For details on +format_string+, see
8610 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8611 *
8612 */
8613
8614VALUE
8615rb_io_printf(int argc, const VALUE *argv, VALUE out)
8616{
8617 rb_io_write(out, rb_f_sprintf(argc, argv));
8618 return Qnil;
8619}
8620
8621/*
8622 * call-seq:
8623 * printf(format_string, *objects) -> nil
8624 * printf(io, format_string, *objects) -> nil
8625 *
8626 * Equivalent to:
8627 *
8628 * io.write(sprintf(format_string, *objects))
8629 *
8630 * For details on +format_string+, see
8631 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8632 *
8633 * With the single argument +format_string+, formats +objects+ into the string,
8634 * then writes the formatted string to $stdout:
8635 *
8636 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8637 *
8638 * Output (on $stdout):
8639 *
8640 * 0024 24 24.00#
8641 *
8642 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8643 * then writes the formatted string to +io+:
8644 *
8645 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8646 *
8647 * Output (on $stderr):
8648 *
8649 * 0024 24 24.00# => nil
8650 *
8651 * With no arguments, does nothing.
8652 *
8653 */
8654
8655static VALUE
8656rb_f_printf(int argc, VALUE *argv, VALUE _)
8657{
8658 VALUE out;
8659
8660 if (argc == 0) return Qnil;
8661 if (RB_TYPE_P(argv[0], T_STRING)) {
8662 out = rb_ractor_stdout();
8663 }
8664 else {
8665 out = argv[0];
8666 argv++;
8667 argc--;
8668 }
8669 rb_io_write(out, rb_f_sprintf(argc, argv));
8670
8671 return Qnil;
8672}
8673
8674extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
8675
8676static void
8677deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8678{
8679 rb_deprecated_str_setter(val, id, &val);
8680 if (!NIL_P(val)) {
8681 if (rb_str_equal(val, rb_default_rs)) {
8682 val = rb_default_rs;
8683 }
8684 else {
8685 val = rb_str_frozen_bare_string(val);
8686 }
8687 }
8688 *var = val;
8689}
8690
8691/*
8692 * call-seq:
8693 * print(*objects) -> nil
8694 *
8695 * Writes the given objects to the stream; returns +nil+.
8696 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8697 * (<tt>$\</tt>), if it is not +nil+.
8698 * See {Line IO}[rdoc-ref:IO@Line+IO].
8699 *
8700 * With argument +objects+ given, for each object:
8701 *
8702 * - Converts via its method +to_s+ if not a string.
8703 * - Writes to the stream.
8704 * - If not the last object, writes the output field separator
8705 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8706 *
8707 * With default separators:
8708 *
8709 * f = File.open('t.tmp', 'w+')
8710 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8711 * p $OUTPUT_RECORD_SEPARATOR
8712 * p $OUTPUT_FIELD_SEPARATOR
8713 * f.print(*objects)
8714 * f.rewind
8715 * p f.read
8716 * f.close
8717 *
8718 * Output:
8719 *
8720 * nil
8721 * nil
8722 * "00.00/10+0izerozero"
8723 *
8724 * With specified separators:
8725 *
8726 * $\ = "\n"
8727 * $, = ','
8728 * f.rewind
8729 * f.print(*objects)
8730 * f.rewind
8731 * p f.read
8732 *
8733 * Output:
8734 *
8735 * "0,0.0,0/1,0+0i,zero,zero\n"
8736 *
8737 * With no argument given, writes the content of <tt>$_</tt>
8738 * (which is usually the most recent user input):
8739 *
8740 * f = File.open('t.tmp', 'w+')
8741 * gets # Sets $_ to the most recent user input.
8742 * f.print
8743 * f.close
8744 *
8745 */
8746
8747VALUE
8748rb_io_print(int argc, const VALUE *argv, VALUE out)
8749{
8750 int i;
8751 VALUE line;
8752
8753 /* if no argument given, print `$_' */
8754 if (argc == 0) {
8755 argc = 1;
8756 line = rb_lastline_get();
8757 argv = &line;
8758 }
8759 if (argc > 1 && !NIL_P(rb_output_fs)) {
8760 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8761 }
8762 for (i=0; i<argc; i++) {
8763 if (!NIL_P(rb_output_fs) && i>0) {
8764 rb_io_write(out, rb_output_fs);
8765 }
8766 rb_io_write(out, argv[i]);
8767 }
8768 if (argc > 0 && !NIL_P(rb_output_rs)) {
8769 rb_io_write(out, rb_output_rs);
8770 }
8771
8772 return Qnil;
8773}
8774
8775/*
8776 * call-seq:
8777 * print(*objects) -> nil
8778 *
8779 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8780 * this method is the straightforward way to write to <tt>$stdout</tt>.
8781 *
8782 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8783 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8784 * <tt>$\</tt>), if it is not +nil+.
8785 *
8786 * With argument +objects+ given, for each object:
8787 *
8788 * - Converts via its method +to_s+ if not a string.
8789 * - Writes to <tt>stdout</tt>.
8790 * - If not the last object, writes the output field separator
8791 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8792 *
8793 * With default separators:
8794 *
8795 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8796 * $OUTPUT_RECORD_SEPARATOR
8797 * $OUTPUT_FIELD_SEPARATOR
8798 * print(*objects)
8799 *
8800 * Output:
8801 *
8802 * nil
8803 * nil
8804 * 00.00/10+0izerozero
8805 *
8806 * With specified separators:
8807 *
8808 * $OUTPUT_RECORD_SEPARATOR = "\n"
8809 * $OUTPUT_FIELD_SEPARATOR = ','
8810 * print(*objects)
8811 *
8812 * Output:
8813 *
8814 * 0,0.0,0/1,0+0i,zero,zero
8815 *
8816 * With no argument given, writes the content of <tt>$_</tt>
8817 * (which is usually the most recent user input):
8818 *
8819 * gets # Sets $_ to the most recent user input.
8820 * print # Prints $_.
8821 *
8822 */
8823
8824static VALUE
8825rb_f_print(int argc, const VALUE *argv, VALUE _)
8826{
8827 rb_io_print(argc, argv, rb_ractor_stdout());
8828 return Qnil;
8829}
8830
8831/*
8832 * call-seq:
8833 * putc(object) -> object
8834 *
8835 * Writes a character to the stream.
8836 * See {Character IO}[rdoc-ref:IO@Character+IO].
8837 *
8838 * If +object+ is numeric, converts to integer if necessary,
8839 * then writes the character whose code is the
8840 * least significant byte;
8841 * if +object+ is a string, writes the first character:
8842 *
8843 * $stdout.putc "A"
8844 * $stdout.putc 65
8845 *
8846 * Output:
8847 *
8848 * AA
8849 *
8850 */
8851
8852static VALUE
8853rb_io_putc(VALUE io, VALUE ch)
8854{
8855 VALUE str;
8856 if (RB_TYPE_P(ch, T_STRING)) {
8857 str = rb_str_substr(ch, 0, 1);
8858 }
8859 else {
8860 char c = NUM2CHR(ch);
8861 str = rb_str_new(&c, 1);
8862 }
8863 rb_io_write(io, str);
8864 return ch;
8865}
8866
8867#define forward(obj, id, argc, argv) \
8868 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8869#define forward_public(obj, id, argc, argv) \
8870 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8871#define forward_current(id, argc, argv) \
8872 forward_public(ARGF.current_file, id, argc, argv)
8873
8874/*
8875 * call-seq:
8876 * putc(int) -> int
8877 *
8878 * Equivalent to:
8879 *
8880 * $stdout.putc(int)
8881 *
8882 * See IO#putc for important information regarding multi-byte characters.
8883 *
8884 */
8885
8886static VALUE
8887rb_f_putc(VALUE recv, VALUE ch)
8888{
8889 VALUE r_stdout = rb_ractor_stdout();
8890 if (recv == r_stdout) {
8891 return rb_io_putc(recv, ch);
8892 }
8893 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8894}
8895
8896
8897int
8898rb_str_end_with_asciichar(VALUE str, int c)
8899{
8900 long len = RSTRING_LEN(str);
8901 const char *ptr = RSTRING_PTR(str);
8902 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8903 int n;
8904
8905 if (len == 0) return 0;
8906 if ((n = rb_enc_mbminlen(enc)) == 1) {
8907 return ptr[len - 1] == c;
8908 }
8909 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8910}
8911
8912static VALUE
8913io_puts_ary(VALUE ary, VALUE out, int recur)
8914{
8915 VALUE tmp;
8916 long i;
8917
8918 if (recur) {
8919 tmp = rb_str_new2("[...]");
8920 rb_io_puts(1, &tmp, out);
8921 return Qtrue;
8922 }
8923 ary = rb_check_array_type(ary);
8924 if (NIL_P(ary)) return Qfalse;
8925 for (i=0; i<RARRAY_LEN(ary); i++) {
8926 tmp = RARRAY_AREF(ary, i);
8927 rb_io_puts(1, &tmp, out);
8928 }
8929 return Qtrue;
8930}
8931
8932/*
8933 * call-seq:
8934 * puts(*objects) -> nil
8935 *
8936 * Writes the given +objects+ to the stream, which must be open for writing;
8937 * returns +nil+.\
8938 * Writes a newline after each that does not already end with a newline sequence.
8939 * If called without arguments, writes a newline.
8940 * See {Line IO}[rdoc-ref:IO@Line+IO].
8941 *
8942 * Note that each added newline is the character <tt>"\n"<//tt>,
8943 * not the output record separator (<tt>$\</tt>).
8944 *
8945 * Treatment for each object:
8946 *
8947 * - String: writes the string.
8948 * - Neither string nor array: writes <tt>object.to_s</tt>.
8949 * - Array: writes each element of the array; arrays may be nested.
8950 *
8951 * To keep these examples brief, we define this helper method:
8952 *
8953 * def show(*objects)
8954 * # Puts objects to file.
8955 * f = File.new('t.tmp', 'w+')
8956 * f.puts(objects)
8957 * # Return file content.
8958 * f.rewind
8959 * p f.read
8960 * f.close
8961 * end
8962 *
8963 * # Strings without newlines.
8964 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8965 * # Strings, some with newlines.
8966 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8967 *
8968 * # Neither strings nor arrays:
8969 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8970 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8971 *
8972 * # Array of strings.
8973 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8974 * # Nested arrays.
8975 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8976 *
8977 */
8978
8979VALUE
8980rb_io_puts(int argc, const VALUE *argv, VALUE out)
8981{
8982 VALUE line, args[2];
8983
8984 /* if no argument given, print newline. */
8985 if (argc == 0) {
8986 rb_io_write(out, rb_default_rs);
8987 return Qnil;
8988 }
8989 for (int i = 0; i < argc; i++) {
8990 // Convert the argument to a string:
8991 if (RB_TYPE_P(argv[i], T_STRING)) {
8992 line = argv[i];
8993 }
8994 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8995 continue;
8996 }
8997 else {
8998 line = rb_obj_as_string(argv[i]);
8999 }
9000
9001 // Write the line:
9002 int n = 0;
9003 if (RSTRING_LEN(line) == 0) {
9004 args[n++] = rb_default_rs;
9005 }
9006 else {
9007 args[n++] = line;
9008 if (!rb_str_end_with_asciichar(line, '\n')) {
9009 args[n++] = rb_default_rs;
9010 }
9011 }
9012
9013 rb_io_writev(out, n, args);
9014 }
9015
9016 return Qnil;
9017}
9018
9019/*
9020 * call-seq:
9021 * puts(*objects) -> nil
9022 *
9023 * Equivalent to
9024 *
9025 * $stdout.puts(objects)
9026 */
9027
9028static VALUE
9029rb_f_puts(int argc, VALUE *argv, VALUE recv)
9030{
9031 VALUE r_stdout = rb_ractor_stdout();
9032 if (recv == r_stdout) {
9033 return rb_io_puts(argc, argv, recv);
9034 }
9035 return forward(r_stdout, rb_intern("puts"), argc, argv);
9036}
9037
9038static VALUE
9039rb_p_write(VALUE str)
9040{
9041 VALUE args[2];
9042 args[0] = str;
9043 args[1] = rb_default_rs;
9044 VALUE r_stdout = rb_ractor_stdout();
9045 if (RB_TYPE_P(r_stdout, T_FILE) &&
9046 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9047 io_writev(2, args, r_stdout);
9048 }
9049 else {
9050 rb_io_writev(r_stdout, 2, args);
9051 }
9052 return Qnil;
9053}
9054
9055void
9056rb_p(VALUE obj) /* for debug print within C code */
9057{
9058 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9059}
9060
9061static VALUE
9062rb_p_result(int argc, const VALUE *argv)
9063{
9064 VALUE ret = Qnil;
9065
9066 if (argc == 1) {
9067 ret = argv[0];
9068 }
9069 else if (argc > 1) {
9070 ret = rb_ary_new4(argc, argv);
9071 }
9072 VALUE r_stdout = rb_ractor_stdout();
9073 if (RB_TYPE_P(r_stdout, T_FILE)) {
9074 rb_uninterruptible(rb_io_flush, r_stdout);
9075 }
9076 return ret;
9077}
9078
9079/*
9080 * call-seq:
9081 * p(object) -> obj
9082 * p(*objects) -> array of objects
9083 * p -> nil
9084 *
9085 * For each object +obj+, executes:
9086 *
9087 * $stdout.write(obj.inspect, "\n")
9088 *
9089 * With one object given, returns the object;
9090 * with multiple objects given, returns an array containing the objects;
9091 * with no object given, returns +nil+.
9092 *
9093 * Examples:
9094 *
9095 * r = Range.new(0, 4)
9096 * p r # => 0..4
9097 * p [r, r, r] # => [0..4, 0..4, 0..4]
9098 * p # => nil
9099 *
9100 * Output:
9101 *
9102 * 0..4
9103 * [0..4, 0..4, 0..4]
9104 *
9105 * Kernel#p is designed for debugging purposes.
9106 * Ruby implementations may define Kernel#p to be uninterruptible
9107 * in whole or in part.
9108 * On CRuby, Kernel#p's writing of data is uninterruptible.
9109 */
9110
9111static VALUE
9112rb_f_p(int argc, VALUE *argv, VALUE self)
9113{
9114 int i;
9115 for (i=0; i<argc; i++) {
9116 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9117 rb_uninterruptible(rb_p_write, inspected);
9118 }
9119 return rb_p_result(argc, argv);
9120}
9121
9122/*
9123 * call-seq:
9124 * display(port = $>) -> nil
9125 *
9126 * Writes +self+ on the given port:
9127 *
9128 * 1.display
9129 * "cat".display
9130 * [ 4, 5, 6 ].display
9131 * puts
9132 *
9133 * Output:
9134 *
9135 * 1cat[4, 5, 6]
9136 *
9137 */
9138
9139static VALUE
9140rb_obj_display(int argc, VALUE *argv, VALUE self)
9141{
9142 VALUE out;
9143
9144 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9145 rb_io_write(out, self);
9146
9147 return Qnil;
9148}
9149
9150static int
9151rb_stderr_to_original_p(VALUE err)
9152{
9153 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9154}
9155
9156void
9157rb_write_error2(const char *mesg, long len)
9158{
9159 VALUE out = rb_ractor_stderr();
9160 if (rb_stderr_to_original_p(out)) {
9161#ifdef _WIN32
9162 if (isatty(fileno(stderr))) {
9163 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9164 }
9165#endif
9166 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9167 /* failed to write to stderr, what can we do? */
9168 return;
9169 }
9170 }
9171 else {
9172 rb_io_write(out, rb_str_new(mesg, len));
9173 }
9174}
9175
9176void
9177rb_write_error(const char *mesg)
9178{
9179 rb_write_error2(mesg, strlen(mesg));
9180}
9181
9182void
9183rb_write_error_str(VALUE mesg)
9184{
9185 VALUE out = rb_ractor_stderr();
9186 /* a stopgap measure for the time being */
9187 if (rb_stderr_to_original_p(out)) {
9188 size_t len = (size_t)RSTRING_LEN(mesg);
9189#ifdef _WIN32
9190 if (isatty(fileno(stderr))) {
9191 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9192 }
9193#endif
9194 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9195 RB_GC_GUARD(mesg);
9196 return;
9197 }
9198 }
9199 else {
9200 /* may unlock GVL, and */
9201 rb_io_write(out, mesg);
9202 }
9203}
9204
9205int
9206rb_stderr_tty_p(void)
9207{
9208 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9209 return isatty(fileno(stderr));
9210 return 0;
9211}
9212
9213static void
9214must_respond_to(ID mid, VALUE val, ID id)
9215{
9216 if (!rb_respond_to(val, mid)) {
9217 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9218 rb_id2str(id), rb_id2str(mid),
9219 rb_obj_class(val));
9220 }
9221}
9222
9223static void
9224stdin_setter(VALUE val, ID id, VALUE *ptr)
9225{
9227}
9228
9229static VALUE
9230stdin_getter(ID id, VALUE *ptr)
9231{
9232 return rb_ractor_stdin();
9233}
9234
9235static void
9236stdout_setter(VALUE val, ID id, VALUE *ptr)
9237{
9238 must_respond_to(id_write, val, id);
9240}
9241
9242static VALUE
9243stdout_getter(ID id, VALUE *ptr)
9244{
9245 return rb_ractor_stdout();
9246}
9247
9248static void
9249stderr_setter(VALUE val, ID id, VALUE *ptr)
9250{
9251 must_respond_to(id_write, val, id);
9253}
9254
9255static VALUE
9256stderr_getter(ID id, VALUE *ptr)
9257{
9258 return rb_ractor_stderr();
9259}
9260
9261static VALUE
9262allocate_and_open_new_file(VALUE klass)
9263{
9264 VALUE self = io_alloc(klass);
9265 rb_io_make_open_file(self);
9266 return self;
9267}
9268
9269VALUE
9270rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9271{
9272 int state;
9273 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9274 if (state) {
9275 /* if we raised an exception allocating an IO object, but the caller
9276 intended to transfer ownership of this FD to us, close the fd before
9277 raising the exception. Otherwise, we would leak a FD - the caller
9278 expects GC to close the file, but we never got around to assigning
9279 it to a rb_io. */
9280 if (!(mode & FMODE_EXTERNAL)) {
9281 maygvl_close(descriptor, 0);
9282 }
9283 rb_jump_tag(state);
9284 }
9285
9286
9287 rb_io_t *io = RFILE(self)->fptr;
9288 io->self = self;
9289 io->fd = descriptor;
9290 io->mode = mode;
9291
9292 /* At this point, Ruby fully owns the descriptor, and will close it when
9293 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9294 in the rest of this method. */
9295
9296 if (NIL_P(path)) {
9297 io->pathv = Qnil;
9298 }
9299 else {
9300 StringValue(path);
9301 io->pathv = rb_str_new_frozen(path);
9302 }
9303
9304 io->timeout = timeout;
9305
9306 ccan_list_head_init(&io->blocking_operations);
9307 io->closing_ec = NULL;
9308 io->wakeup_mutex = Qnil;
9309 io->fork_generation = GET_VM()->fork_gen;
9310
9311 if (encoding) {
9312 io->encs = *encoding;
9313 }
9314
9315 rb_update_max_fd(descriptor);
9316
9317 return self;
9318}
9319
9320static VALUE
9321prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9322{
9323 VALUE path_value = Qnil;
9324 rb_encoding *e;
9325 struct rb_io_encoding convconfig;
9326
9327 if (path) {
9328 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9329 }
9330
9331 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9332 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9333 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9336#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9337 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9338 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9339 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9340#endif
9341 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9342 convconfig.ecopts = Qnil;
9343
9344 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9345 rb_io_t*io = RFILE(self)->fptr;
9346
9347 if (!io_check_tty(io)) {
9348#ifdef __CYGWIN__
9349 io->mode |= FMODE_BINMODE;
9350 setmode(fd, O_BINARY);
9351#endif
9352 }
9353
9354 return self;
9355}
9356
9357VALUE
9358rb_io_fdopen(int fd, int oflags, const char *path)
9359{
9360 VALUE klass = rb_cIO;
9361
9362 if (path && strcmp(path, "-")) klass = rb_cFile;
9363 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9364}
9365
9366static VALUE
9367prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9368{
9369 rb_io_t *fptr;
9370 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9371
9372 GetOpenFile(io, fptr);
9374#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9375 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9376 if (fmode & FMODE_READABLE) {
9378 }
9379#endif
9380 fptr->stdio_file = f;
9381
9382 return io;
9383}
9384
9385VALUE
9386rb_io_prep_stdin(void)
9387{
9388 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9389}
9390
9391VALUE
9392rb_io_prep_stdout(void)
9393{
9394 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9395}
9396
9397VALUE
9398rb_io_prep_stderr(void)
9399{
9400 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9401}
9402
9403FILE *
9404rb_io_stdio_file(rb_io_t *fptr)
9405{
9406 if (!fptr->stdio_file) {
9407 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9408 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9409 }
9410 return fptr->stdio_file;
9411}
9412
9413static inline void
9414rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9415{
9416 buf->ptr = NULL;
9417 buf->off = 0;
9418 buf->len = 0;
9419 buf->capa = 0;
9420}
9421
9422static inline rb_io_t *
9423rb_io_fptr_new(void)
9424{
9425 rb_io_t *fp = ALLOC(rb_io_t);
9426 fp->self = Qnil;
9427 fp->fd = -1;
9428 fp->stdio_file = NULL;
9429 fp->mode = 0;
9430 fp->pid = 0;
9431 fp->lineno = 0;
9432 fp->pathv = Qnil;
9433 fp->finalize = 0;
9434 rb_io_buffer_init(&fp->wbuf);
9435 rb_io_buffer_init(&fp->rbuf);
9436 rb_io_buffer_init(&fp->cbuf);
9437 fp->readconv = NULL;
9438 fp->writeconv = NULL;
9440 fp->writeconv_pre_ecflags = 0;
9442 fp->writeconv_initialized = 0;
9443 fp->tied_io_for_writing = 0;
9444 fp->encs.enc = NULL;
9445 fp->encs.enc2 = NULL;
9446 fp->encs.ecflags = 0;
9447 fp->encs.ecopts = Qnil;
9448 fp->write_lock = Qnil;
9449 fp->timeout = Qnil;
9450 ccan_list_head_init(&fp->blocking_operations);
9451 fp->closing_ec = NULL;
9452 fp->wakeup_mutex = Qnil;
9453 fp->fork_generation = GET_VM()->fork_gen;
9454 return fp;
9455}
9456
9457rb_io_t *
9458rb_io_make_open_file(VALUE obj)
9459{
9460 rb_io_t *fp = 0;
9461
9462 Check_Type(obj, T_FILE);
9463 if (RFILE(obj)->fptr) {
9464 rb_io_close(obj);
9465 rb_io_fptr_finalize(RFILE(obj)->fptr);
9466 RFILE(obj)->fptr = 0;
9467 }
9468 fp = rb_io_fptr_new();
9469 fp->self = obj;
9470 RFILE(obj)->fptr = fp;
9471 return fp;
9472}
9473
9474static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9475
9476/*
9477 * call-seq:
9478 * IO.new(fd, mode = 'r', **opts) -> io
9479 *
9480 * Creates and returns a new \IO object (file stream) from a file descriptor.
9481 *
9482 * \IO.new may be useful for interaction with low-level libraries.
9483 * For higher-level interactions, it may be simpler to create
9484 * the file stream using File.open.
9485 *
9486 * Argument +fd+ must be a valid file descriptor (integer):
9487 *
9488 * path = 't.tmp'
9489 * fd = IO.sysopen(path) # => 3
9490 * IO.new(fd) # => #<IO:fd 3>
9491 *
9492 * The new \IO object does not inherit encoding
9493 * (because the integer file descriptor does not have an encoding):
9494 *
9495 * fd = IO.sysopen('t.rus', 'rb')
9496 * io = IO.new(fd)
9497 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9498 *
9499 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9500 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9501 *
9502 * IO.new(fd, 'w') # => #<IO:fd 3>
9503 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9504 *
9505 * Optional keyword arguments +opts+ specify:
9506 *
9507 * - {Open Options}[rdoc-ref:IO@Open+Options].
9508 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9509 *
9510 * Examples:
9511 *
9512 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9513 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9514 *
9515 */
9516
9517static VALUE
9518rb_io_initialize(int argc, VALUE *argv, VALUE io)
9519{
9520 VALUE fnum, vmode;
9521 VALUE opt;
9522
9523 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9524 return io_initialize(io, fnum, vmode, opt);
9525}
9526
9527static VALUE
9528io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9529{
9530 rb_io_t *fp;
9531 int fd, oflags = O_RDONLY;
9532 enum rb_io_mode fmode;
9533 struct rb_io_encoding convconfig;
9534#if defined(HAVE_FCNTL) && defined(F_GETFL)
9535 int ofmode;
9536#else
9537 struct stat st;
9538#endif
9539
9540 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9541
9542 fd = NUM2INT(fnum);
9543 if (rb_reserved_fd_p(fd)) {
9544 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9545 }
9546#if defined(HAVE_FCNTL) && defined(F_GETFL)
9547 oflags = fcntl(fd, F_GETFL);
9548 if (oflags == -1) rb_sys_fail(0);
9549#else
9550 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9551#endif
9552 rb_update_max_fd(fd);
9553#if defined(HAVE_FCNTL) && defined(F_GETFL)
9554 ofmode = rb_io_oflags_fmode(oflags);
9555 if (NIL_P(vmode)) {
9556 fmode = ofmode;
9557 }
9558 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9559 VALUE error = INT2FIX(EINVAL);
9561 }
9562#endif
9563 VALUE path = Qnil;
9564
9565 if (!NIL_P(opt)) {
9566 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9567 fmode |= FMODE_EXTERNAL;
9568 }
9569
9570 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9571 if (!NIL_P(path)) {
9572 StringValue(path);
9573 path = rb_str_new_frozen(path);
9574 }
9575 }
9576
9577 MakeOpenFile(io, fp);
9578 fp->self = io;
9579 fp->fd = fd;
9580 fp->mode = fmode;
9581 fp->encs = convconfig;
9582 fp->pathv = path;
9583 fp->timeout = Qnil;
9584 ccan_list_head_init(&fp->blocking_operations);
9585 fp->closing_ec = NULL;
9586 fp->wakeup_mutex = Qnil;
9587 fp->fork_generation = GET_VM()->fork_gen;
9588 clear_codeconv(fp);
9589 io_check_tty(fp);
9590 if (fileno(stdin) == fd)
9591 fp->stdio_file = stdin;
9592 else if (fileno(stdout) == fd)
9593 fp->stdio_file = stdout;
9594 else if (fileno(stderr) == fd)
9595 fp->stdio_file = stderr;
9596
9597 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9598 return io;
9599}
9600
9601/*
9602 * call-seq:
9603 * set_encoding_by_bom -> encoding or nil
9604 *
9605 * If the stream begins with a BOM
9606 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9607 * consumes the BOM and sets the external encoding accordingly;
9608 * returns the result encoding if found, or +nil+ otherwise:
9609 *
9610 * File.write('t.tmp', "\u{FEFF}abc")
9611 * io = File.open('t.tmp', 'rb')
9612 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9613 * io.close
9614 *
9615 * File.write('t.tmp', 'abc')
9616 * io = File.open('t.tmp', 'rb')
9617 * io.set_encoding_by_bom # => nil
9618 * io.close
9619 *
9620 * Raises an exception if the stream is not binmode
9621 * or its encoding has already been set.
9622 *
9623 */
9624
9625static VALUE
9626rb_io_set_encoding_by_bom(VALUE io)
9627{
9628 rb_io_t *fptr;
9629
9630 GetOpenFile(io, fptr);
9631 if (!(fptr->mode & FMODE_BINMODE)) {
9632 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9633 }
9634 if (fptr->encs.enc2) {
9635 rb_raise(rb_eArgError, "encoding conversion is set");
9636 }
9637 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9638 rb_raise(rb_eArgError, "encoding is set to %s already",
9639 rb_enc_name(fptr->encs.enc));
9640 }
9641 if (!io_set_encoding_by_bom(io)) return Qnil;
9642 return rb_enc_from_encoding(fptr->encs.enc);
9643}
9644
9645/*
9646 * call-seq:
9647 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9648 *
9649 * Opens the file at the given +path+ according to the given +mode+;
9650 * creates and returns a new File object for that file.
9651 *
9652 * The new File object is buffered mode (or non-sync mode), unless
9653 * +filename+ is a tty.
9654 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9655 *
9656 * Argument +path+ must be a valid file path:
9657 *
9658 * f = File.new('/etc/fstab')
9659 * f.close
9660 * f = File.new('t.txt')
9661 * f.close
9662 *
9663 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9664 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9665 *
9666 * f = File.new('t.tmp', 'w')
9667 * f.close
9668 * f = File.new('t.tmp', File::RDONLY)
9669 * f.close
9670 *
9671 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9672 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9673 *
9674 * f = File.new('t.tmp', File::CREAT, 0644)
9675 * f.close
9676 * f = File.new('t.tmp', File::CREAT, 0444)
9677 * f.close
9678 *
9679 * Optional keyword arguments +opts+ specify:
9680 *
9681 * - {Open Options}[rdoc-ref:IO@Open+Options].
9682 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9683 *
9684 */
9685
9686static VALUE
9687rb_file_initialize(int argc, VALUE *argv, VALUE io)
9688{
9689 if (RFILE(io)->fptr) {
9690 rb_raise(rb_eRuntimeError, "reinitializing File");
9691 }
9692 VALUE fname, vmode, vperm, opt;
9693 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9694 if (posargc < 3) { /* perm is File only */
9695 VALUE fd = rb_check_to_int(fname);
9696
9697 if (!NIL_P(fd)) {
9698 return io_initialize(io, fd, vmode, opt);
9699 }
9700 }
9701 return rb_open_file(io, fname, vmode, vperm, opt);
9702}
9703
9704/* :nodoc: */
9705static VALUE
9706rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9707{
9708 if (rb_block_given_p()) {
9709 VALUE cname = rb_obj_as_string(klass);
9710
9711 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9712 cname, cname);
9713 }
9714 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9715}
9716
9717
9718/*
9719 * call-seq:
9720 * IO.for_fd(fd, mode = 'r', **opts) -> io
9721 *
9722 * Synonym for IO.new.
9723 *
9724 */
9725
9726static VALUE
9727rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9728{
9729 VALUE io = rb_obj_alloc(klass);
9730 rb_io_initialize(argc, argv, io);
9731 return io;
9732}
9733
9734/*
9735 * call-seq:
9736 * ios.autoclose? -> true or false
9737 *
9738 * Returns +true+ if the underlying file descriptor of _ios_ will be
9739 * closed at its finalization or at calling #close, otherwise +false+.
9740 */
9741
9742static VALUE
9743rb_io_autoclose_p(VALUE io)
9744{
9745 rb_io_t *fptr = RFILE(io)->fptr;
9746 rb_io_check_closed(fptr);
9747 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9748}
9749
9750/*
9751 * call-seq:
9752 * io.autoclose = bool -> true or false
9753 *
9754 * Sets auto-close flag.
9755 *
9756 * f = File.open(File::NULL)
9757 * IO.for_fd(f.fileno).close
9758 * f.gets # raises Errno::EBADF
9759 *
9760 * f = File.open(File::NULL)
9761 * g = IO.for_fd(f.fileno)
9762 * g.autoclose = false
9763 * g.close
9764 * f.gets # won't cause Errno::EBADF
9765 */
9766
9767static VALUE
9768rb_io_set_autoclose(VALUE io, VALUE autoclose)
9769{
9770 rb_io_t *fptr;
9771 GetOpenFile(io, fptr);
9772 if (!RTEST(autoclose))
9773 fptr->mode |= FMODE_EXTERNAL;
9774 else
9775 fptr->mode &= ~FMODE_EXTERNAL;
9776 return autoclose;
9777}
9778
9779static VALUE
9780io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9781{
9782 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9783
9784 if (!RB_TEST(result)) {
9785 return Qnil;
9786 }
9787
9788 int mask = RB_NUM2INT(result);
9789
9790 if (mask & event) {
9791 if (return_io)
9792 return io;
9793 else
9794 return result;
9795 }
9796 else {
9797 return Qfalse;
9798 }
9799}
9800
9801/*
9802 * call-seq:
9803 * io.wait_readable -> truthy or falsy
9804 * io.wait_readable(timeout) -> truthy or falsy
9805 *
9806 * Waits until IO is readable and returns a truthy value, or a falsy
9807 * value when times out. Returns a truthy value immediately when
9808 * buffered data is available.
9809 */
9810
9811static VALUE
9812io_wait_readable(int argc, VALUE *argv, VALUE io)
9813{
9814 rb_io_t *fptr;
9815
9816 RB_IO_POINTER(io, fptr);
9818
9819 if (rb_io_read_pending(fptr)) return Qtrue;
9820
9821 rb_check_arity(argc, 0, 1);
9822 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9823
9824 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9825}
9826
9827/*
9828 * call-seq:
9829 * io.wait_writable -> truthy or falsy
9830 * io.wait_writable(timeout) -> truthy or falsy
9831 *
9832 * Waits until IO is writable and returns a truthy value or a falsy
9833 * value when times out.
9834 */
9835static VALUE
9836io_wait_writable(int argc, VALUE *argv, VALUE io)
9837{
9838 rb_io_t *fptr;
9839
9840 RB_IO_POINTER(io, fptr);
9842
9843 rb_check_arity(argc, 0, 1);
9844 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9845
9846 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9847}
9848
9849/*
9850 * call-seq:
9851 * io.wait_priority -> truthy or falsy
9852 * io.wait_priority(timeout) -> truthy or falsy
9853 *
9854 * Waits until IO is priority and returns a truthy value or a falsy
9855 * value when times out. Priority data is sent and received using
9856 * the Socket::MSG_OOB flag and is typically limited to streams.
9857 */
9858static VALUE
9859io_wait_priority(int argc, VALUE *argv, VALUE io)
9860{
9861 rb_io_t *fptr = NULL;
9862
9863 RB_IO_POINTER(io, fptr);
9865
9866 if (rb_io_read_pending(fptr)) return Qtrue;
9867
9868 rb_check_arity(argc, 0, 1);
9869 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9870
9871 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9872}
9873
9874static int
9875wait_mode_sym(VALUE mode)
9876{
9877 if (mode == ID2SYM(rb_intern("r"))) {
9878 return RB_WAITFD_IN;
9879 }
9880 if (mode == ID2SYM(rb_intern("read"))) {
9881 return RB_WAITFD_IN;
9882 }
9883 if (mode == ID2SYM(rb_intern("readable"))) {
9884 return RB_WAITFD_IN;
9885 }
9886 if (mode == ID2SYM(rb_intern("w"))) {
9887 return RB_WAITFD_OUT;
9888 }
9889 if (mode == ID2SYM(rb_intern("write"))) {
9890 return RB_WAITFD_OUT;
9891 }
9892 if (mode == ID2SYM(rb_intern("writable"))) {
9893 return RB_WAITFD_OUT;
9894 }
9895 if (mode == ID2SYM(rb_intern("rw"))) {
9896 return RB_WAITFD_IN|RB_WAITFD_OUT;
9897 }
9898 if (mode == ID2SYM(rb_intern("read_write"))) {
9899 return RB_WAITFD_IN|RB_WAITFD_OUT;
9900 }
9901 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9902 return RB_WAITFD_IN|RB_WAITFD_OUT;
9903 }
9904
9905 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9906}
9907
9908static inline enum rb_io_event
9909io_event_from_value(VALUE value)
9910{
9911 int events = RB_NUM2INT(value);
9912
9913 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9914
9915 return events;
9916}
9917
9918/*
9919 * call-seq:
9920 * io.wait(events, timeout) -> event mask, false or nil
9921 * io.wait(*event_symbols[, timeout]) -> self, true, or false
9922 *
9923 * Waits until the IO becomes ready for the specified events and returns the
9924 * subset of events that become ready, or a falsy value when times out.
9925 *
9926 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9927 * +IO::PRIORITY+.
9928 *
9929 * Returns an event mask (truthy value) immediately when buffered data is
9930 * available.
9931 *
9932 * The second form: if one or more event symbols (+:read+, +:write+, or
9933 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
9934 * corresponding to those symbols. In this form, +timeout+ is optional, the
9935 * order of the arguments is arbitrary, and returns +io+ if any of the
9936 * events is ready.
9937 */
9938
9939static VALUE
9940io_wait(int argc, VALUE *argv, VALUE io)
9941{
9942 VALUE timeout = Qundef;
9943 enum rb_io_event events = 0;
9944 int return_io = 0;
9945
9946 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9947 // We'd prefer to return the actual mask, but this form would return the io itself:
9948 return_io = 1;
9949
9950 // Slow/messy path:
9951 for (int i = 0; i < argc; i += 1) {
9952 if (RB_SYMBOL_P(argv[i])) {
9953 events |= wait_mode_sym(argv[i]);
9954 }
9955 else if (UNDEF_P(timeout)) {
9956 rb_time_interval(timeout = argv[i]);
9957 }
9958 else {
9959 rb_raise(rb_eArgError, "timeout given more than once");
9960 }
9961 }
9962
9963 if (UNDEF_P(timeout)) timeout = Qnil;
9964
9965 if (events == 0) {
9966 events = RUBY_IO_READABLE;
9967 }
9968 }
9969 else /* argc == 2 and neither are symbols */ {
9970 // This is the fast path:
9971 events = io_event_from_value(argv[0]);
9972 timeout = argv[1];
9973 }
9974
9975 if (events & RUBY_IO_READABLE) {
9976 rb_io_t *fptr = NULL;
9977 RB_IO_POINTER(io, fptr);
9978
9979 if (rb_io_read_pending(fptr)) {
9980 // This was the original behaviour:
9981 if (return_io) return Qtrue;
9982 // New behaviour always returns an event mask:
9983 else return RB_INT2NUM(RUBY_IO_READABLE);
9984 }
9985 }
9986
9987 return io_wait_event(io, events, timeout, return_io);
9988}
9989
9990static void
9991argf_mark_and_move(void *ptr)
9992{
9993 struct argf *p = ptr;
9994 rb_gc_mark_and_move(&p->filename);
9995 rb_gc_mark_and_move(&p->current_file);
9996 rb_gc_mark_and_move(&p->argv);
9997 rb_gc_mark_and_move(&p->inplace);
9998 rb_gc_mark_and_move(&p->encs.ecopts);
9999}
10000
10001static size_t
10002argf_memsize(const void *ptr)
10003{
10004 const struct argf *p = ptr;
10005 size_t size = sizeof(*p);
10006 return size;
10007}
10008
10009static const rb_data_type_t argf_type = {
10010 "ARGF",
10011 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10012 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
10013};
10014
10015static inline void
10016argf_init(struct argf *p, VALUE v)
10017{
10018 p->filename = Qnil;
10019 p->current_file = Qnil;
10020 p->lineno = 0;
10021 p->argv = v;
10022}
10023
10024static VALUE
10025argf_alloc(VALUE klass)
10026{
10027 struct argf *p;
10028 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10029
10030 argf_init(p, Qnil);
10031 return argf;
10032}
10033
10034#undef rb_argv
10035
10036/* :nodoc: */
10037static VALUE
10038argf_initialize(VALUE argf, VALUE argv)
10039{
10040 memset(&ARGF, 0, sizeof(ARGF));
10041 argf_init(&ARGF, argv);
10042
10043 return argf;
10044}
10045
10046/* :nodoc: */
10047static VALUE
10048argf_initialize_copy(VALUE argf, VALUE orig)
10049{
10050 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10051 ARGF = argf_of(orig);
10052 ARGF.argv = rb_obj_dup(ARGF.argv);
10053 return argf;
10054}
10055
10056/*
10057 * call-seq:
10058 * ARGF.lineno = integer -> integer
10059 *
10060 * Sets the line number of ARGF as a whole to the given Integer.
10061 *
10062 * ARGF sets the line number automatically as you read data, so normally
10063 * you will not need to set it explicitly. To access the current line number
10064 * use ARGF.lineno.
10065 *
10066 * For example:
10067 *
10068 * ARGF.lineno #=> 0
10069 * ARGF.readline #=> "This is line 1\n"
10070 * ARGF.lineno #=> 1
10071 * ARGF.lineno = 0 #=> 0
10072 * ARGF.lineno #=> 0
10073 */
10074static VALUE
10075argf_set_lineno(VALUE argf, VALUE val)
10076{
10077 ARGF.lineno = NUM2INT(val);
10078 ARGF.last_lineno = ARGF.lineno;
10079 return val;
10080}
10081
10082/*
10083 * call-seq:
10084 * ARGF.lineno -> integer
10085 *
10086 * Returns the current line number of ARGF as a whole. This value
10087 * can be set manually with ARGF.lineno=.
10088 *
10089 * For example:
10090 *
10091 * ARGF.lineno #=> 0
10092 * ARGF.readline #=> "This is line 1\n"
10093 * ARGF.lineno #=> 1
10094 */
10095static VALUE
10096argf_lineno(VALUE argf)
10097{
10098 return INT2FIX(ARGF.lineno);
10099}
10100
10101static VALUE
10102argf_forward(int argc, VALUE *argv, VALUE argf)
10103{
10104 return forward_current(rb_frame_this_func(), argc, argv);
10105}
10106
10107#define next_argv() argf_next_argv(argf)
10108#define ARGF_GENERIC_INPUT_P() \
10109 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10110#define ARGF_FORWARD(argc, argv) do {\
10111 if (ARGF_GENERIC_INPUT_P())\
10112 return argf_forward((argc), (argv), argf);\
10113} while (0)
10114#define NEXT_ARGF_FORWARD(argc, argv) do {\
10115 if (!next_argv()) return Qnil;\
10116 ARGF_FORWARD((argc), (argv));\
10117} while (0)
10118
10119static void
10120argf_close(VALUE argf)
10121{
10122 VALUE file = ARGF.current_file;
10123 if (file == rb_stdin) return;
10124 if (RB_TYPE_P(file, T_FILE)) {
10125 rb_io_set_write_io(file, Qnil);
10126 }
10127 io_close(file);
10128 ARGF.init_p = -1;
10129}
10130
10131static int
10132argf_next_argv(VALUE argf)
10133{
10134 char *fn;
10135 rb_io_t *fptr;
10136 int stdout_binmode = 0;
10137 enum rb_io_mode fmode;
10138
10139 VALUE r_stdout = rb_ractor_stdout();
10140
10141 if (RB_TYPE_P(r_stdout, T_FILE)) {
10142 GetOpenFile(r_stdout, fptr);
10143 if (fptr->mode & FMODE_BINMODE)
10144 stdout_binmode = 1;
10145 }
10146
10147 if (ARGF.init_p == 0) {
10148 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10149 ARGF.next_p = 1;
10150 }
10151 else {
10152 ARGF.next_p = -1;
10153 }
10154 ARGF.init_p = 1;
10155 }
10156 else {
10157 if (NIL_P(ARGF.argv)) {
10158 ARGF.next_p = -1;
10159 }
10160 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10161 ARGF.next_p = 1;
10162 }
10163 }
10164
10165 if (ARGF.next_p == 1) {
10166 if (ARGF.init_p == 1) argf_close(argf);
10167 retry:
10168 if (RARRAY_LEN(ARGF.argv) > 0) {
10169 VALUE filename = rb_ary_shift(ARGF.argv);
10170 FilePathValue(filename);
10171 ARGF.filename = filename;
10172 filename = rb_str_encode_ospath(filename);
10173 fn = StringValueCStr(filename);
10174 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10175 ARGF.current_file = rb_stdin;
10176 if (ARGF.inplace) {
10177 rb_warn("Can't do inplace edit for stdio; skipping");
10178 goto retry;
10179 }
10180 }
10181 else {
10182 VALUE write_io = Qnil;
10183 int fr = rb_sysopen(filename, O_RDONLY, 0);
10184
10185 if (ARGF.inplace) {
10186 struct stat st;
10187#ifndef NO_SAFE_RENAME
10188 struct stat st2;
10189#endif
10190 VALUE str;
10191 int fw;
10192
10193 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10194 rb_io_close(r_stdout);
10195 }
10196 fstat(fr, &st);
10197 str = filename;
10198 if (!NIL_P(ARGF.inplace)) {
10199 VALUE suffix = ARGF.inplace;
10200 str = rb_str_dup(str);
10201 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10202 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10203 rb_enc_get(suffix), 0, Qnil))) {
10204 rb_str_append(str, suffix);
10205 }
10206#ifdef NO_SAFE_RENAME
10207 (void)close(fr);
10208 (void)unlink(RSTRING_PTR(str));
10209 if (rename(fn, RSTRING_PTR(str)) < 0) {
10210 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10211 filename, str, strerror(errno));
10212 goto retry;
10213 }
10214 fr = rb_sysopen(str, O_RDONLY, 0);
10215#else
10216 if (rename(fn, RSTRING_PTR(str)) < 0) {
10217 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10218 filename, str, strerror(errno));
10219 close(fr);
10220 goto retry;
10221 }
10222#endif
10223 }
10224 else {
10225#ifdef NO_SAFE_RENAME
10226 rb_fatal("Can't do inplace edit without backup");
10227#else
10228 if (unlink(fn) < 0) {
10229 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10230 filename, strerror(errno));
10231 close(fr);
10232 goto retry;
10233 }
10234#endif
10235 }
10236 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10237#ifndef NO_SAFE_RENAME
10238 fstat(fw, &st2);
10239#ifdef HAVE_FCHMOD
10240 fchmod(fw, st.st_mode);
10241#else
10242 chmod(fn, st.st_mode);
10243#endif
10244 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10245 int err;
10246#ifdef HAVE_FCHOWN
10247 err = fchown(fw, st.st_uid, st.st_gid);
10248#else
10249 err = chown(fn, st.st_uid, st.st_gid);
10250#endif
10251 if (err && getuid() == 0 && st2.st_uid == 0) {
10252 const char *wkfn = RSTRING_PTR(filename);
10253 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10254 filename, str, strerror(errno));
10255 (void)close(fr);
10256 (void)close(fw);
10257 (void)unlink(wkfn);
10258 goto retry;
10259 }
10260 }
10261#endif
10262 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10263 rb_ractor_stdout_set(write_io);
10264 if (stdout_binmode) rb_io_binmode(rb_stdout);
10265 }
10266 fmode = FMODE_READABLE;
10267 if (!ARGF.binmode) {
10268 fmode |= DEFAULT_TEXTMODE;
10269 }
10270 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10271 if (!NIL_P(write_io)) {
10272 rb_io_set_write_io(ARGF.current_file, write_io);
10273 }
10274 RB_GC_GUARD(filename);
10275 }
10276 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10277 GetOpenFile(ARGF.current_file, fptr);
10278 if (ARGF.encs.enc) {
10279 fptr->encs = ARGF.encs;
10280 clear_codeconv(fptr);
10281 }
10282 else {
10284 if (!ARGF.binmode) {
10286#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10287 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10288#endif
10289 }
10290 }
10291 ARGF.next_p = 0;
10292 }
10293 else {
10294 ARGF.next_p = 1;
10295 return FALSE;
10296 }
10297 }
10298 else if (ARGF.next_p == -1) {
10299 ARGF.current_file = rb_stdin;
10300 ARGF.filename = rb_str_new2("-");
10301 if (ARGF.inplace) {
10302 rb_warn("Can't do inplace edit for stdio");
10303 rb_ractor_stdout_set(orig_stdout);
10304 }
10305 }
10306 if (ARGF.init_p == -1) ARGF.init_p = 1;
10307 return TRUE;
10308}
10309
10310static VALUE
10311argf_getline(int argc, VALUE *argv, VALUE argf)
10312{
10313 VALUE line;
10314 long lineno = ARGF.lineno;
10315
10316 retry:
10317 if (!next_argv()) return Qnil;
10318 if (ARGF_GENERIC_INPUT_P()) {
10319 line = forward_current(idGets, argc, argv);
10320 }
10321 else {
10322 if (argc == 0 && rb_rs == rb_default_rs) {
10323 line = rb_io_gets(ARGF.current_file);
10324 }
10325 else {
10326 line = rb_io_getline(argc, argv, ARGF.current_file);
10327 }
10328 if (NIL_P(line) && ARGF.next_p != -1) {
10329 argf_close(argf);
10330 ARGF.next_p = 1;
10331 goto retry;
10332 }
10333 }
10334 if (!NIL_P(line)) {
10335 ARGF.lineno = ++lineno;
10336 ARGF.last_lineno = ARGF.lineno;
10337 }
10338 return line;
10339}
10340
10341static VALUE
10342argf_lineno_getter(ID id, VALUE *var)
10343{
10344 VALUE argf = *var;
10345 return INT2FIX(ARGF.last_lineno);
10346}
10347
10348static void
10349argf_lineno_setter(VALUE val, ID id, VALUE *var)
10350{
10351 VALUE argf = *var;
10352 int n = NUM2INT(val);
10353 ARGF.last_lineno = ARGF.lineno = n;
10354}
10355
10356void
10357rb_reset_argf_lineno(long n)
10358{
10359 ARGF.last_lineno = ARGF.lineno = n;
10360}
10361
10362static VALUE argf_gets(int, VALUE *, VALUE);
10363
10364/*
10365 * call-seq:
10366 * gets(sep=$/ [, getline_args]) -> string or nil
10367 * gets(limit [, getline_args]) -> string or nil
10368 * gets(sep, limit [, getline_args]) -> string or nil
10369 *
10370 * Returns (and assigns to <code>$_</code>) the next line from the list
10371 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10372 * no files are present on the command line. Returns +nil+ at end of
10373 * file. The optional argument specifies the record separator. The
10374 * separator is included with the contents of each record. A separator
10375 * of +nil+ reads the entire contents, and a zero-length separator
10376 * reads the input one paragraph at a time, where paragraphs are
10377 * divided by two consecutive newlines. If the first argument is an
10378 * integer, or optional second argument is given, the returning string
10379 * would not be longer than the given value in bytes. If multiple
10380 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10381 * the contents one file at a time.
10382 *
10383 * ARGV << "testfile"
10384 * print while gets
10385 *
10386 * <em>produces:</em>
10387 *
10388 * This is line one
10389 * This is line two
10390 * This is line three
10391 * And so on...
10392 *
10393 * The style of programming using <code>$_</code> as an implicit
10394 * parameter is gradually losing favor in the Ruby community.
10395 */
10396
10397static VALUE
10398rb_f_gets(int argc, VALUE *argv, VALUE recv)
10399{
10400 if (recv == argf) {
10401 return argf_gets(argc, argv, argf);
10402 }
10403 return forward(argf, idGets, argc, argv);
10404}
10405
10406/*
10407 * call-seq:
10408 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10409 * ARGF.gets(limit [, getline_args]) -> string or nil
10410 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10411 *
10412 * Returns the next line from the current file in ARGF.
10413 *
10414 * By default lines are assumed to be separated by <code>$/</code>;
10415 * to use a different character as a separator, supply it as a String
10416 * for the _sep_ argument.
10417 *
10418 * The optional _limit_ argument specifies how many characters of each line
10419 * to return. By default all characters are returned.
10420 *
10421 * See IO.readlines for details about getline_args.
10422 *
10423 */
10424static VALUE
10425argf_gets(int argc, VALUE *argv, VALUE argf)
10426{
10427 VALUE line;
10428
10429 line = argf_getline(argc, argv, argf);
10430 rb_lastline_set(line);
10431
10432 return line;
10433}
10434
10435VALUE
10437{
10438 VALUE line;
10439
10440 if (rb_rs != rb_default_rs) {
10441 return rb_f_gets(0, 0, argf);
10442 }
10443
10444 retry:
10445 if (!next_argv()) return Qnil;
10446 line = rb_io_gets(ARGF.current_file);
10447 if (NIL_P(line) && ARGF.next_p != -1) {
10448 rb_io_close(ARGF.current_file);
10449 ARGF.next_p = 1;
10450 goto retry;
10451 }
10452 rb_lastline_set(line);
10453 if (!NIL_P(line)) {
10454 ARGF.lineno++;
10455 ARGF.last_lineno = ARGF.lineno;
10456 }
10457
10458 return line;
10459}
10460
10461static VALUE argf_readline(int, VALUE *, VALUE);
10462
10463/*
10464 * call-seq:
10465 * readline(sep = $/, chomp: false) -> string
10466 * readline(limit, chomp: false) -> string
10467 * readline(sep, limit, chomp: false) -> string
10468 *
10469 * Equivalent to method Kernel#gets, except that it raises an exception
10470 * if called at end-of-stream:
10471 *
10472 * $ cat t.txt | ruby -e "p readlines; readline"
10473 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10474 * in `readline': end of file reached (EOFError)
10475 *
10476 * Optional keyword argument +chomp+ specifies whether line separators
10477 * are to be omitted.
10478 */
10479
10480static VALUE
10481rb_f_readline(int argc, VALUE *argv, VALUE recv)
10482{
10483 if (recv == argf) {
10484 return argf_readline(argc, argv, argf);
10485 }
10486 return forward(argf, rb_intern("readline"), argc, argv);
10487}
10488
10489
10490/*
10491 * call-seq:
10492 * ARGF.readline(sep=$/) -> string
10493 * ARGF.readline(limit) -> string
10494 * ARGF.readline(sep, limit) -> string
10495 *
10496 * Returns the next line from the current file in ARGF.
10497 *
10498 * By default lines are assumed to be separated by <code>$/</code>;
10499 * to use a different character as a separator, supply it as a String
10500 * for the _sep_ argument.
10501 *
10502 * The optional _limit_ argument specifies how many characters of each line
10503 * to return. By default all characters are returned.
10504 *
10505 * An EOFError is raised at the end of the file.
10506 */
10507static VALUE
10508argf_readline(int argc, VALUE *argv, VALUE argf)
10509{
10510 VALUE line;
10511
10512 if (!next_argv()) rb_eof_error();
10513 ARGF_FORWARD(argc, argv);
10514 line = argf_gets(argc, argv, argf);
10515 if (NIL_P(line)) {
10516 rb_eof_error();
10517 }
10518
10519 return line;
10520}
10521
10522static VALUE argf_readlines(int, VALUE *, VALUE);
10523
10524/*
10525 * call-seq:
10526 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10527 * readlines(limit, chomp: false, **enc_opts) -> array
10528 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10529 *
10530 * Returns an array containing the lines returned by calling
10531 * Kernel#gets until the end-of-stream is reached;
10532 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10533 *
10534 * With only string argument +sep+ given,
10535 * returns the remaining lines as determined by line separator +sep+,
10536 * or +nil+ if none;
10537 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10538 *
10539 * # Default separator.
10540 * $ cat t.txt | ruby -e "p readlines"
10541 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10542 *
10543 * # Specified separator.
10544 * $ cat t.txt | ruby -e "p readlines 'li'"
10545 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10546 *
10547 * # Get-all separator.
10548 * $ cat t.txt | ruby -e "p readlines nil"
10549 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10550 *
10551 * # Get-paragraph separator.
10552 * $ cat t.txt | ruby -e "p readlines ''"
10553 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10554 *
10555 * With only integer argument +limit+ given,
10556 * limits the number of bytes in the line;
10557 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10558 *
10559 * $cat t.txt | ruby -e "p readlines 10"
10560 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10561 *
10562 * $cat t.txt | ruby -e "p readlines 11"
10563 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10564 *
10565 * $cat t.txt | ruby -e "p readlines 12"
10566 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10567 *
10568 * With arguments +sep+ and +limit+ given,
10569 * combines the two behaviors
10570 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10571 *
10572 * Optional keyword argument +chomp+ specifies whether line separators
10573 * are to be omitted:
10574 *
10575 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10576 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10577 *
10578 * Optional keyword arguments +enc_opts+ specify encoding options;
10579 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10580 *
10581 */
10582
10583static VALUE
10584rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10585{
10586 if (recv == argf) {
10587 return argf_readlines(argc, argv, argf);
10588 }
10589 return forward(argf, rb_intern("readlines"), argc, argv);
10590}
10591
10592/*
10593 * call-seq:
10594 * ARGF.readlines(sep = $/, chomp: false) -> array
10595 * ARGF.readlines(limit, chomp: false) -> array
10596 * ARGF.readlines(sep, limit, chomp: false) -> array
10597 *
10598 * ARGF.to_a(sep = $/, chomp: false) -> array
10599 * ARGF.to_a(limit, chomp: false) -> array
10600 * ARGF.to_a(sep, limit, chomp: false) -> array
10601 *
10602 * Reads each file in ARGF in its entirety, returning an Array containing
10603 * lines from the files. Lines are assumed to be separated by _sep_.
10604 *
10605 * lines = ARGF.readlines
10606 * lines[0] #=> "This is line one\n"
10607 *
10608 * See +IO.readlines+ for a full description of all options.
10609 */
10610static VALUE
10611argf_readlines(int argc, VALUE *argv, VALUE argf)
10612{
10613 long lineno = ARGF.lineno;
10614 VALUE lines, ary;
10615
10616 ary = rb_ary_new();
10617 while (next_argv()) {
10618 if (ARGF_GENERIC_INPUT_P()) {
10619 lines = forward_current(rb_intern("readlines"), argc, argv);
10620 }
10621 else {
10622 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10623 argf_close(argf);
10624 }
10625 ARGF.next_p = 1;
10626 rb_ary_concat(ary, lines);
10627 ARGF.lineno = lineno + RARRAY_LEN(ary);
10628 ARGF.last_lineno = ARGF.lineno;
10629 }
10630 ARGF.init_p = 0;
10631 return ary;
10632}
10633
10634/*
10635 * call-seq:
10636 * `command` -> string
10637 *
10638 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10639 * sets global variable <tt>$?</tt> to the process status.
10640 *
10641 * This method has potential security vulnerabilities if called with untrusted input;
10642 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
10643 *
10644 * Examples:
10645 *
10646 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10647 * $ `echo oops && exit 99` # => "oops\n"
10648 * $ $? # => #<Process::Status: pid 17088 exit 99>
10649 * $ $?.exitstatus # => 99
10650 *
10651 * The built-in syntax <tt>%x{...}</tt> uses this method.
10652 *
10653 */
10654
10655static VALUE
10656rb_f_backquote(VALUE obj, VALUE str)
10657{
10658 VALUE port;
10659 VALUE result;
10660 rb_io_t *fptr;
10661
10662 StringValue(str);
10663 rb_last_status_clear();
10664 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10665 if (NIL_P(port)) return rb_str_new(0,0);
10666
10667 GetOpenFile(port, fptr);
10668 result = read_all(fptr, remain_size(fptr), Qnil);
10669 rb_io_close(port);
10670 rb_io_fptr_cleanup_all(fptr);
10671 RB_GC_GUARD(port);
10672
10673 return result;
10674}
10675
10676#ifdef HAVE_SYS_SELECT_H
10677#include <sys/select.h>
10678#endif
10679
10680static VALUE
10681select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10682{
10683 VALUE res, list;
10684 rb_fdset_t *rp, *wp, *ep;
10685 rb_io_t *fptr;
10686 long i;
10687 int max = 0, n;
10688 int pending = 0;
10689 struct timeval timerec;
10690
10691 if (!NIL_P(read)) {
10692 Check_Type(read, T_ARRAY);
10693 for (i=0; i<RARRAY_LEN(read); i++) {
10694 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10695 rb_fd_set(fptr->fd, &fds[0]);
10696 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10697 pending++;
10698 rb_fd_set(fptr->fd, &fds[3]);
10699 }
10700 if (max < fptr->fd) max = fptr->fd;
10701 }
10702 if (pending) { /* no blocking if there's buffered data */
10703 timerec.tv_sec = timerec.tv_usec = 0;
10704 tp = &timerec;
10705 }
10706 rp = &fds[0];
10707 }
10708 else
10709 rp = 0;
10710
10711 if (!NIL_P(write)) {
10712 Check_Type(write, T_ARRAY);
10713 for (i=0; i<RARRAY_LEN(write); i++) {
10714 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10715 GetOpenFile(write_io, fptr);
10716 rb_fd_set(fptr->fd, &fds[1]);
10717 if (max < fptr->fd) max = fptr->fd;
10718 }
10719 wp = &fds[1];
10720 }
10721 else
10722 wp = 0;
10723
10724 if (!NIL_P(except)) {
10725 Check_Type(except, T_ARRAY);
10726 for (i=0; i<RARRAY_LEN(except); i++) {
10727 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10728 VALUE write_io = GetWriteIO(io);
10729 GetOpenFile(io, fptr);
10730 rb_fd_set(fptr->fd, &fds[2]);
10731 if (max < fptr->fd) max = fptr->fd;
10732 if (io != write_io) {
10733 GetOpenFile(write_io, fptr);
10734 rb_fd_set(fptr->fd, &fds[2]);
10735 if (max < fptr->fd) max = fptr->fd;
10736 }
10737 }
10738 ep = &fds[2];
10739 }
10740 else {
10741 ep = 0;
10742 }
10743
10744 max++;
10745
10746 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10747 if (n < 0) {
10748 rb_sys_fail(0);
10749 }
10750 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10751
10752 res = rb_ary_new2(3);
10753 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10754 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10755 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10756
10757 if (rp) {
10758 list = RARRAY_AREF(res, 0);
10759 for (i=0; i< RARRAY_LEN(read); i++) {
10760 VALUE obj = rb_ary_entry(read, i);
10761 VALUE io = rb_io_get_io(obj);
10762 GetOpenFile(io, fptr);
10763 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10764 rb_fd_isset(fptr->fd, &fds[3])) {
10765 rb_ary_push(list, obj);
10766 }
10767 }
10768 }
10769
10770 if (wp) {
10771 list = RARRAY_AREF(res, 1);
10772 for (i=0; i< RARRAY_LEN(write); i++) {
10773 VALUE obj = rb_ary_entry(write, i);
10774 VALUE io = rb_io_get_io(obj);
10775 VALUE write_io = GetWriteIO(io);
10776 GetOpenFile(write_io, fptr);
10777 if (rb_fd_isset(fptr->fd, &fds[1])) {
10778 rb_ary_push(list, obj);
10779 }
10780 }
10781 }
10782
10783 if (ep) {
10784 list = RARRAY_AREF(res, 2);
10785 for (i=0; i< RARRAY_LEN(except); i++) {
10786 VALUE obj = rb_ary_entry(except, i);
10787 VALUE io = rb_io_get_io(obj);
10788 VALUE write_io = GetWriteIO(io);
10789 GetOpenFile(io, fptr);
10790 if (rb_fd_isset(fptr->fd, &fds[2])) {
10791 rb_ary_push(list, obj);
10792 }
10793 else if (io != write_io) {
10794 GetOpenFile(write_io, fptr);
10795 if (rb_fd_isset(fptr->fd, &fds[2])) {
10796 rb_ary_push(list, obj);
10797 }
10798 }
10799 }
10800 }
10801
10802 return res; /* returns an empty array on interrupt */
10803}
10804
10806 VALUE read, write, except;
10807 struct timeval *timeout;
10808 rb_fdset_t fdsets[4];
10809};
10810
10811static VALUE
10812select_call(VALUE arg)
10813{
10814 struct select_args *p = (struct select_args *)arg;
10815
10816 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10817}
10818
10819static VALUE
10820select_end(VALUE arg)
10821{
10822 struct select_args *p = (struct select_args *)arg;
10823 int i;
10824
10825 for (i = 0; i < numberof(p->fdsets); ++i)
10826 rb_fd_term(&p->fdsets[i]);
10827 return Qnil;
10828}
10829
10830static VALUE sym_normal, sym_sequential, sym_random,
10831 sym_willneed, sym_dontneed, sym_noreuse;
10832
10833#ifdef HAVE_POSIX_FADVISE
10834struct io_advise_struct {
10835 int fd;
10836 int advice;
10837 rb_off_t offset;
10838 rb_off_t len;
10839};
10840
10841static VALUE
10842io_advise_internal(void *arg)
10843{
10844 struct io_advise_struct *ptr = arg;
10845 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10846}
10847
10848static VALUE
10849io_advise_sym_to_const(VALUE sym)
10850{
10851#ifdef POSIX_FADV_NORMAL
10852 if (sym == sym_normal)
10853 return INT2NUM(POSIX_FADV_NORMAL);
10854#endif
10855
10856#ifdef POSIX_FADV_RANDOM
10857 if (sym == sym_random)
10858 return INT2NUM(POSIX_FADV_RANDOM);
10859#endif
10860
10861#ifdef POSIX_FADV_SEQUENTIAL
10862 if (sym == sym_sequential)
10863 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10864#endif
10865
10866#ifdef POSIX_FADV_WILLNEED
10867 if (sym == sym_willneed)
10868 return INT2NUM(POSIX_FADV_WILLNEED);
10869#endif
10870
10871#ifdef POSIX_FADV_DONTNEED
10872 if (sym == sym_dontneed)
10873 return INT2NUM(POSIX_FADV_DONTNEED);
10874#endif
10875
10876#ifdef POSIX_FADV_NOREUSE
10877 if (sym == sym_noreuse)
10878 return INT2NUM(POSIX_FADV_NOREUSE);
10879#endif
10880
10881 return Qnil;
10882}
10883
10884static VALUE
10885do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10886{
10887 int rv;
10888 struct io_advise_struct ias;
10889 VALUE num_adv;
10890
10891 num_adv = io_advise_sym_to_const(advice);
10892
10893 /*
10894 * The platform doesn't support this hint. We don't raise exception, instead
10895 * silently ignore it. Because IO::advise is only hint.
10896 */
10897 if (NIL_P(num_adv))
10898 return Qnil;
10899
10900 ias.fd = fptr->fd;
10901 ias.advice = NUM2INT(num_adv);
10902 ias.offset = offset;
10903 ias.len = len;
10904
10905 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10906 if (rv && rv != ENOSYS) {
10907 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10908 it returns the error code. */
10909 VALUE message = rb_sprintf("%"PRIsVALUE" "
10910 "(%"PRI_OFFT_PREFIX"d, "
10911 "%"PRI_OFFT_PREFIX"d, "
10912 "%"PRIsVALUE")",
10913 fptr->pathv, offset, len, advice);
10914 rb_syserr_fail_str(rv, message);
10915 }
10916
10917 return Qnil;
10918}
10919
10920#endif /* HAVE_POSIX_FADVISE */
10921
10922static void
10923advice_arg_check(VALUE advice)
10924{
10925 if (!SYMBOL_P(advice))
10926 rb_raise(rb_eTypeError, "advice must be a Symbol");
10927
10928 if (advice != sym_normal &&
10929 advice != sym_sequential &&
10930 advice != sym_random &&
10931 advice != sym_willneed &&
10932 advice != sym_dontneed &&
10933 advice != sym_noreuse) {
10934 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10935 }
10936}
10937
10938/*
10939 * call-seq:
10940 * advise(advice, offset = 0, len = 0) -> nil
10941 *
10942 * Invokes Posix system call
10943 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10944 * which announces an intention to access data from the current file
10945 * in a particular manner.
10946 *
10947 * The arguments and results are platform-dependent.
10948 *
10949 * The relevant data is specified by:
10950 *
10951 * - +offset+: The offset of the first byte of data.
10952 * - +len+: The number of bytes to be accessed;
10953 * if +len+ is zero, or is larger than the number of bytes remaining,
10954 * all remaining bytes will be accessed.
10955 *
10956 * Argument +advice+ is one of the following symbols:
10957 *
10958 * - +:normal+: The application has no advice to give
10959 * about its access pattern for the specified data.
10960 * If no advice is given for an open file, this is the default assumption.
10961 * - +:sequential+: The application expects to access the specified data sequentially
10962 * (with lower offsets read before higher ones).
10963 * - +:random+: The specified data will be accessed in random order.
10964 * - +:noreuse+: The specified data will be accessed only once.
10965 * - +:willneed+: The specified data will be accessed in the near future.
10966 * - +:dontneed+: The specified data will not be accessed in the near future.
10967 *
10968 * Not implemented on all platforms.
10969 *
10970 */
10971static VALUE
10972rb_io_advise(int argc, VALUE *argv, VALUE io)
10973{
10974 VALUE advice, offset, len;
10975 rb_off_t off, l;
10976 rb_io_t *fptr;
10977
10978 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10979 advice_arg_check(advice);
10980
10981 io = GetWriteIO(io);
10982 GetOpenFile(io, fptr);
10983
10984 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10985 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10986
10987#ifdef HAVE_POSIX_FADVISE
10988 return do_io_advise(fptr, advice, off, l);
10989#else
10990 ((void)off, (void)l); /* Ignore all hint */
10991 return Qnil;
10992#endif
10993}
10994
10995static int
10996is_pos_inf(VALUE x)
10997{
10998 double f;
10999 if (!RB_FLOAT_TYPE_P(x))
11000 return 0;
11001 f = RFLOAT_VALUE(x);
11002 return isinf(f) && 0 < f;
11003}
11004
11005/*
11006 * call-seq:
11007 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11008 *
11009 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
11010 * which monitors multiple file descriptors,
11011 * waiting until one or more of the file descriptors
11012 * becomes ready for some class of I/O operation.
11013 *
11014 * Not implemented on all platforms.
11015 *
11016 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11017 * is an array of IO objects.
11018 *
11019 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11020 * interval in seconds.
11021 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11022 * +nil+ and +Float::INFINITY+ means no timeout.
11023 *
11024 * The method monitors the \IO objects given in all three arrays,
11025 * waiting for some to be ready;
11026 * returns a 3-element array whose elements are:
11027 *
11028 * - An array of the objects in +read_ios+ that are ready for reading.
11029 * - An array of the objects in +write_ios+ that are ready for writing.
11030 * - An array of the objects in +error_ios+ have pending exceptions.
11031 *
11032 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11033 *
11034 * \IO.select peeks the buffer of \IO objects for testing readability.
11035 * If the \IO buffer is not empty, \IO.select immediately notifies
11036 * readability. This "peek" only happens for \IO objects. It does not
11037 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11038 *
11039 * The best way to use \IO.select is invoking it after non-blocking
11040 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11041 * raise an exception which is extended by IO::WaitReadable or
11042 * IO::WaitWritable. The modules notify how the caller should wait
11043 * with \IO.select. If IO::WaitReadable is raised, the caller should
11044 * wait for reading. If IO::WaitWritable is raised, the caller should
11045 * wait for writing.
11046 *
11047 * So, blocking read (#readpartial) can be emulated using
11048 * #read_nonblock and \IO.select as follows:
11049 *
11050 * begin
11051 * result = io_like.read_nonblock(maxlen)
11052 * rescue IO::WaitReadable
11053 * IO.select([io_like])
11054 * retry
11055 * rescue IO::WaitWritable
11056 * IO.select(nil, [io_like])
11057 * retry
11058 * end
11059 *
11060 * Especially, the combination of non-blocking methods and \IO.select is
11061 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11062 * has #to_io method to return underlying IO object. IO.select calls
11063 * #to_io to obtain the file descriptor to wait.
11064 *
11065 * This means that readability notified by \IO.select doesn't mean
11066 * readability from OpenSSL::SSL::SSLSocket object.
11067 *
11068 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11069 * some data. \IO.select doesn't see the buffer. So \IO.select can
11070 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11071 *
11072 * However, several more complicated situations exist.
11073 *
11074 * SSL is a protocol which is sequence of records.
11075 * The record consists of multiple bytes.
11076 * So, the remote side of SSL sends a partial record, IO.select
11077 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11078 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11079 *
11080 * Also, the remote side can request SSL renegotiation which forces
11081 * the local SSL engine to write some data.
11082 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11083 * system call and it can block.
11084 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11085 * IO::WaitWritable instead of blocking.
11086 * So, the caller should wait for ready for writability as above
11087 * example.
11088 *
11089 * The combination of non-blocking methods and \IO.select is also useful
11090 * for streams such as tty, pipe socket socket when multiple processes
11091 * read from a stream.
11092 *
11093 * Finally, Linux kernel developers don't guarantee that
11094 * readability of select(2) means readability of following read(2) even
11095 * for a single process;
11096 * see {select(2)}[https://linux.die.net/man/2/select]
11097 *
11098 * Invoking \IO.select before IO#readpartial works well as usual.
11099 * However it is not the best way to use \IO.select.
11100 *
11101 * The writability notified by select(2) doesn't show
11102 * how many bytes are writable.
11103 * IO#write method blocks until given whole string is written.
11104 * So, <tt>IO#write(two or more bytes)</tt> can block after
11105 * writability is notified by \IO.select. IO#write_nonblock is required
11106 * to avoid the blocking.
11107 *
11108 * Blocking write (#write) can be emulated using #write_nonblock and
11109 * IO.select as follows: IO::WaitReadable should also be rescued for
11110 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11111 *
11112 * while 0 < string.bytesize
11113 * begin
11114 * written = io_like.write_nonblock(string)
11115 * rescue IO::WaitReadable
11116 * IO.select([io_like])
11117 * retry
11118 * rescue IO::WaitWritable
11119 * IO.select(nil, [io_like])
11120 * retry
11121 * end
11122 * string = string.byteslice(written..-1)
11123 * end
11124 *
11125 * Example:
11126 *
11127 * rp, wp = IO.pipe
11128 * mesg = "ping "
11129 * 100.times {
11130 * # IO.select follows IO#read. Not the best way to use IO.select.
11131 * rs, ws, = IO.select([rp], [wp])
11132 * if r = rs[0]
11133 * ret = r.read(5)
11134 * print ret
11135 * case ret
11136 * when /ping/
11137 * mesg = "pong\n"
11138 * when /pong/
11139 * mesg = "ping "
11140 * end
11141 * end
11142 * if w = ws[0]
11143 * w.write(mesg)
11144 * end
11145 * }
11146 *
11147 * Output:
11148 *
11149 * ping pong
11150 * ping pong
11151 * ping pong
11152 * (snipped)
11153 * ping
11154 *
11155 */
11156
11157static VALUE
11158rb_f_select(int argc, VALUE *argv, VALUE obj)
11159{
11160 VALUE scheduler = rb_fiber_scheduler_current();
11161 if (scheduler != Qnil) {
11162 // It's optionally supported.
11163 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11164 if (!UNDEF_P(result)) return result;
11165 }
11166
11167 VALUE timeout;
11168 struct select_args args;
11169 struct timeval timerec;
11170 int i;
11171
11172 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11173 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11174 args.timeout = 0;
11175 }
11176 else {
11177 timerec = rb_time_interval(timeout);
11178 args.timeout = &timerec;
11179 }
11180
11181 for (i = 0; i < numberof(args.fdsets); ++i)
11182 rb_fd_init(&args.fdsets[i]);
11183
11184 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11185}
11186
11187#ifdef IOCTL_REQ_TYPE
11188 typedef IOCTL_REQ_TYPE ioctl_req_t;
11189#else
11190 typedef int ioctl_req_t;
11191# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11192#endif
11193
11194#ifdef HAVE_IOCTL
11195struct ioctl_arg {
11196 int fd;
11197 ioctl_req_t cmd;
11198 long narg;
11199};
11200
11201static VALUE
11202nogvl_ioctl(void *ptr)
11203{
11204 struct ioctl_arg *arg = ptr;
11205
11206 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11207}
11208
11209static int
11210do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11211{
11212 int retval;
11213 struct ioctl_arg arg;
11214
11215 arg.fd = io->fd;
11216 arg.cmd = cmd;
11217 arg.narg = narg;
11218
11219 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11220
11221 return retval;
11222}
11223#endif
11224
11225#define DEFAULT_IOCTL_NARG_LEN (256)
11226
11227#if defined(__linux__) && defined(_IOC_SIZE)
11228static long
11229linux_iocparm_len(ioctl_req_t cmd)
11230{
11231 long len;
11232
11233 if ((cmd & 0xFFFF0000) == 0) {
11234 /* legacy and unstructured ioctl number. */
11235 return DEFAULT_IOCTL_NARG_LEN;
11236 }
11237
11238 len = _IOC_SIZE(cmd);
11239
11240 /* paranoia check for silly drivers which don't keep ioctl convention */
11241 if (len < DEFAULT_IOCTL_NARG_LEN)
11242 len = DEFAULT_IOCTL_NARG_LEN;
11243
11244 return len;
11245}
11246#endif
11247
11248#ifdef HAVE_IOCTL
11249static long
11250ioctl_narg_len(ioctl_req_t cmd)
11251{
11252 long len;
11253
11254#ifdef IOCPARM_MASK
11255#ifndef IOCPARM_LEN
11256#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11257#endif
11258#endif
11259#ifdef IOCPARM_LEN
11260 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11261#elif defined(__linux__) && defined(_IOC_SIZE)
11262 len = linux_iocparm_len(cmd);
11263#else
11264 /* otherwise guess at what's safe */
11265 len = DEFAULT_IOCTL_NARG_LEN;
11266#endif
11267
11268 return len;
11269}
11270#endif
11271
11272#ifdef HAVE_FCNTL
11273#ifdef __linux__
11274typedef long fcntl_arg_t;
11275#else
11276/* posix */
11277typedef int fcntl_arg_t;
11278#endif
11279
11280static long
11281fcntl_narg_len(ioctl_req_t cmd)
11282{
11283 long len;
11284
11285 switch (cmd) {
11286#ifdef F_DUPFD
11287 case F_DUPFD:
11288 len = sizeof(fcntl_arg_t);
11289 break;
11290#endif
11291#ifdef F_DUP2FD /* bsd specific */
11292 case F_DUP2FD:
11293 len = sizeof(int);
11294 break;
11295#endif
11296#ifdef F_DUPFD_CLOEXEC /* linux specific */
11297 case F_DUPFD_CLOEXEC:
11298 len = sizeof(fcntl_arg_t);
11299 break;
11300#endif
11301#ifdef F_GETFD
11302 case F_GETFD:
11303 len = 1;
11304 break;
11305#endif
11306#ifdef F_SETFD
11307 case F_SETFD:
11308 len = sizeof(fcntl_arg_t);
11309 break;
11310#endif
11311#ifdef F_GETFL
11312 case F_GETFL:
11313 len = 1;
11314 break;
11315#endif
11316#ifdef F_SETFL
11317 case F_SETFL:
11318 len = sizeof(fcntl_arg_t);
11319 break;
11320#endif
11321#ifdef F_GETOWN
11322 case F_GETOWN:
11323 len = 1;
11324 break;
11325#endif
11326#ifdef F_SETOWN
11327 case F_SETOWN:
11328 len = sizeof(fcntl_arg_t);
11329 break;
11330#endif
11331#ifdef F_GETOWN_EX /* linux specific */
11332 case F_GETOWN_EX:
11333 len = sizeof(struct f_owner_ex);
11334 break;
11335#endif
11336#ifdef F_SETOWN_EX /* linux specific */
11337 case F_SETOWN_EX:
11338 len = sizeof(struct f_owner_ex);
11339 break;
11340#endif
11341#ifdef F_GETLK
11342 case F_GETLK:
11343 len = sizeof(struct flock);
11344 break;
11345#endif
11346#ifdef F_SETLK
11347 case F_SETLK:
11348 len = sizeof(struct flock);
11349 break;
11350#endif
11351#ifdef F_SETLKW
11352 case F_SETLKW:
11353 len = sizeof(struct flock);
11354 break;
11355#endif
11356#ifdef F_READAHEAD /* bsd specific */
11357 case F_READAHEAD:
11358 len = sizeof(int);
11359 break;
11360#endif
11361#ifdef F_RDAHEAD /* Darwin specific */
11362 case F_RDAHEAD:
11363 len = sizeof(int);
11364 break;
11365#endif
11366#ifdef F_GETSIG /* linux specific */
11367 case F_GETSIG:
11368 len = 1;
11369 break;
11370#endif
11371#ifdef F_SETSIG /* linux specific */
11372 case F_SETSIG:
11373 len = sizeof(fcntl_arg_t);
11374 break;
11375#endif
11376#ifdef F_GETLEASE /* linux specific */
11377 case F_GETLEASE:
11378 len = 1;
11379 break;
11380#endif
11381#ifdef F_SETLEASE /* linux specific */
11382 case F_SETLEASE:
11383 len = sizeof(fcntl_arg_t);
11384 break;
11385#endif
11386#ifdef F_NOTIFY /* linux specific */
11387 case F_NOTIFY:
11388 len = sizeof(fcntl_arg_t);
11389 break;
11390#endif
11391
11392 default:
11393 len = 256;
11394 break;
11395 }
11396
11397 return len;
11398}
11399#else /* HAVE_FCNTL */
11400static long
11401fcntl_narg_len(ioctl_req_t cmd)
11402{
11403 return 0;
11404}
11405#endif /* HAVE_FCNTL */
11406
11407#define NARG_SENTINEL 17
11408
11409static long
11410setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11411{
11412 long narg = 0;
11413 VALUE arg = *argp;
11414
11415 if (!RTEST(arg)) {
11416 narg = 0;
11417 }
11418 else if (FIXNUM_P(arg)) {
11419 narg = FIX2LONG(arg);
11420 }
11421 else if (arg == Qtrue) {
11422 narg = 1;
11423 }
11424 else {
11425 VALUE tmp = rb_check_string_type(arg);
11426
11427 if (NIL_P(tmp)) {
11428 narg = NUM2LONG(arg);
11429 }
11430 else {
11431 char *ptr;
11432 long len, slen;
11433
11434 *argp = arg = tmp;
11435 len = narg_len(cmd);
11436 rb_str_modify(arg);
11437
11438 slen = RSTRING_LEN(arg);
11439 /* expand for data + sentinel. */
11440 if (slen < len+1) {
11441 rb_str_resize(arg, len+1);
11442 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11443 slen = len+1;
11444 }
11445 /* a little sanity check here */
11446 ptr = RSTRING_PTR(arg);
11447 ptr[slen - 1] = NARG_SENTINEL;
11448 narg = (long)(SIGNED_VALUE)ptr;
11449 }
11450 }
11451
11452 return narg;
11453}
11454
11455static VALUE
11456finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11457{
11458 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11459 if (RB_TYPE_P(arg, T_STRING)) {
11460 char *ptr;
11461 long slen;
11462 RSTRING_GETMEM(arg, ptr, slen);
11463 if (ptr[slen-1] != NARG_SENTINEL)
11464 rb_raise(rb_eArgError, "return value overflowed string");
11465 ptr[slen-1] = '\0';
11466 }
11467
11468 return INT2NUM(retval);
11469}
11470
11471#ifdef HAVE_IOCTL
11472static VALUE
11473rb_ioctl(VALUE io, VALUE req, VALUE arg)
11474{
11475 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11476 rb_io_t *fptr;
11477 long narg;
11478 int retval;
11479
11480 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11481 GetOpenFile(io, fptr);
11482 retval = do_ioctl(fptr, cmd, narg);
11483 return finish_narg(retval, arg, fptr);
11484}
11485
11486/*
11487 * call-seq:
11488 * ioctl(integer_cmd, argument) -> integer
11489 *
11490 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11491 * which issues a low-level command to an I/O device.
11492 *
11493 * Issues a low-level command to an I/O device.
11494 * The arguments and returned value are platform-dependent.
11495 * The effect of the call is platform-dependent.
11496 *
11497 * If argument +argument+ is an integer, it is passed directly;
11498 * if it is a string, it is interpreted as a binary sequence of bytes.
11499 *
11500 * Not implemented on all platforms.
11501 *
11502 */
11503
11504static VALUE
11505rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11506{
11507 VALUE req, arg;
11508
11509 rb_scan_args(argc, argv, "11", &req, &arg);
11510 return rb_ioctl(io, req, arg);
11511}
11512#else
11513#define rb_io_ioctl rb_f_notimplement
11514#endif
11515
11516#ifdef HAVE_FCNTL
11517struct fcntl_arg {
11518 int fd;
11519 int cmd;
11520 long narg;
11521};
11522
11523static VALUE
11524nogvl_fcntl(void *ptr)
11525{
11526 struct fcntl_arg *arg = ptr;
11527
11528#if defined(F_DUPFD)
11529 if (arg->cmd == F_DUPFD)
11530 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11531#endif
11532 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11533}
11534
11535static int
11536do_fcntl(struct rb_io *io, int cmd, long narg)
11537{
11538 int retval;
11539 struct fcntl_arg arg;
11540
11541 arg.fd = io->fd;
11542 arg.cmd = cmd;
11543 arg.narg = narg;
11544
11545 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11546 if (retval != -1) {
11547 switch (cmd) {
11548#if defined(F_DUPFD)
11549 case F_DUPFD:
11550#endif
11551#if defined(F_DUPFD_CLOEXEC)
11552 case F_DUPFD_CLOEXEC:
11553#endif
11554 rb_update_max_fd(retval);
11555 }
11556 }
11557
11558 return retval;
11559}
11560
11561static VALUE
11562rb_fcntl(VALUE io, VALUE req, VALUE arg)
11563{
11564 int cmd = NUM2INT(req);
11565 rb_io_t *fptr;
11566 long narg;
11567 int retval;
11568
11569 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11570 GetOpenFile(io, fptr);
11571 retval = do_fcntl(fptr, cmd, narg);
11572 return finish_narg(retval, arg, fptr);
11573}
11574
11575/*
11576 * call-seq:
11577 * fcntl(integer_cmd, argument) -> integer
11578 *
11579 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11580 * which provides a mechanism for issuing low-level commands to control or query
11581 * a file-oriented I/O stream. Arguments and results are platform
11582 * dependent.
11583 *
11584 * If +argument+ is a number, its value is passed directly;
11585 * if it is a string, it is interpreted as a binary sequence of bytes.
11586 * (Array#pack might be a useful way to build this string.)
11587 *
11588 * Not implemented on all platforms.
11589 *
11590 */
11591
11592static VALUE
11593rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11594{
11595 VALUE req, arg;
11596
11597 rb_scan_args(argc, argv, "11", &req, &arg);
11598 return rb_fcntl(io, req, arg);
11599}
11600#else
11601#define rb_io_fcntl rb_f_notimplement
11602#endif
11603
11604#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11605/*
11606 * call-seq:
11607 * syscall(integer_callno, *arguments) -> integer
11608 *
11609 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11610 * which calls a specified function.
11611 *
11612 * Calls the operating system function identified by +integer_callno+;
11613 * returns the result of the function or raises SystemCallError if it failed.
11614 * The effect of the call is platform-dependent.
11615 * The arguments and returned value are platform-dependent.
11616 *
11617 * For each of +arguments+: if it is an integer, it is passed directly;
11618 * if it is a string, it is interpreted as a binary sequence of bytes.
11619 * There may be as many as nine such arguments.
11620 *
11621 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11622 * are platform-dependent.
11623 *
11624 * Note: Method +syscall+ is essentially unsafe and unportable.
11625 * The DL (Fiddle) library is preferred for safer and a bit
11626 * more portable programming.
11627 *
11628 * Not implemented on all platforms.
11629 *
11630 */
11631
11632static VALUE
11633rb_f_syscall(int argc, VALUE *argv, VALUE _)
11634{
11635 VALUE arg[8];
11636#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11637# define SYSCALL __syscall
11638# define NUM2SYSCALLID(x) NUM2LONG(x)
11639# define RETVAL2NUM(x) LONG2NUM(x)
11640# if SIZEOF_LONG == 8
11641 long num, retval = -1;
11642# elif SIZEOF_LONG_LONG == 8
11643 long long num, retval = -1;
11644# else
11645# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11646# endif
11647#elif defined(__linux__)
11648# define SYSCALL syscall
11649# define NUM2SYSCALLID(x) NUM2LONG(x)
11650# define RETVAL2NUM(x) LONG2NUM(x)
11651 /*
11652 * Linux man page says, syscall(2) function prototype is below.
11653 *
11654 * int syscall(int number, ...);
11655 *
11656 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11657 */
11658 long num, retval = -1;
11659#else
11660# define SYSCALL syscall
11661# define NUM2SYSCALLID(x) NUM2INT(x)
11662# define RETVAL2NUM(x) INT2NUM(x)
11663 int num, retval = -1;
11664#endif
11665 int i;
11666
11667 if (RTEST(ruby_verbose)) {
11669 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11670 }
11671
11672 if (argc == 0)
11673 rb_raise(rb_eArgError, "too few arguments for syscall");
11674 if (argc > numberof(arg))
11675 rb_raise(rb_eArgError, "too many arguments for syscall");
11676 num = NUM2SYSCALLID(argv[0]); ++argv;
11677 for (i = argc - 1; i--; ) {
11678 VALUE v = rb_check_string_type(argv[i]);
11679
11680 if (!NIL_P(v)) {
11681 StringValue(v);
11682 rb_str_modify(v);
11683 arg[i] = (VALUE)StringValueCStr(v);
11684 }
11685 else {
11686 arg[i] = (VALUE)NUM2LONG(argv[i]);
11687 }
11688 }
11689
11690 switch (argc) {
11691 case 1:
11692 retval = SYSCALL(num);
11693 break;
11694 case 2:
11695 retval = SYSCALL(num, arg[0]);
11696 break;
11697 case 3:
11698 retval = SYSCALL(num, arg[0],arg[1]);
11699 break;
11700 case 4:
11701 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11702 break;
11703 case 5:
11704 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11705 break;
11706 case 6:
11707 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11708 break;
11709 case 7:
11710 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11711 break;
11712 case 8:
11713 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11714 break;
11715 }
11716
11717 if (retval == -1)
11718 rb_sys_fail(0);
11719 return RETVAL2NUM(retval);
11720#undef SYSCALL
11721#undef NUM2SYSCALLID
11722#undef RETVAL2NUM
11723}
11724#else
11725#define rb_f_syscall rb_f_notimplement
11726#endif
11727
11728static VALUE
11729io_new_instance(VALUE args)
11730{
11731 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11732}
11733
11734static rb_encoding *
11735find_encoding(VALUE v)
11736{
11737 rb_encoding *enc = rb_find_encoding(v);
11738 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11739 return enc;
11740}
11741
11742static void
11743io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11744{
11745 rb_encoding *enc, *enc2;
11746 int ecflags = fptr->encs.ecflags;
11747 VALUE ecopts, tmp;
11748
11749 if (!NIL_P(v2)) {
11750 enc2 = find_encoding(v1);
11751 tmp = rb_check_string_type(v2);
11752 if (!NIL_P(tmp)) {
11753 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11754 /* Special case - "-" => no transcoding */
11755 enc = enc2;
11756 enc2 = NULL;
11757 }
11758 else
11759 enc = find_encoding(v2);
11760 if (enc == enc2) {
11761 /* Special case - "-" => no transcoding */
11762 enc2 = NULL;
11763 }
11764 }
11765 else {
11766 enc = find_encoding(v2);
11767 if (enc == enc2) {
11768 /* Special case - "-" => no transcoding */
11769 enc2 = NULL;
11770 }
11771 }
11772 if (enc2 == rb_ascii8bit_encoding()) {
11773 /* If external is ASCII-8BIT, no transcoding */
11774 enc = enc2;
11775 enc2 = NULL;
11776 }
11777 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11778 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11779 }
11780 else {
11781 if (NIL_P(v1)) {
11782 /* Set to default encodings */
11783 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11784 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11785 ecopts = Qnil;
11786 }
11787 else {
11788 tmp = rb_check_string_type(v1);
11789 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11790 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11791 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11792 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11793 }
11794 else {
11795 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11796 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11797 ecopts = Qnil;
11798 }
11799 }
11800 }
11801 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11802 fptr->encs.enc = enc;
11803 fptr->encs.enc2 = enc2;
11804 fptr->encs.ecflags = ecflags;
11805 fptr->encs.ecopts = ecopts;
11806 clear_codeconv(fptr);
11807
11808}
11809
11811 rb_io_t *fptr;
11812 VALUE v1;
11813 VALUE v2;
11814 VALUE opt;
11815};
11816
11817static VALUE
11818io_encoding_set_v(VALUE v)
11819{
11820 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11821 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11822 return Qnil;
11823}
11824
11825static VALUE
11826pipe_pair_close(VALUE rw)
11827{
11828 VALUE *rwp = (VALUE *)rw;
11829 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11830}
11831
11832/*
11833 * call-seq:
11834 * IO.pipe(**opts) -> [read_io, write_io]
11835 * IO.pipe(enc, **opts) -> [read_io, write_io]
11836 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11837 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11838 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11839 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11840 *
11841 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11842 * connected to each other.
11843 *
11844 * If argument +enc_string+ is given, it must be a string containing one of:
11845 *
11846 * - The name of the encoding to be used as the external encoding.
11847 * - The colon-separated names of two encodings to be used as the external
11848 * and internal encodings.
11849 *
11850 * If argument +int_enc+ is given, it must be an Encoding object
11851 * or encoding name string that specifies the internal encoding to be used;
11852 * if argument +ext_enc+ is also given, it must be an Encoding object
11853 * or encoding name string that specifies the external encoding to be used.
11854 *
11855 * The string read from +read_io+ is tagged with the external encoding;
11856 * if an internal encoding is also specified, the string is converted
11857 * to, and tagged with, that encoding.
11858 *
11859 * If any encoding is specified,
11860 * optional hash arguments specify the conversion option.
11861 *
11862 * Optional keyword arguments +opts+ specify:
11863 *
11864 * - {Open Options}[rdoc-ref:IO@Open+Options].
11865 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11866 *
11867 * With no block given, returns the two endpoints in an array:
11868 *
11869 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11870 *
11871 * With a block given, calls the block with the two endpoints;
11872 * closes both endpoints and returns the value of the block:
11873 *
11874 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11875 *
11876 * Output:
11877 *
11878 * #<IO:fd 6>
11879 * #<IO:fd 7>
11880 *
11881 * Not available on all platforms.
11882 *
11883 * In the example below, the two processes close the ends of the pipe
11884 * that they are not using. This is not just a cosmetic nicety. The
11885 * read end of a pipe will not generate an end of file condition if
11886 * there are any writers with the pipe still open. In the case of the
11887 * parent process, the <tt>rd.read</tt> will never return if it
11888 * does not first issue a <tt>wr.close</tt>:
11889 *
11890 * rd, wr = IO.pipe
11891 *
11892 * if fork
11893 * wr.close
11894 * puts "Parent got: <#{rd.read}>"
11895 * rd.close
11896 * Process.wait
11897 * else
11898 * rd.close
11899 * puts 'Sending message to parent'
11900 * wr.write "Hi Dad"
11901 * wr.close
11902 * end
11903 *
11904 * <em>produces:</em>
11905 *
11906 * Sending message to parent
11907 * Parent got: <Hi Dad>
11908 *
11909 */
11910
11911static VALUE
11912rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11913{
11914 int pipes[2], state;
11915 VALUE r, w, args[3], v1, v2;
11916 VALUE opt;
11917 rb_io_t *fptr, *fptr2;
11918 struct io_encoding_set_args ies_args;
11919 enum rb_io_mode fmode = 0;
11920 VALUE ret;
11921
11922 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11923 if (rb_pipe(pipes) < 0)
11924 rb_sys_fail(0);
11925
11926 args[0] = klass;
11927 args[1] = INT2NUM(pipes[0]);
11928 args[2] = INT2FIX(O_RDONLY);
11929 r = rb_protect(io_new_instance, (VALUE)args, &state);
11930 if (state) {
11931 close(pipes[0]);
11932 close(pipes[1]);
11933 rb_jump_tag(state);
11934 }
11935 GetOpenFile(r, fptr);
11936
11937 ies_args.fptr = fptr;
11938 ies_args.v1 = v1;
11939 ies_args.v2 = v2;
11940 ies_args.opt = opt;
11941 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11942 if (state) {
11943 close(pipes[1]);
11944 io_close(r);
11945 rb_jump_tag(state);
11946 }
11947
11948 args[1] = INT2NUM(pipes[1]);
11949 args[2] = INT2FIX(O_WRONLY);
11950 w = rb_protect(io_new_instance, (VALUE)args, &state);
11951 if (state) {
11952 close(pipes[1]);
11953 if (!NIL_P(r)) rb_io_close(r);
11954 rb_jump_tag(state);
11955 }
11956 GetOpenFile(w, fptr2);
11957 rb_io_synchronized(fptr2);
11958
11959 extract_binmode(opt, &fmode);
11960
11961 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11964 }
11965
11966#if DEFAULT_TEXTMODE
11967 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11968 fptr->mode &= ~FMODE_TEXTMODE;
11969 setmode(fptr->fd, O_BINARY);
11970 }
11971#if RUBY_CRLF_ENVIRONMENT
11974 }
11975#endif
11976#endif
11977 fptr->mode |= fmode;
11978#if DEFAULT_TEXTMODE
11979 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11980 fptr2->mode &= ~FMODE_TEXTMODE;
11981 setmode(fptr2->fd, O_BINARY);
11982 }
11983#endif
11984 fptr2->mode |= fmode;
11985
11986 ret = rb_assoc_new(r, w);
11987 if (rb_block_given_p()) {
11988 VALUE rw[2];
11989 rw[0] = r;
11990 rw[1] = w;
11991 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11992 }
11993 return ret;
11994}
11995
11997 int argc;
11998 VALUE *argv;
11999 VALUE io;
12000};
12001
12002static void
12003open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12004{
12005 VALUE path, v;
12006 VALUE vmode = Qnil, vperm = Qnil;
12007
12008 path = *argv++;
12009 argc--;
12010 FilePathValue(path);
12011 arg->io = 0;
12012 arg->argc = argc;
12013 arg->argv = argv;
12014 if (NIL_P(opt)) {
12015 vmode = INT2NUM(O_RDONLY);
12016 vperm = INT2FIX(0666);
12017 }
12018 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12019 int n;
12020
12021 v = rb_to_array_type(v);
12022 n = RARRAY_LENINT(v);
12023 rb_check_arity(n, 0, 3); /* rb_io_open */
12024 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12025 }
12026 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12027}
12028
12029static VALUE
12030io_s_foreach(VALUE v)
12031{
12032 struct getline_arg *arg = (void *)v;
12033 VALUE str;
12034
12035 if (arg->limit == 0)
12036 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12037 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12038 rb_lastline_set(str);
12039 rb_yield(str);
12040 }
12042 return Qnil;
12043}
12044
12045/*
12046 * call-seq:
12047 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12048 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12049 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12050 * IO.foreach(...) -> an_enumerator
12051 *
12052 * Calls the block with each successive line read from the stream.
12053 *
12054 * The first argument must be a string that is the path to a file.
12055 *
12056 * With only argument +path+ given, parses lines from the file at the given +path+,
12057 * as determined by the default line separator,
12058 * and calls the block with each successive line:
12059 *
12060 * File.foreach('t.txt') {|line| p line }
12061 *
12062 * Output: the same as above.
12063 *
12064 * For both forms, command and path, the remaining arguments are the same.
12065 *
12066 * With argument +sep+ given, parses lines as determined by that line separator
12067 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12068 *
12069 * File.foreach('t.txt', 'li') {|line| p line }
12070 *
12071 * Output:
12072 *
12073 * "First li"
12074 * "ne\nSecond li"
12075 * "ne\n\nThird li"
12076 * "ne\nFourth li"
12077 * "ne\n"
12078 *
12079 * Each paragraph:
12080 *
12081 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12082 *
12083 * Output:
12084 *
12085 * "First line\nSecond line\n\n"
12086 * "Third line\nFourth line\n"
12087 *
12088 * With argument +limit+ given, parses lines as determined by the default
12089 * line separator and the given line-length limit
12090 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12091 *
12092 * File.foreach('t.txt', 7) {|line| p line }
12093 *
12094 * Output:
12095 *
12096 * "First l"
12097 * "ine\n"
12098 * "Second "
12099 * "line\n"
12100 * "\n"
12101 * "Third l"
12102 * "ine\n"
12103 * "Fourth l"
12104 * "line\n"
12105 *
12106 * With arguments +sep+ and +limit+ given,
12107 * combines the two behaviors
12108 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12109 *
12110 * Optional keyword arguments +opts+ specify:
12111 *
12112 * - {Open Options}[rdoc-ref:IO@Open+Options].
12113 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12114 * - {Line Options}[rdoc-ref:IO@Line+IO].
12115 *
12116 * Returns an Enumerator if no block is given.
12117 *
12118 */
12119
12120static VALUE
12121rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12122{
12123 VALUE opt;
12124 int orig_argc = argc;
12125 struct foreach_arg arg;
12126 struct getline_arg garg;
12127
12128 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12129 RETURN_ENUMERATOR(self, orig_argc, argv);
12130 extract_getline_args(argc-1, argv+1, &garg);
12131 open_key_args(self, argc, argv, opt, &arg);
12132 if (NIL_P(arg.io)) return Qnil;
12133 extract_getline_opts(opt, &garg);
12134 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12135 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12136}
12137
12138static VALUE
12139io_s_readlines(VALUE v)
12140{
12141 struct getline_arg *arg = (void *)v;
12142 return io_readlines(arg, arg->io);
12143}
12144
12145/*
12146 * call-seq:
12147 * IO.readlines(path, sep = $/, **opts) -> array
12148 * IO.readlines(path, limit, **opts) -> array
12149 * IO.readlines(path, sep, limit, **opts) -> array
12150 *
12151 * Returns an array of all lines read from the stream.
12152 *
12153 * The first argument must be a string that is the path to a file.
12154 *
12155 * With only argument +path+ given, parses lines from the file at the given +path+,
12156 * as determined by the default line separator,
12157 * and returns those lines in an array:
12158 *
12159 * IO.readlines('t.txt')
12160 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12161 *
12162 * With argument +sep+ given, parses lines as determined by that line separator
12163 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12164 *
12165 * # Ordinary separator.
12166 * IO.readlines('t.txt', 'li')
12167 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12168 * # Get-paragraphs separator.
12169 * IO.readlines('t.txt', '')
12170 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12171 * # Get-all separator.
12172 * IO.readlines('t.txt', nil)
12173 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12174 *
12175 * With argument +limit+ given, parses lines as determined by the default
12176 * line separator and the given line-length limit
12177 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12178 *
12179 * IO.readlines('t.txt', 7)
12180 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12181 *
12182 * With arguments +sep+ and +limit+ given,
12183 * combines the two behaviors
12184 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12185 *
12186 * Optional keyword arguments +opts+ specify:
12187 *
12188 * - {Open Options}[rdoc-ref:IO@Open+Options].
12189 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12190 * - {Line Options}[rdoc-ref:IO@Line+IO].
12191 *
12192 */
12193
12194static VALUE
12195rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12196{
12197 VALUE opt;
12198 struct foreach_arg arg;
12199 struct getline_arg garg;
12200
12201 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12202 extract_getline_args(argc-1, argv+1, &garg);
12203 open_key_args(io, argc, argv, opt, &arg);
12204 if (NIL_P(arg.io)) return Qnil;
12205 extract_getline_opts(opt, &garg);
12206 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12207 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12208}
12209
12210static VALUE
12211io_s_read(VALUE v)
12212{
12213 struct foreach_arg *arg = (void *)v;
12214 return io_read(arg->argc, arg->argv, arg->io);
12215}
12216
12217struct seek_arg {
12218 VALUE io;
12219 VALUE offset;
12220 int mode;
12221};
12222
12223static VALUE
12224seek_before_access(VALUE argp)
12225{
12226 struct seek_arg *arg = (struct seek_arg *)argp;
12227 rb_io_binmode(arg->io);
12228 return rb_io_seek(arg->io, arg->offset, arg->mode);
12229}
12230
12231/*
12232 * call-seq:
12233 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12234 *
12235 * Opens the stream, reads and returns some or all of its content,
12236 * and closes the stream; returns +nil+ if no bytes were read.
12237 *
12238 * The first argument must be a string that is the path to a file.
12239 *
12240 * With only argument +path+ given, reads in text mode and returns the entire content
12241 * of the file at the given path:
12242 *
12243 * IO.read('t.txt')
12244 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12245 *
12246 * On Windows, text mode can terminate reading and leave bytes in the file
12247 * unread when encountering certain special bytes. Consider using
12248 * IO.binread if all bytes in the file should be read.
12249 *
12250 * With argument +length+, returns +length+ bytes if available:
12251 *
12252 * IO.read('t.txt', 7) # => "First l"
12253 * IO.read('t.txt', 700)
12254 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12255 *
12256 * With arguments +length+ and +offset+, returns +length+ bytes
12257 * if available, beginning at the given +offset+:
12258 *
12259 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12260 * IO.read('t.txt', 10, 200) # => nil
12261 *
12262 * Optional keyword arguments +opts+ specify:
12263 *
12264 * - {Open Options}[rdoc-ref:IO@Open+Options].
12265 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12266 *
12267 */
12268
12269static VALUE
12270rb_io_s_read(int argc, VALUE *argv, VALUE io)
12271{
12272 VALUE opt, offset;
12273 long off;
12274 struct foreach_arg arg;
12275
12276 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12277 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12278 rb_raise(rb_eArgError, "negative offset %ld given", off);
12279 }
12280 open_key_args(io, argc, argv, opt, &arg);
12281 if (NIL_P(arg.io)) return Qnil;
12282 if (!NIL_P(offset)) {
12283 struct seek_arg sarg;
12284 int state = 0;
12285 sarg.io = arg.io;
12286 sarg.offset = offset;
12287 sarg.mode = SEEK_SET;
12288 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12289 if (state) {
12290 rb_io_close(arg.io);
12291 rb_jump_tag(state);
12292 }
12293 if (arg.argc == 2) arg.argc = 1;
12294 }
12295 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12296}
12297
12298/*
12299 * call-seq:
12300 * IO.binread(path, length = nil, offset = 0) -> string or nil
12301 *
12302 * Behaves like IO.read, except that the stream is opened in binary mode
12303 * with ASCII-8BIT encoding.
12304 *
12305 */
12306
12307static VALUE
12308rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12309{
12310 VALUE offset;
12311 struct foreach_arg arg;
12312 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12313 enum {
12314 oflags = O_RDONLY
12315#ifdef O_BINARY
12316 |O_BINARY
12317#endif
12318 };
12319 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12320
12321 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12322 FilePathValue(argv[0]);
12323 convconfig.enc = rb_ascii8bit_encoding();
12324 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12325 if (NIL_P(arg.io)) return Qnil;
12326 arg.argv = argv+1;
12327 arg.argc = (argc > 1) ? 1 : 0;
12328 if (!NIL_P(offset)) {
12329 struct seek_arg sarg;
12330 int state = 0;
12331 sarg.io = arg.io;
12332 sarg.offset = offset;
12333 sarg.mode = SEEK_SET;
12334 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12335 if (state) {
12336 rb_io_close(arg.io);
12337 rb_jump_tag(state);
12338 }
12339 }
12340 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12341}
12342
12343static VALUE
12344io_s_write0(VALUE v)
12345{
12346 struct write_arg *arg = (void *)v;
12347 return io_write(arg->io,arg->str,arg->nosync);
12348}
12349
12350static VALUE
12351io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12352{
12353 VALUE string, offset, opt;
12354 struct foreach_arg arg;
12355 struct write_arg warg;
12356
12357 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12358
12359 if (NIL_P(opt)) opt = rb_hash_new();
12360 else opt = rb_hash_dup(opt);
12361
12362
12363 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12364 int mode = O_WRONLY|O_CREAT;
12365#ifdef O_BINARY
12366 if (binary) mode |= O_BINARY;
12367#endif
12368 if (NIL_P(offset)) mode |= O_TRUNC;
12369 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12370 }
12371 open_key_args(klass, argc, argv, opt, &arg);
12372
12373#ifndef O_BINARY
12374 if (binary) rb_io_binmode_m(arg.io);
12375#endif
12376
12377 if (NIL_P(arg.io)) return Qnil;
12378 if (!NIL_P(offset)) {
12379 struct seek_arg sarg;
12380 int state = 0;
12381 sarg.io = arg.io;
12382 sarg.offset = offset;
12383 sarg.mode = SEEK_SET;
12384 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12385 if (state) {
12386 rb_io_close(arg.io);
12387 rb_jump_tag(state);
12388 }
12389 }
12390
12391 warg.io = arg.io;
12392 warg.str = string;
12393 warg.nosync = 0;
12394
12395 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12396}
12397
12398/*
12399 * call-seq:
12400 * IO.write(path, data, offset = 0, **opts) -> integer
12401 *
12402 * Opens the stream, writes the given +data+ to it,
12403 * and closes the stream; returns the number of bytes written.
12404 *
12405 * The first argument must be a string that is the path to a file.
12406 *
12407 * With only argument +path+ given, writes the given +data+ to the file at that path:
12408 *
12409 * IO.write('t.tmp', 'abc') # => 3
12410 * File.read('t.tmp') # => "abc"
12411 *
12412 * If +offset+ is zero (the default), the file is overwritten:
12413 *
12414 * IO.write('t.tmp', 'A') # => 1
12415 * File.read('t.tmp') # => "A"
12416 *
12417 * If +offset+ in within the file content, the file is partly overwritten:
12418 *
12419 * IO.write('t.tmp', 'abcdef') # => 3
12420 * File.read('t.tmp') # => "abcdef"
12421 * # Offset within content.
12422 * IO.write('t.tmp', '012', 2) # => 3
12423 * File.read('t.tmp') # => "ab012f"
12424 *
12425 * If +offset+ is outside the file content,
12426 * the file is padded with null characters <tt>"\u0000"</tt>:
12427 *
12428 * IO.write('t.tmp', 'xyz', 10) # => 3
12429 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12430 *
12431 * Optional keyword arguments +opts+ specify:
12432 *
12433 * - {Open Options}[rdoc-ref:IO@Open+Options].
12434 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12435 *
12436 */
12437
12438static VALUE
12439rb_io_s_write(int argc, VALUE *argv, VALUE io)
12440{
12441 return io_s_write(argc, argv, io, 0);
12442}
12443
12444/*
12445 * call-seq:
12446 * IO.binwrite(path, string, offset = 0) -> integer
12447 *
12448 * Behaves like IO.write, except that the stream is opened in binary mode
12449 * with ASCII-8BIT encoding.
12450 *
12451 */
12452
12453static VALUE
12454rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12455{
12456 return io_s_write(argc, argv, io, 1);
12457}
12458
12460 VALUE src;
12461 VALUE dst;
12462 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12463 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12464
12465 rb_io_t *src_fptr;
12466 rb_io_t *dst_fptr;
12467 unsigned close_src : 1;
12468 unsigned close_dst : 1;
12469 int error_no;
12470 rb_off_t total;
12471 const char *syserr;
12472 const char *notimp;
12473 VALUE th;
12474 struct stat src_stat;
12475 struct stat dst_stat;
12476#ifdef HAVE_FCOPYFILE
12477 copyfile_state_t copyfile_state;
12478#endif
12479};
12480
12481static void *
12482exec_interrupts(void *arg)
12483{
12484 VALUE th = (VALUE)arg;
12485 rb_thread_execute_interrupts(th);
12486 return NULL;
12487}
12488
12489/*
12490 * returns TRUE if the preceding system call was interrupted
12491 * so we can continue. If the thread was interrupted, we
12492 * reacquire the GVL to execute interrupts before continuing.
12493 */
12494static int
12495maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12496{
12497 switch (errno) {
12498 case EINTR:
12499#if defined(ERESTART)
12500 case ERESTART:
12501#endif
12502 if (rb_thread_interrupted(stp->th)) {
12503 if (has_gvl)
12504 rb_thread_execute_interrupts(stp->th);
12505 else
12506 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12507 }
12508 return TRUE;
12509 }
12510 return FALSE;
12511}
12512
12514 VALUE scheduler;
12515
12516 rb_io_t *fptr;
12517 short events;
12518
12519 VALUE result;
12520};
12521
12522static void *
12523fiber_scheduler_wait_for(void * _arguments)
12524{
12525 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12526
12527 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12528
12529 return NULL;
12530}
12531
12532#if USE_POLL
12533# define IOWAIT_SYSCALL "poll"
12534STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12535STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12536static int
12537nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12538{
12540 if (scheduler != Qnil) {
12541 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12542 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12543 return RTEST(args.result);
12544 }
12545
12546 int fd = fptr->fd;
12547 if (fd == -1) return 0;
12548
12549 struct pollfd fds;
12550
12551 fds.fd = fd;
12552 fds.events = events;
12553
12554 int timeout_milliseconds = -1;
12555
12556 if (timeout) {
12557 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12558 }
12559
12560 return poll(&fds, 1, timeout_milliseconds);
12561}
12562#else /* !USE_POLL */
12563# define IOWAIT_SYSCALL "select"
12564static int
12565nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12566{
12568 if (scheduler != Qnil) {
12569 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12570 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12571 return RTEST(args.result);
12572 }
12573
12574 int fd = fptr->fd;
12575
12576 if (fd == -1) {
12577 errno = EBADF;
12578 return -1;
12579 }
12580
12581 rb_fdset_t fds;
12582 int ret;
12583
12584 rb_fd_init(&fds);
12585 rb_fd_set(fd, &fds);
12586
12587 switch (events) {
12588 case RB_WAITFD_IN:
12589 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12590 break;
12591 case RB_WAITFD_OUT:
12592 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12593 break;
12594 default:
12595 VM_UNREACHABLE(nogvl_wait_for);
12596 }
12597
12598 rb_fd_term(&fds);
12599
12600 // On timeout, this returns 0.
12601 return ret;
12602}
12603#endif /* !USE_POLL */
12604
12605static int
12606maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12607{
12608 int ret;
12609
12610 do {
12611 if (has_gvl) {
12613 }
12614 else {
12615 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12616 }
12617 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12618
12619 if (ret < 0) {
12620 stp->syserr = IOWAIT_SYSCALL;
12621 stp->error_no = errno;
12622 return ret;
12623 }
12624 return 0;
12625}
12626
12627static int
12628nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12629{
12630 int ret;
12631
12632 do {
12633 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12634 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12635
12636 if (ret < 0) {
12637 stp->syserr = IOWAIT_SYSCALL;
12638 stp->error_no = errno;
12639 return ret;
12640 }
12641 return 0;
12642}
12643
12644#ifdef USE_COPY_FILE_RANGE
12645
12646static ssize_t
12647simple_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)
12648{
12649#ifdef HAVE_COPY_FILE_RANGE
12650 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12651#else
12652 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12653#endif
12654}
12655
12656static int
12657nogvl_copy_file_range(struct copy_stream_struct *stp)
12658{
12659 ssize_t ss;
12660 rb_off_t src_size;
12661 rb_off_t copy_length, src_offset, *src_offset_ptr;
12662
12663 if (!S_ISREG(stp->src_stat.st_mode))
12664 return 0;
12665
12666 src_size = stp->src_stat.st_size;
12667 src_offset = stp->src_offset;
12668 if (src_offset >= (rb_off_t)0) {
12669 src_offset_ptr = &src_offset;
12670 }
12671 else {
12672 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12673 }
12674
12675 copy_length = stp->copy_length;
12676 if (copy_length < (rb_off_t)0) {
12677 if (src_offset < (rb_off_t)0) {
12678 rb_off_t current_offset;
12679 errno = 0;
12680 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12681 if (current_offset < (rb_off_t)0 && errno) {
12682 stp->syserr = "lseek";
12683 stp->error_no = errno;
12684 return (int)current_offset;
12685 }
12686 copy_length = src_size - current_offset;
12687 }
12688 else {
12689 copy_length = src_size - src_offset;
12690 }
12691 }
12692
12693 retry_copy_file_range:
12694# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12695 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12696 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12697# else
12698 ss = (ssize_t)copy_length;
12699# endif
12700 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12701 if (0 < ss) {
12702 stp->total += ss;
12703 copy_length -= ss;
12704 if (0 < copy_length) {
12705 goto retry_copy_file_range;
12706 }
12707 }
12708 if (ss < 0) {
12709 if (maygvl_copy_stream_continue_p(0, stp)) {
12710 goto retry_copy_file_range;
12711 }
12712 switch (errno) {
12713 case EINVAL:
12714 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12715 docker container) */
12716#ifdef ENOSYS
12717 case ENOSYS:
12718#endif
12719#ifdef EXDEV
12720 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12721#endif
12722 return 0;
12723 case EAGAIN:
12724#if EWOULDBLOCK != EAGAIN
12725 case EWOULDBLOCK:
12726#endif
12727 {
12728 int ret = nogvl_copy_stream_wait_write(stp);
12729 if (ret < 0) return ret;
12730 }
12731 goto retry_copy_file_range;
12732 case EBADF:
12733 {
12734 int e = errno;
12735 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12736
12737 if (flags != -1 && flags & O_APPEND) {
12738 return 0;
12739 }
12740 errno = e;
12741 }
12742 }
12743 stp->syserr = "copy_file_range";
12744 stp->error_no = errno;
12745 return (int)ss;
12746 }
12747 return 1;
12748}
12749#endif
12750
12751#ifdef HAVE_FCOPYFILE
12752static int
12753nogvl_fcopyfile(struct copy_stream_struct *stp)
12754{
12755 rb_off_t cur, ss = 0;
12756 const rb_off_t src_offset = stp->src_offset;
12757 int ret;
12758
12759 if (stp->copy_length >= (rb_off_t)0) {
12760 /* copy_length can't be specified in fcopyfile(3) */
12761 return 0;
12762 }
12763
12764 if (!S_ISREG(stp->src_stat.st_mode))
12765 return 0;
12766
12767 if (!S_ISREG(stp->dst_stat.st_mode))
12768 return 0;
12769 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12770 return 0;
12771 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12772 /* fcopyfile(3) appends src IO to dst IO and then truncates
12773 * dst IO to src IO's original size. */
12774 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12775 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12776 if (end > (rb_off_t)0) return 0;
12777 }
12778
12779 if (src_offset > (rb_off_t)0) {
12780 rb_off_t r;
12781
12782 /* get current offset */
12783 errno = 0;
12784 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12785 if (cur < (rb_off_t)0 && errno) {
12786 stp->error_no = errno;
12787 return 1;
12788 }
12789
12790 errno = 0;
12791 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12792 if (r < (rb_off_t)0 && errno) {
12793 stp->error_no = errno;
12794 return 1;
12795 }
12796 }
12797
12798 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12799 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12800 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12801
12802 if (ret == 0) { /* success */
12803 stp->total = ss;
12804 if (src_offset > (rb_off_t)0) {
12805 rb_off_t r;
12806 errno = 0;
12807 /* reset offset */
12808 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12809 if (r < (rb_off_t)0 && errno) {
12810 stp->error_no = errno;
12811 return 1;
12812 }
12813 }
12814 }
12815 else {
12816 switch (errno) {
12817 case ENOTSUP:
12818 case EPERM:
12819 case EINVAL:
12820 return 0;
12821 }
12822 stp->syserr = "fcopyfile";
12823 stp->error_no = errno;
12824 return (int)ret;
12825 }
12826 return 1;
12827}
12828#endif
12829
12830#ifdef HAVE_SENDFILE
12831
12832# ifdef __linux__
12833# define USE_SENDFILE
12834
12835# ifdef HAVE_SYS_SENDFILE_H
12836# include <sys/sendfile.h>
12837# endif
12838
12839static ssize_t
12840simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12841{
12842 return sendfile(out_fd, in_fd, offset, (size_t)count);
12843}
12844
12845# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12846/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12847 * without cpuset -l 0.
12848 */
12849# define USE_SENDFILE
12850
12851static ssize_t
12852simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12853{
12854 int r;
12855 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12856 rb_off_t sbytes;
12857# ifdef __APPLE__
12858 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12859 sbytes = count;
12860# else
12861 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12862# endif
12863 if (r != 0 && sbytes == 0) return r;
12864 if (offset) {
12865 *offset += sbytes;
12866 }
12867 else {
12868 lseek(in_fd, sbytes, SEEK_CUR);
12869 }
12870 return (ssize_t)sbytes;
12871}
12872
12873# endif
12874
12875#endif
12876
12877#ifdef USE_SENDFILE
12878static int
12879nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12880{
12881 ssize_t ss;
12882 rb_off_t src_size;
12883 rb_off_t copy_length;
12884 rb_off_t src_offset;
12885 int use_pread;
12886
12887 if (!S_ISREG(stp->src_stat.st_mode))
12888 return 0;
12889
12890 src_size = stp->src_stat.st_size;
12891#ifndef __linux__
12892 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12893 return 0;
12894#endif
12895
12896 src_offset = stp->src_offset;
12897 use_pread = src_offset >= (rb_off_t)0;
12898
12899 copy_length = stp->copy_length;
12900 if (copy_length < (rb_off_t)0) {
12901 if (use_pread)
12902 copy_length = src_size - src_offset;
12903 else {
12904 rb_off_t cur;
12905 errno = 0;
12906 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12907 if (cur < (rb_off_t)0 && errno) {
12908 stp->syserr = "lseek";
12909 stp->error_no = errno;
12910 return (int)cur;
12911 }
12912 copy_length = src_size - cur;
12913 }
12914 }
12915
12916 retry_sendfile:
12917# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12918 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12919 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12920# else
12921 ss = (ssize_t)copy_length;
12922# endif
12923 if (use_pread) {
12924 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12925 }
12926 else {
12927 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12928 }
12929 if (0 < ss) {
12930 stp->total += ss;
12931 copy_length -= ss;
12932 if (0 < copy_length) {
12933 goto retry_sendfile;
12934 }
12935 }
12936 if (ss < 0) {
12937 if (maygvl_copy_stream_continue_p(0, stp))
12938 goto retry_sendfile;
12939 switch (errno) {
12940 case EINVAL:
12941#ifdef ENOSYS
12942 case ENOSYS:
12943#endif
12944#ifdef EOPNOTSUP
12945 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12946 see also: [Feature #16965] */
12947 case EOPNOTSUP:
12948#endif
12949 return 0;
12950 case EAGAIN:
12951#if EWOULDBLOCK != EAGAIN
12952 case EWOULDBLOCK:
12953#endif
12954 {
12955 int ret;
12956#ifndef __linux__
12957 /*
12958 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12959 * select() reports regular files to always be "ready", so
12960 * there is no need to select() on it.
12961 * Other OSes may have the same limitation for sendfile() which
12962 * allow us to bypass maygvl_copy_stream_wait_read()...
12963 */
12964 ret = maygvl_copy_stream_wait_read(0, stp);
12965 if (ret < 0) return ret;
12966#endif
12967 ret = nogvl_copy_stream_wait_write(stp);
12968 if (ret < 0) return ret;
12969 }
12970 goto retry_sendfile;
12971 }
12972 stp->syserr = "sendfile";
12973 stp->error_no = errno;
12974 return (int)ss;
12975 }
12976 return 1;
12977}
12978#endif
12979
12980static ssize_t
12981maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
12982{
12983 if (has_gvl)
12984 return rb_io_read_memory(fptr, buf, count);
12985 else
12986 return read(fptr->fd, buf, count);
12987}
12988
12989static ssize_t
12990maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
12991{
12992 ssize_t ss;
12993 retry_read:
12994 if (offset < (rb_off_t)0) {
12995 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
12996 }
12997 else {
12998 ss = pread(stp->src_fptr->fd, buf, len, offset);
12999 }
13000 if (ss == 0) {
13001 return 0;
13002 }
13003 if (ss < 0) {
13004 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13005 goto retry_read;
13006 switch (errno) {
13007 case EAGAIN:
13008#if EWOULDBLOCK != EAGAIN
13009 case EWOULDBLOCK:
13010#endif
13011 {
13012 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13013 if (ret < 0) return ret;
13014 }
13015 goto retry_read;
13016#ifdef ENOSYS
13017 case ENOSYS:
13018 stp->notimp = "pread";
13019 return ss;
13020#endif
13021 }
13022 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13023 stp->error_no = errno;
13024 }
13025 return ss;
13026}
13027
13028static int
13029nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13030{
13031 ssize_t ss;
13032 int off = 0;
13033 while (len) {
13034 ss = write(stp->dst_fptr->fd, buf+off, len);
13035 if (ss < 0) {
13036 if (maygvl_copy_stream_continue_p(0, stp))
13037 continue;
13038 if (io_again_p(errno)) {
13039 int ret = nogvl_copy_stream_wait_write(stp);
13040 if (ret < 0) return ret;
13041 continue;
13042 }
13043 stp->syserr = "write";
13044 stp->error_no = errno;
13045 return (int)ss;
13046 }
13047 off += (int)ss;
13048 len -= (int)ss;
13049 stp->total += ss;
13050 }
13051 return 0;
13052}
13053
13054static void
13055nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13056{
13057 char buf[1024*16];
13058 size_t len;
13059 ssize_t ss;
13060 int ret;
13061 rb_off_t copy_length;
13062 rb_off_t src_offset;
13063 int use_eof;
13064 int use_pread;
13065
13066 copy_length = stp->copy_length;
13067 use_eof = copy_length < (rb_off_t)0;
13068 src_offset = stp->src_offset;
13069 use_pread = src_offset >= (rb_off_t)0;
13070
13071 if (use_pread && stp->close_src) {
13072 rb_off_t r;
13073 errno = 0;
13074 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13075 if (r < (rb_off_t)0 && errno) {
13076 stp->syserr = "lseek";
13077 stp->error_no = errno;
13078 return;
13079 }
13080 src_offset = (rb_off_t)-1;
13081 use_pread = 0;
13082 }
13083
13084 while (use_eof || 0 < copy_length) {
13085 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13086 len = (size_t)copy_length;
13087 }
13088 else {
13089 len = sizeof(buf);
13090 }
13091 if (use_pread) {
13092 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13093 if (0 < ss)
13094 src_offset += ss;
13095 }
13096 else {
13097 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13098 }
13099 if (ss <= 0) /* EOF or error */
13100 return;
13101
13102 ret = nogvl_copy_stream_write(stp, buf, ss);
13103 if (ret < 0)
13104 return;
13105
13106 if (!use_eof)
13107 copy_length -= ss;
13108 }
13109}
13110
13111static void *
13112nogvl_copy_stream_func(void *arg)
13113{
13114 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13115#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13116 int ret;
13117#endif
13118
13119#ifdef USE_COPY_FILE_RANGE
13120 ret = nogvl_copy_file_range(stp);
13121 if (ret != 0)
13122 goto finish; /* error or success */
13123#endif
13124
13125#ifdef HAVE_FCOPYFILE
13126 ret = nogvl_fcopyfile(stp);
13127 if (ret != 0)
13128 goto finish; /* error or success */
13129#endif
13130
13131#ifdef USE_SENDFILE
13132 ret = nogvl_copy_stream_sendfile(stp);
13133 if (ret != 0)
13134 goto finish; /* error or success */
13135#endif
13136
13137 nogvl_copy_stream_read_write(stp);
13138
13139#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13140 finish:
13141#endif
13142 return 0;
13143}
13144
13145static VALUE
13146copy_stream_fallback_body(VALUE arg)
13147{
13148 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13149 const int buflen = 16*1024;
13150 VALUE n;
13151 VALUE buf = rb_str_buf_new(buflen);
13152 rb_off_t rest = stp->copy_length;
13153 rb_off_t off = stp->src_offset;
13154 ID read_method = id_readpartial;
13155
13156 if (!stp->src_fptr) {
13157 if (!rb_respond_to(stp->src, read_method)) {
13158 read_method = id_read;
13159 }
13160 }
13161
13162 while (1) {
13163 long numwrote;
13164 long l;
13165 rb_str_make_independent(buf);
13166 if (stp->copy_length < (rb_off_t)0) {
13167 l = buflen;
13168 }
13169 else {
13170 if (rest == 0) {
13171 rb_str_resize(buf, 0);
13172 break;
13173 }
13174 l = buflen < rest ? buflen : (long)rest;
13175 }
13176 if (!stp->src_fptr) {
13177 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13178
13179 if (read_method == id_read && NIL_P(rc))
13180 break;
13181 }
13182 else {
13183 ssize_t ss;
13184 rb_str_resize(buf, buflen);
13185 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13186 rb_str_resize(buf, ss > 0 ? ss : 0);
13187 if (ss < 0)
13188 return Qnil;
13189 if (ss == 0)
13190 rb_eof_error();
13191 if (off >= (rb_off_t)0)
13192 off += ss;
13193 }
13194 n = rb_io_write(stp->dst, buf);
13195 numwrote = NUM2LONG(n);
13196 stp->total += numwrote;
13197 rest -= numwrote;
13198 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13199 break;
13200 }
13201 }
13202
13203 return Qnil;
13204}
13205
13206static VALUE
13207copy_stream_fallback(struct copy_stream_struct *stp)
13208{
13209 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13210 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13211 }
13212 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13213 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13214 rb_eEOFError, (VALUE)0);
13215 return Qnil;
13216}
13217
13218static VALUE
13219copy_stream_body(VALUE arg)
13220{
13221 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13222 VALUE src_io = stp->src, dst_io = stp->dst;
13223 const int common_oflags = 0
13224#ifdef O_NOCTTY
13225 | O_NOCTTY
13226#endif
13227 ;
13228
13229 stp->th = rb_thread_current();
13230
13231 stp->total = 0;
13232
13233 if (src_io == argf ||
13234 !(RB_TYPE_P(src_io, T_FILE) ||
13235 RB_TYPE_P(src_io, T_STRING) ||
13236 rb_respond_to(src_io, rb_intern("to_path")))) {
13237 stp->src_fptr = NULL;
13238 }
13239 else {
13240 int stat_ret;
13241 VALUE tmp_io = rb_io_check_io(src_io);
13242 if (!NIL_P(tmp_io)) {
13243 src_io = tmp_io;
13244 }
13245 else if (!RB_TYPE_P(src_io, T_FILE)) {
13246 VALUE args[2];
13247 FilePathValue(src_io);
13248 args[0] = src_io;
13249 args[1] = INT2NUM(O_RDONLY|common_oflags);
13250 src_io = rb_class_new_instance(2, args, rb_cFile);
13251 stp->src = src_io;
13252 stp->close_src = 1;
13253 }
13254 RB_IO_POINTER(src_io, stp->src_fptr);
13255 rb_io_check_byte_readable(stp->src_fptr);
13256
13257 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13258 if (stat_ret < 0) {
13259 stp->syserr = "fstat";
13260 stp->error_no = errno;
13261 return Qnil;
13262 }
13263 }
13264
13265 if (dst_io == argf ||
13266 !(RB_TYPE_P(dst_io, T_FILE) ||
13267 RB_TYPE_P(dst_io, T_STRING) ||
13268 rb_respond_to(dst_io, rb_intern("to_path")))) {
13269 stp->dst_fptr = NULL;
13270 }
13271 else {
13272 int stat_ret;
13273 VALUE tmp_io = rb_io_check_io(dst_io);
13274 if (!NIL_P(tmp_io)) {
13275 dst_io = GetWriteIO(tmp_io);
13276 }
13277 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13278 VALUE args[3];
13279 FilePathValue(dst_io);
13280 args[0] = dst_io;
13281 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13282 args[2] = INT2FIX(0666);
13283 dst_io = rb_class_new_instance(3, args, rb_cFile);
13284 stp->dst = dst_io;
13285 stp->close_dst = 1;
13286 }
13287 else {
13288 dst_io = GetWriteIO(dst_io);
13289 stp->dst = dst_io;
13290 }
13291 RB_IO_POINTER(dst_io, stp->dst_fptr);
13292 rb_io_check_writable(stp->dst_fptr);
13293
13294 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13295 if (stat_ret < 0) {
13296 stp->syserr = "fstat";
13297 stp->error_no = errno;
13298 return Qnil;
13299 }
13300 }
13301
13302#ifdef O_BINARY
13303 if (stp->src_fptr)
13304 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13305#endif
13306 if (stp->dst_fptr)
13307 io_ascii8bit_binmode(stp->dst_fptr);
13308
13309 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13310 size_t len = stp->src_fptr->rbuf.len;
13311 VALUE str;
13312 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13313 len = (size_t)stp->copy_length;
13314 }
13315 str = rb_str_buf_new(len);
13316 rb_str_resize(str,len);
13317 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13318 if (stp->dst_fptr) { /* IO or filename */
13319 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13320 rb_sys_fail_on_write(stp->dst_fptr);
13321 }
13322 else /* others such as StringIO */
13323 rb_io_write(dst_io, str);
13324 rb_str_resize(str, 0);
13325 stp->total += len;
13326 if (stp->copy_length >= (rb_off_t)0)
13327 stp->copy_length -= len;
13328 }
13329
13330 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13331 rb_raise(rb_eIOError, "flush failed");
13332 }
13333
13334 if (stp->copy_length == 0)
13335 return Qnil;
13336
13337 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13338 return copy_stream_fallback(stp);
13339 }
13340
13341 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13342 return Qnil;
13343}
13344
13345static VALUE
13346copy_stream_finalize(VALUE arg)
13347{
13348 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13349
13350#ifdef HAVE_FCOPYFILE
13351 if (stp->copyfile_state) {
13352 copyfile_state_free(stp->copyfile_state);
13353 }
13354#endif
13355
13356 if (stp->close_src) {
13357 rb_io_close_m(stp->src);
13358 }
13359 if (stp->close_dst) {
13360 rb_io_close_m(stp->dst);
13361 }
13362 if (stp->syserr) {
13363 rb_syserr_fail(stp->error_no, stp->syserr);
13364 }
13365 if (stp->notimp) {
13366 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13367 }
13368 return Qnil;
13369}
13370
13371/*
13372 * call-seq:
13373 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13374 *
13375 * Copies from the given +src+ to the given +dst+,
13376 * returning the number of bytes copied.
13377 *
13378 * - The given +src+ must be one of the following:
13379 *
13380 * - The path to a readable file, from which source data is to be read.
13381 * - An \IO-like object, opened for reading and capable of responding
13382 * to method +:readpartial+ or method +:read+.
13383 *
13384 * - The given +dst+ must be one of the following:
13385 *
13386 * - The path to a writable file, to which data is to be written.
13387 * - An \IO-like object, opened for writing and capable of responding
13388 * to method +:write+.
13389 *
13390 * The examples here use file <tt>t.txt</tt> as source:
13391 *
13392 * File.read('t.txt')
13393 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13394 * File.read('t.txt').size # => 47
13395 *
13396 * If only arguments +src+ and +dst+ are given,
13397 * the entire source stream is copied:
13398 *
13399 * # Paths.
13400 * IO.copy_stream('t.txt', 't.tmp') # => 47
13401 *
13402 * # IOs (recall that a File is also an IO).
13403 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13404 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13405 * IO.copy_stream(src_io, dst_io) # => 47
13406 * src_io.close
13407 * dst_io.close
13408 *
13409 * With argument +src_length+ a non-negative integer,
13410 * no more than that many bytes are copied:
13411 *
13412 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13413 * File.read('t.tmp') # => "First line"
13414 *
13415 * With argument +src_offset+ also given,
13416 * the source stream is read beginning at that offset:
13417 *
13418 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13419 * IO.read('t.tmp') # => "Second line"
13420 *
13421 */
13422static VALUE
13423rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13424{
13425 VALUE src, dst, length, src_offset;
13426 struct copy_stream_struct st;
13427
13428 MEMZERO(&st, struct copy_stream_struct, 1);
13429
13430 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13431
13432 st.src = src;
13433 st.dst = dst;
13434
13435 st.src_fptr = NULL;
13436 st.dst_fptr = NULL;
13437
13438 if (NIL_P(length))
13439 st.copy_length = (rb_off_t)-1;
13440 else
13441 st.copy_length = NUM2OFFT(length);
13442
13443 if (NIL_P(src_offset))
13444 st.src_offset = (rb_off_t)-1;
13445 else
13446 st.src_offset = NUM2OFFT(src_offset);
13447
13448 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13449
13450 return OFFT2NUM(st.total);
13451}
13452
13453/*
13454 * call-seq:
13455 * external_encoding -> encoding or nil
13456 *
13457 * Returns the Encoding object that represents the encoding of the stream,
13458 * or +nil+ if the stream is in write mode and no encoding is specified.
13459 *
13460 * See {Encodings}[rdoc-ref:File@Encodings].
13461 *
13462 */
13463
13464static VALUE
13465rb_io_external_encoding(VALUE io)
13466{
13467 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13468
13469 if (fptr->encs.enc2) {
13470 return rb_enc_from_encoding(fptr->encs.enc2);
13471 }
13472 if (fptr->mode & FMODE_WRITABLE) {
13473 if (fptr->encs.enc)
13474 return rb_enc_from_encoding(fptr->encs.enc);
13475 return Qnil;
13476 }
13477 return rb_enc_from_encoding(io_read_encoding(fptr));
13478}
13479
13480/*
13481 * call-seq:
13482 * internal_encoding -> encoding or nil
13483 *
13484 * Returns the Encoding object that represents the encoding of the internal string,
13485 * if conversion is specified,
13486 * or +nil+ otherwise.
13487 *
13488 * See {Encodings}[rdoc-ref:File@Encodings].
13489 *
13490 */
13491
13492static VALUE
13493rb_io_internal_encoding(VALUE io)
13494{
13495 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13496
13497 if (!fptr->encs.enc2) return Qnil;
13498 return rb_enc_from_encoding(io_read_encoding(fptr));
13499}
13500
13501/*
13502 * call-seq:
13503 * set_encoding(ext_enc) -> self
13504 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13505 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13506 *
13507 * See {Encodings}[rdoc-ref:File@Encodings].
13508 *
13509 * Argument +ext_enc+, if given, must be an Encoding object
13510 * or a String with the encoding name;
13511 * it is assigned as the encoding for the stream.
13512 *
13513 * Argument +int_enc+, if given, must be an Encoding object
13514 * or a String with the encoding name;
13515 * it is assigned as the encoding for the internal string.
13516 *
13517 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13518 * containing two colon-separated encoding names;
13519 * corresponding Encoding objects are assigned as the external
13520 * and internal encodings for the stream.
13521 *
13522 * If the external encoding of a string is binary/ASCII-8BIT,
13523 * the internal encoding of the string is set to nil, since no
13524 * transcoding is needed.
13525 *
13526 * Optional keyword arguments +enc_opts+ specify
13527 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13528 *
13529 */
13530
13531static VALUE
13532rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13533{
13534 rb_io_t *fptr;
13535 VALUE v1, v2, opt;
13536
13537 if (!RB_TYPE_P(io, T_FILE)) {
13538 return forward(io, id_set_encoding, argc, argv);
13539 }
13540
13541 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13542 GetOpenFile(io, fptr);
13543 io_encoding_set(fptr, v1, v2, opt);
13544 return io;
13545}
13546
13547void
13548rb_stdio_set_default_encoding(void)
13549{
13550 VALUE val = Qnil;
13551
13552#ifdef _WIN32
13553 if (isatty(fileno(stdin))) {
13554 rb_encoding *external = rb_locale_encoding();
13555 rb_encoding *internal = rb_default_internal_encoding();
13556 if (!internal) internal = rb_default_external_encoding();
13557 io_encoding_set(RFILE(rb_stdin)->fptr,
13558 rb_enc_from_encoding(external),
13559 rb_enc_from_encoding(internal),
13560 Qnil);
13561 }
13562 else
13563#endif
13564 rb_io_set_encoding(1, &val, rb_stdin);
13565 rb_io_set_encoding(1, &val, rb_stdout);
13566 rb_io_set_encoding(1, &val, rb_stderr);
13567}
13568
13569static inline int
13570global_argf_p(VALUE arg)
13571{
13572 return arg == argf;
13573}
13574
13575typedef VALUE (*argf_encoding_func)(VALUE io);
13576
13577static VALUE
13578argf_encoding(VALUE argf, argf_encoding_func func)
13579{
13580 if (!RTEST(ARGF.current_file)) {
13581 return rb_enc_default_external();
13582 }
13583 return func(rb_io_check_io(ARGF.current_file));
13584}
13585
13586/*
13587 * call-seq:
13588 * ARGF.external_encoding -> encoding
13589 *
13590 * Returns the external encoding for files read from ARGF as an Encoding
13591 * object. The external encoding is the encoding of the text as stored in a
13592 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13593 * represent this text within Ruby.
13594 *
13595 * To set the external encoding use ARGF.set_encoding.
13596 *
13597 * For example:
13598 *
13599 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13600 *
13601 */
13602static VALUE
13603argf_external_encoding(VALUE argf)
13604{
13605 return argf_encoding(argf, rb_io_external_encoding);
13606}
13607
13608/*
13609 * call-seq:
13610 * ARGF.internal_encoding -> encoding
13611 *
13612 * Returns the internal encoding for strings read from ARGF as an
13613 * Encoding object.
13614 *
13615 * If ARGF.set_encoding has been called with two encoding names, the second
13616 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13617 * value is returned. Failing that, if a default external encoding was
13618 * specified on the command-line, that value is used. If the encoding is
13619 * unknown, +nil+ is returned.
13620 */
13621static VALUE
13622argf_internal_encoding(VALUE argf)
13623{
13624 return argf_encoding(argf, rb_io_internal_encoding);
13625}
13626
13627/*
13628 * call-seq:
13629 * ARGF.set_encoding(ext_enc) -> ARGF
13630 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13631 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13632 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13633 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13634 *
13635 * If single argument is specified, strings read from ARGF are tagged with
13636 * the encoding specified.
13637 *
13638 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13639 * the read string is converted from the first encoding (external encoding)
13640 * to the second encoding (internal encoding), then tagged with the second
13641 * encoding.
13642 *
13643 * If two arguments are specified, they must be encoding objects or encoding
13644 * names. Again, the first specifies the external encoding; the second
13645 * specifies the internal encoding.
13646 *
13647 * If the external encoding and the internal encoding are specified, the
13648 * optional Hash argument can be used to adjust the conversion process. The
13649 * structure of this hash is explained in the String#encode documentation.
13650 *
13651 * For example:
13652 *
13653 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13654 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13655 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13656 * # to UTF-8.
13657 */
13658static VALUE
13659argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13660{
13661 rb_io_t *fptr;
13662
13663 if (!next_argv()) {
13664 rb_raise(rb_eArgError, "no stream to set encoding");
13665 }
13666 rb_io_set_encoding(argc, argv, ARGF.current_file);
13667 GetOpenFile(ARGF.current_file, fptr);
13668 ARGF.encs = fptr->encs;
13669 return argf;
13670}
13671
13672/*
13673 * call-seq:
13674 * ARGF.tell -> Integer
13675 * ARGF.pos -> Integer
13676 *
13677 * Returns the current offset (in bytes) of the current file in ARGF.
13678 *
13679 * ARGF.pos #=> 0
13680 * ARGF.gets #=> "This is line one\n"
13681 * ARGF.pos #=> 17
13682 *
13683 */
13684static VALUE
13685argf_tell(VALUE argf)
13686{
13687 if (!next_argv()) {
13688 rb_raise(rb_eArgError, "no stream to tell");
13689 }
13690 ARGF_FORWARD(0, 0);
13691 return rb_io_tell(ARGF.current_file);
13692}
13693
13694/*
13695 * call-seq:
13696 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13697 *
13698 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13699 * the value of _whence_. See IO#seek for further details.
13700 */
13701static VALUE
13702argf_seek_m(int argc, VALUE *argv, VALUE argf)
13703{
13704 if (!next_argv()) {
13705 rb_raise(rb_eArgError, "no stream to seek");
13706 }
13707 ARGF_FORWARD(argc, argv);
13708 return rb_io_seek_m(argc, argv, ARGF.current_file);
13709}
13710
13711/*
13712 * call-seq:
13713 * ARGF.pos = position -> Integer
13714 *
13715 * Seeks to the position given by _position_ (in bytes) in ARGF.
13716 *
13717 * For example:
13718 *
13719 * ARGF.pos = 17
13720 * ARGF.gets #=> "This is line two\n"
13721 */
13722static VALUE
13723argf_set_pos(VALUE argf, VALUE offset)
13724{
13725 if (!next_argv()) {
13726 rb_raise(rb_eArgError, "no stream to set position");
13727 }
13728 ARGF_FORWARD(1, &offset);
13729 return rb_io_set_pos(ARGF.current_file, offset);
13730}
13731
13732/*
13733 * call-seq:
13734 * ARGF.rewind -> 0
13735 *
13736 * Positions the current file to the beginning of input, resetting
13737 * ARGF.lineno to zero.
13738 *
13739 * ARGF.readline #=> "This is line one\n"
13740 * ARGF.rewind #=> 0
13741 * ARGF.lineno #=> 0
13742 * ARGF.readline #=> "This is line one\n"
13743 */
13744static VALUE
13745argf_rewind(VALUE argf)
13746{
13747 VALUE ret;
13748 int old_lineno;
13749
13750 if (!next_argv()) {
13751 rb_raise(rb_eArgError, "no stream to rewind");
13752 }
13753 ARGF_FORWARD(0, 0);
13754 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13755 ret = rb_io_rewind(ARGF.current_file);
13756 if (!global_argf_p(argf)) {
13757 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13758 }
13759 return ret;
13760}
13761
13762/*
13763 * call-seq:
13764 * ARGF.fileno -> integer
13765 * ARGF.to_i -> integer
13766 *
13767 * Returns an integer representing the numeric file descriptor for
13768 * the current file. Raises an ArgumentError if there isn't a current file.
13769 *
13770 * ARGF.fileno #=> 3
13771 */
13772static VALUE
13773argf_fileno(VALUE argf)
13774{
13775 if (!next_argv()) {
13776 rb_raise(rb_eArgError, "no stream");
13777 }
13778 ARGF_FORWARD(0, 0);
13779 return rb_io_fileno(ARGF.current_file);
13780}
13781
13782/*
13783 * call-seq:
13784 * ARGF.to_io -> IO
13785 *
13786 * Returns an IO object representing the current file. This will be a
13787 * File object unless the current file is a stream such as STDIN.
13788 *
13789 * For example:
13790 *
13791 * ARGF.to_io #=> #<File:glark.txt>
13792 * ARGF.to_io #=> #<IO:<STDIN>>
13793 */
13794static VALUE
13795argf_to_io(VALUE argf)
13796{
13797 next_argv();
13798 ARGF_FORWARD(0, 0);
13799 return ARGF.current_file;
13800}
13801
13802/*
13803 * call-seq:
13804 * ARGF.eof? -> true or false
13805 * ARGF.eof -> true or false
13806 *
13807 * Returns true if the current file in ARGF is at end of file, i.e. it has
13808 * no data to read. The stream must be opened for reading or an IOError
13809 * will be raised.
13810 *
13811 * $ echo "eof" | ruby argf.rb
13812 *
13813 * ARGF.eof? #=> false
13814 * 3.times { ARGF.readchar }
13815 * ARGF.eof? #=> false
13816 * ARGF.readchar #=> "\n"
13817 * ARGF.eof? #=> true
13818 */
13819
13820static VALUE
13821argf_eof(VALUE argf)
13822{
13823 next_argv();
13824 if (RTEST(ARGF.current_file)) {
13825 if (ARGF.init_p == 0) return Qtrue;
13826 next_argv();
13827 ARGF_FORWARD(0, 0);
13828 if (rb_io_eof(ARGF.current_file)) {
13829 return Qtrue;
13830 }
13831 }
13832 return Qfalse;
13833}
13834
13835/*
13836 * call-seq:
13837 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13838 *
13839 * Reads _length_ bytes from ARGF. The files named on the command line
13840 * are concatenated and treated as a single file by this method, so when
13841 * called without arguments the contents of this pseudo file are returned in
13842 * their entirety.
13843 *
13844 * _length_ must be a non-negative integer or +nil+.
13845 *
13846 * If _length_ is a positive integer, +read+ tries to read
13847 * _length_ bytes without any conversion (binary mode).
13848 * It returns +nil+ if an EOF is encountered before anything can be read.
13849 * Fewer than _length_ bytes are returned if an EOF is encountered during
13850 * the read.
13851 * In the case of an integer _length_, the resulting string is always
13852 * in ASCII-8BIT encoding.
13853 *
13854 * If _length_ is omitted or is +nil+, it reads until EOF
13855 * and the encoding conversion is applied, if applicable.
13856 * A string is returned even if EOF is encountered before any data is read.
13857 *
13858 * If _length_ is zero, it returns an empty string (<code>""</code>).
13859 *
13860 * If the optional _outbuf_ argument is present,
13861 * it must reference a String, which will receive the data.
13862 * The _outbuf_ will contain only the received data after the method call
13863 * even if it is not empty at the beginning.
13864 *
13865 * For example:
13866 *
13867 * $ echo "small" > small.txt
13868 * $ echo "large" > large.txt
13869 * $ ./glark.rb small.txt large.txt
13870 *
13871 * ARGF.read #=> "small\nlarge"
13872 * ARGF.read(200) #=> "small\nlarge"
13873 * ARGF.read(2) #=> "sm"
13874 * ARGF.read(0) #=> ""
13875 *
13876 * Note that this method behaves like the fread() function in C.
13877 * This means it retries to invoke read(2) system calls to read data
13878 * with the specified length.
13879 * If you need the behavior like a single read(2) system call,
13880 * consider ARGF#readpartial or ARGF#read_nonblock.
13881 */
13882
13883static VALUE
13884argf_read(int argc, VALUE *argv, VALUE argf)
13885{
13886 VALUE tmp, str, length;
13887 long len = 0;
13888
13889 rb_scan_args(argc, argv, "02", &length, &str);
13890 if (!NIL_P(length)) {
13891 len = NUM2LONG(argv[0]);
13892 }
13893 if (!NIL_P(str)) {
13894 StringValue(str);
13895 rb_str_resize(str,0);
13896 argv[1] = Qnil;
13897 }
13898
13899 retry:
13900 if (!next_argv()) {
13901 return str;
13902 }
13903 if (ARGF_GENERIC_INPUT_P()) {
13904 tmp = argf_forward(argc, argv, argf);
13905 }
13906 else {
13907 tmp = io_read(argc, argv, ARGF.current_file);
13908 }
13909 if (NIL_P(str)) str = tmp;
13910 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13911 if (NIL_P(tmp) || NIL_P(length)) {
13912 if (ARGF.next_p != -1) {
13913 argf_close(argf);
13914 ARGF.next_p = 1;
13915 goto retry;
13916 }
13917 }
13918 else if (argc >= 1) {
13919 long slen = RSTRING_LEN(str);
13920 if (slen < len) {
13921 argv[0] = LONG2NUM(len - slen);
13922 goto retry;
13923 }
13924 }
13925 return str;
13926}
13927
13929 int argc;
13930 VALUE *argv;
13931 VALUE argf;
13932};
13933
13934static VALUE
13935argf_forward_call(VALUE arg)
13936{
13937 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13938 argf_forward(p->argc, p->argv, p->argf);
13939 return Qnil;
13940}
13941
13942static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13943 int nonblock);
13944
13945/*
13946 * call-seq:
13947 * ARGF.readpartial(maxlen) -> string
13948 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13949 *
13950 * Reads at most _maxlen_ bytes from the ARGF stream.
13951 *
13952 * If the optional _outbuf_ argument is present,
13953 * it must reference a String, which will receive the data.
13954 * The _outbuf_ will contain only the received data after the method call
13955 * even if it is not empty at the beginning.
13956 *
13957 * It raises EOFError on end of ARGF stream.
13958 * Since ARGF stream is a concatenation of multiple files,
13959 * internally EOF is occur for each file.
13960 * ARGF.readpartial returns empty strings for EOFs except the last one and
13961 * raises EOFError for the last one.
13962 *
13963 */
13964
13965static VALUE
13966argf_readpartial(int argc, VALUE *argv, VALUE argf)
13967{
13968 return argf_getpartial(argc, argv, argf, Qnil, 0);
13969}
13970
13971/*
13972 * call-seq:
13973 * ARGF.read_nonblock(maxlen[, options]) -> string
13974 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13975 *
13976 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13977 */
13978
13979static VALUE
13980argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13981{
13982 VALUE opts;
13983
13984 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
13985
13986 if (!NIL_P(opts))
13987 argc--;
13988
13989 return argf_getpartial(argc, argv, argf, opts, 1);
13990}
13991
13992static VALUE
13993argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
13994{
13995 VALUE tmp, str, length;
13996 int no_exception;
13997
13998 rb_scan_args(argc, argv, "11", &length, &str);
13999 if (!NIL_P(str)) {
14000 StringValue(str);
14001 argv[1] = str;
14002 }
14003 no_exception = no_exception_p(opts);
14004
14005 if (!next_argv()) {
14006 if (!NIL_P(str)) {
14007 rb_str_resize(str, 0);
14008 }
14009 rb_eof_error();
14010 }
14011 if (ARGF_GENERIC_INPUT_P()) {
14012 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14013 struct argf_call_arg arg;
14014 arg.argc = argc;
14015 arg.argv = argv;
14016 arg.argf = argf;
14017 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14018 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14019 }
14020 else {
14021 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14022 }
14023 if (NIL_P(tmp)) {
14024 if (ARGF.next_p == -1) {
14025 return io_nonblock_eof(no_exception);
14026 }
14027 argf_close(argf);
14028 ARGF.next_p = 1;
14029 if (RARRAY_LEN(ARGF.argv) == 0) {
14030 return io_nonblock_eof(no_exception);
14031 }
14032 if (NIL_P(str))
14033 str = rb_str_new(NULL, 0);
14034 return str;
14035 }
14036 return tmp;
14037}
14038
14039/*
14040 * call-seq:
14041 * ARGF.getc -> String or nil
14042 *
14043 * Reads the next character from ARGF and returns it as a String. Returns
14044 * +nil+ at the end of the stream.
14045 *
14046 * ARGF treats the files named on the command line as a single file created
14047 * by concatenating their contents. After returning the last character of the
14048 * first file, it returns the first character of the second file, and so on.
14049 *
14050 * For example:
14051 *
14052 * $ echo "foo" > file
14053 * $ ruby argf.rb file
14054 *
14055 * ARGF.getc #=> "f"
14056 * ARGF.getc #=> "o"
14057 * ARGF.getc #=> "o"
14058 * ARGF.getc #=> "\n"
14059 * ARGF.getc #=> nil
14060 * ARGF.getc #=> nil
14061 */
14062static VALUE
14063argf_getc(VALUE argf)
14064{
14065 VALUE ch;
14066
14067 retry:
14068 if (!next_argv()) return Qnil;
14069 if (ARGF_GENERIC_INPUT_P()) {
14070 ch = forward_current(rb_intern("getc"), 0, 0);
14071 }
14072 else {
14073 ch = rb_io_getc(ARGF.current_file);
14074 }
14075 if (NIL_P(ch) && ARGF.next_p != -1) {
14076 argf_close(argf);
14077 ARGF.next_p = 1;
14078 goto retry;
14079 }
14080
14081 return ch;
14082}
14083
14084/*
14085 * call-seq:
14086 * ARGF.getbyte -> Integer or nil
14087 *
14088 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14089 * the end of the stream.
14090 *
14091 * For example:
14092 *
14093 * $ echo "foo" > file
14094 * $ ruby argf.rb file
14095 *
14096 * ARGF.getbyte #=> 102
14097 * ARGF.getbyte #=> 111
14098 * ARGF.getbyte #=> 111
14099 * ARGF.getbyte #=> 10
14100 * ARGF.getbyte #=> nil
14101 */
14102static VALUE
14103argf_getbyte(VALUE argf)
14104{
14105 VALUE ch;
14106
14107 retry:
14108 if (!next_argv()) return Qnil;
14109 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14110 ch = forward_current(rb_intern("getbyte"), 0, 0);
14111 }
14112 else {
14113 ch = rb_io_getbyte(ARGF.current_file);
14114 }
14115 if (NIL_P(ch) && ARGF.next_p != -1) {
14116 argf_close(argf);
14117 ARGF.next_p = 1;
14118 goto retry;
14119 }
14120
14121 return ch;
14122}
14123
14124/*
14125 * call-seq:
14126 * ARGF.readchar -> String or nil
14127 *
14128 * Reads the next character from ARGF and returns it as a String. Raises
14129 * an EOFError after the last character of the last file has been read.
14130 *
14131 * For example:
14132 *
14133 * $ echo "foo" > file
14134 * $ ruby argf.rb file
14135 *
14136 * ARGF.readchar #=> "f"
14137 * ARGF.readchar #=> "o"
14138 * ARGF.readchar #=> "o"
14139 * ARGF.readchar #=> "\n"
14140 * ARGF.readchar #=> end of file reached (EOFError)
14141 */
14142static VALUE
14143argf_readchar(VALUE argf)
14144{
14145 VALUE ch;
14146
14147 retry:
14148 if (!next_argv()) rb_eof_error();
14149 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14150 ch = forward_current(rb_intern("getc"), 0, 0);
14151 }
14152 else {
14153 ch = rb_io_getc(ARGF.current_file);
14154 }
14155 if (NIL_P(ch) && ARGF.next_p != -1) {
14156 argf_close(argf);
14157 ARGF.next_p = 1;
14158 goto retry;
14159 }
14160
14161 return ch;
14162}
14163
14164/*
14165 * call-seq:
14166 * ARGF.readbyte -> Integer
14167 *
14168 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14169 * an EOFError after the last byte of the last file has been read.
14170 *
14171 * For example:
14172 *
14173 * $ echo "foo" > file
14174 * $ ruby argf.rb file
14175 *
14176 * ARGF.readbyte #=> 102
14177 * ARGF.readbyte #=> 111
14178 * ARGF.readbyte #=> 111
14179 * ARGF.readbyte #=> 10
14180 * ARGF.readbyte #=> end of file reached (EOFError)
14181 */
14182static VALUE
14183argf_readbyte(VALUE argf)
14184{
14185 VALUE c;
14186
14187 NEXT_ARGF_FORWARD(0, 0);
14188 c = argf_getbyte(argf);
14189 if (NIL_P(c)) {
14190 rb_eof_error();
14191 }
14192 return c;
14193}
14194
14195#define FOREACH_ARGF() while (next_argv())
14196
14197static VALUE
14198argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14199{
14200 const VALUE current = ARGF.current_file;
14201 rb_yield_values2(argc, argv);
14202 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14204 }
14205 return Qnil;
14206}
14207
14208#define ARGF_block_call(mid, argc, argv, func, argf) \
14209 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14210 func, argf, rb_keyword_given_p())
14211
14212static void
14213argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14214{
14215 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14216 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14217}
14218
14219static VALUE
14220argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14221{
14222 if (!global_argf_p(argf)) {
14223 ARGF.last_lineno = ++ARGF.lineno;
14224 }
14225 return argf_block_call_i(i, argf, argc, argv, blockarg);
14226}
14227
14228static void
14229argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14230{
14231 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14232 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14233}
14234
14235/*
14236 * call-seq:
14237 * ARGF.each(sep=$/) {|line| block } -> ARGF
14238 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14239 * ARGF.each(...) -> an_enumerator
14240 *
14241 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14242 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14243 * ARGF.each_line(...) -> an_enumerator
14244 *
14245 * Returns an enumerator which iterates over each line (separated by _sep_,
14246 * which defaults to your platform's newline character) of each file in
14247 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14248 * block, otherwise an enumerator is returned.
14249 * The optional _limit_ argument is an Integer specifying the maximum
14250 * length of each line; longer lines will be split according to this limit.
14251 *
14252 * This method allows you to treat the files supplied on the command line as
14253 * a single file consisting of the concatenation of each named file. After
14254 * the last line of the first file has been returned, the first line of the
14255 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14256 * used to determine the filename of the current line and line number of the
14257 * whole input, respectively.
14258 *
14259 * For example, the following code prints out each line of each named file
14260 * prefixed with its line number, displaying the filename once per file:
14261 *
14262 * ARGF.each_line do |line|
14263 * puts ARGF.filename if ARGF.file.lineno == 1
14264 * puts "#{ARGF.file.lineno}: #{line}"
14265 * end
14266 *
14267 * While the following code prints only the first file's name at first, and
14268 * the contents with line number counted through all named files.
14269 *
14270 * ARGF.each_line do |line|
14271 * puts ARGF.filename if ARGF.lineno == 1
14272 * puts "#{ARGF.lineno}: #{line}"
14273 * end
14274 */
14275static VALUE
14276argf_each_line(int argc, VALUE *argv, VALUE argf)
14277{
14278 RETURN_ENUMERATOR(argf, argc, argv);
14279 FOREACH_ARGF() {
14280 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14281 }
14282 return argf;
14283}
14284
14285/*
14286 * call-seq:
14287 * ARGF.each_byte {|byte| block } -> ARGF
14288 * ARGF.each_byte -> an_enumerator
14289 *
14290 * Iterates over each byte of each file in +ARGV+.
14291 * A byte is returned as an Integer in the range 0..255.
14292 *
14293 * This method allows you to treat the files supplied on the command line as
14294 * a single file consisting of the concatenation of each named file. After
14295 * the last byte of the first file has been returned, the first byte of the
14296 * second file is returned. The ARGF.filename method can be used to
14297 * determine the filename of the current byte.
14298 *
14299 * If no block is given, an enumerator is returned instead.
14300 *
14301 * For example:
14302 *
14303 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14304 *
14305 */
14306static VALUE
14307argf_each_byte(VALUE argf)
14308{
14309 RETURN_ENUMERATOR(argf, 0, 0);
14310 FOREACH_ARGF() {
14311 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14312 }
14313 return argf;
14314}
14315
14316/*
14317 * call-seq:
14318 * ARGF.each_char {|char| block } -> ARGF
14319 * ARGF.each_char -> an_enumerator
14320 *
14321 * Iterates over each character of each file in ARGF.
14322 *
14323 * This method allows you to treat the files supplied on the command line as
14324 * a single file consisting of the concatenation of each named file. After
14325 * the last character of the first file has been returned, the first
14326 * character of the second file is returned. The ARGF.filename method can
14327 * be used to determine the name of the file in which the current character
14328 * appears.
14329 *
14330 * If no block is given, an enumerator is returned instead.
14331 */
14332static VALUE
14333argf_each_char(VALUE argf)
14334{
14335 RETURN_ENUMERATOR(argf, 0, 0);
14336 FOREACH_ARGF() {
14337 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14338 }
14339 return argf;
14340}
14341
14342/*
14343 * call-seq:
14344 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14345 * ARGF.each_codepoint -> an_enumerator
14346 *
14347 * Iterates over each codepoint of each file in ARGF.
14348 *
14349 * This method allows you to treat the files supplied on the command line as
14350 * a single file consisting of the concatenation of each named file. After
14351 * the last codepoint of the first file has been returned, the first
14352 * codepoint of the second file is returned. The ARGF.filename method can
14353 * be used to determine the name of the file in which the current codepoint
14354 * appears.
14355 *
14356 * If no block is given, an enumerator is returned instead.
14357 */
14358static VALUE
14359argf_each_codepoint(VALUE argf)
14360{
14361 RETURN_ENUMERATOR(argf, 0, 0);
14362 FOREACH_ARGF() {
14363 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14364 }
14365 return argf;
14366}
14367
14368/*
14369 * call-seq:
14370 * ARGF.filename -> String
14371 * ARGF.path -> String
14372 *
14373 * Returns the current filename. "-" is returned when the current file is
14374 * STDIN.
14375 *
14376 * For example:
14377 *
14378 * $ echo "foo" > foo
14379 * $ echo "bar" > bar
14380 * $ echo "glark" > glark
14381 *
14382 * $ ruby argf.rb foo bar glark
14383 *
14384 * ARGF.filename #=> "foo"
14385 * ARGF.read(5) #=> "foo\nb"
14386 * ARGF.filename #=> "bar"
14387 * ARGF.skip
14388 * ARGF.filename #=> "glark"
14389 */
14390static VALUE
14391argf_filename(VALUE argf)
14392{
14393 next_argv();
14394 return ARGF.filename;
14395}
14396
14397static VALUE
14398argf_filename_getter(ID id, VALUE *var)
14399{
14400 return argf_filename(*var);
14401}
14402
14403/*
14404 * call-seq:
14405 * ARGF.file -> IO or File object
14406 *
14407 * Returns the current file as an IO or File object.
14408 * <code>$stdin</code> is returned when the current file is STDIN.
14409 *
14410 * For example:
14411 *
14412 * $ echo "foo" > foo
14413 * $ echo "bar" > bar
14414 *
14415 * $ ruby argf.rb foo bar
14416 *
14417 * ARGF.file #=> #<File:foo>
14418 * ARGF.read(5) #=> "foo\nb"
14419 * ARGF.file #=> #<File:bar>
14420 */
14421static VALUE
14422argf_file(VALUE argf)
14423{
14424 next_argv();
14425 return ARGF.current_file;
14426}
14427
14428/*
14429 * call-seq:
14430 * ARGF.binmode -> ARGF
14431 *
14432 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14433 * be reset to non-binary mode. This option has the following effects:
14434 *
14435 * * Newline conversion is disabled.
14436 * * Encoding conversion is disabled.
14437 * * Content is treated as ASCII-8BIT.
14438 */
14439static VALUE
14440argf_binmode_m(VALUE argf)
14441{
14442 ARGF.binmode = 1;
14443 next_argv();
14444 ARGF_FORWARD(0, 0);
14445 rb_io_ascii8bit_binmode(ARGF.current_file);
14446 return argf;
14447}
14448
14449/*
14450 * call-seq:
14451 * ARGF.binmode? -> true or false
14452 *
14453 * Returns true if ARGF is being read in binary mode; false otherwise.
14454 * To enable binary mode use ARGF.binmode.
14455 *
14456 * For example:
14457 *
14458 * ARGF.binmode? #=> false
14459 * ARGF.binmode
14460 * ARGF.binmode? #=> true
14461 */
14462static VALUE
14463argf_binmode_p(VALUE argf)
14464{
14465 return RBOOL(ARGF.binmode);
14466}
14467
14468/*
14469 * call-seq:
14470 * ARGF.skip -> ARGF
14471 *
14472 * Sets the current file to the next file in ARGV. If there aren't any more
14473 * files it has no effect.
14474 *
14475 * For example:
14476 *
14477 * $ ruby argf.rb foo bar
14478 * ARGF.filename #=> "foo"
14479 * ARGF.skip
14480 * ARGF.filename #=> "bar"
14481 */
14482static VALUE
14483argf_skip(VALUE argf)
14484{
14485 if (ARGF.init_p && ARGF.next_p == 0) {
14486 argf_close(argf);
14487 ARGF.next_p = 1;
14488 }
14489 return argf;
14490}
14491
14492/*
14493 * call-seq:
14494 * ARGF.close -> ARGF
14495 *
14496 * Closes the current file and skips to the next file in ARGV. If there are
14497 * no more files to open, just closes the current file. STDIN will not be
14498 * closed.
14499 *
14500 * For example:
14501 *
14502 * $ ruby argf.rb foo bar
14503 *
14504 * ARGF.filename #=> "foo"
14505 * ARGF.close
14506 * ARGF.filename #=> "bar"
14507 * ARGF.close
14508 */
14509static VALUE
14510argf_close_m(VALUE argf)
14511{
14512 next_argv();
14513 argf_close(argf);
14514 if (ARGF.next_p != -1) {
14515 ARGF.next_p = 1;
14516 }
14517 ARGF.lineno = 0;
14518 return argf;
14519}
14520
14521/*
14522 * call-seq:
14523 * ARGF.closed? -> true or false
14524 *
14525 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14526 * ARGF.close to actually close the current file.
14527 */
14528static VALUE
14529argf_closed(VALUE argf)
14530{
14531 next_argv();
14532 ARGF_FORWARD(0, 0);
14533 return rb_io_closed_p(ARGF.current_file);
14534}
14535
14536/*
14537 * call-seq:
14538 * ARGF.to_s -> String
14539 *
14540 * Returns "ARGF".
14541 */
14542static VALUE
14543argf_to_s(VALUE argf)
14544{
14545 return rb_str_new2("ARGF");
14546}
14547
14548/*
14549 * call-seq:
14550 * ARGF.inplace_mode -> String
14551 *
14552 * Returns the file extension appended to the names of backup copies of
14553 * modified files under in-place edit mode. This value can be set using
14554 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14555 */
14556static VALUE
14557argf_inplace_mode_get(VALUE argf)
14558{
14559 if (!ARGF.inplace) return Qnil;
14560 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14561 return rb_str_dup(ARGF.inplace);
14562}
14563
14564static VALUE
14565opt_i_get(ID id, VALUE *var)
14566{
14567 return argf_inplace_mode_get(*var);
14568}
14569
14570/*
14571 * call-seq:
14572 * ARGF.inplace_mode = ext -> ARGF
14573 *
14574 * Sets the filename extension for in-place editing mode to the given String.
14575 * The backup copy of each file being edited has this value appended to its
14576 * filename.
14577 *
14578 * For example:
14579 *
14580 * $ ruby argf.rb file.txt
14581 *
14582 * ARGF.inplace_mode = '.bak'
14583 * ARGF.each_line do |line|
14584 * print line.sub("foo","bar")
14585 * end
14586 *
14587 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14588 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14589 * "bar".
14590 */
14591static VALUE
14592argf_inplace_mode_set(VALUE argf, VALUE val)
14593{
14594 if (!RTEST(val)) {
14595 ARGF.inplace = Qfalse;
14596 }
14597 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14598 ARGF.inplace = Qnil;
14599 }
14600 else {
14601 ARGF.inplace = rb_str_new_frozen(val);
14602 }
14603 return argf;
14604}
14605
14606static void
14607opt_i_set(VALUE val, ID id, VALUE *var)
14608{
14609 argf_inplace_mode_set(*var, val);
14610}
14611
14612void
14613ruby_set_inplace_mode(const char *suffix)
14614{
14615 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14616}
14617
14618/*
14619 * call-seq:
14620 * ARGF.argv -> ARGV
14621 *
14622 * Returns the +ARGV+ array, which contains the arguments passed to your
14623 * script, one per element.
14624 *
14625 * For example:
14626 *
14627 * $ ruby argf.rb -v glark.txt
14628 *
14629 * ARGF.argv #=> ["-v", "glark.txt"]
14630 *
14631 */
14632static VALUE
14633argf_argv(VALUE argf)
14634{
14635 return ARGF.argv;
14636}
14637
14638static VALUE
14639argf_argv_getter(ID id, VALUE *var)
14640{
14641 return argf_argv(*var);
14642}
14643
14644VALUE
14646{
14647 return ARGF.argv;
14648}
14649
14650/*
14651 * call-seq:
14652 * ARGF.to_write_io -> io
14653 *
14654 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14655 * enabled.
14656 */
14657static VALUE
14658argf_write_io(VALUE argf)
14659{
14660 if (!RTEST(ARGF.current_file)) {
14661 rb_raise(rb_eIOError, "not opened for writing");
14662 }
14663 return GetWriteIO(ARGF.current_file);
14664}
14665
14666/*
14667 * call-seq:
14668 * ARGF.write(*objects) -> integer
14669 *
14670 * Writes each of the given +objects+ if inplace mode.
14671 */
14672static VALUE
14673argf_write(int argc, VALUE *argv, VALUE argf)
14674{
14675 return rb_io_writev(argf_write_io(argf), argc, argv);
14676}
14677
14678void
14679rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14680{
14681 rb_readwrite_syserr_fail(waiting, errno, mesg);
14682}
14683
14684void
14685rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14686{
14687 VALUE arg, c = Qnil;
14688 arg = mesg ? rb_str_new2(mesg) : Qnil;
14689 switch (waiting) {
14690 case RB_IO_WAIT_WRITABLE:
14691 switch (n) {
14692 case EAGAIN:
14693 c = rb_eEAGAINWaitWritable;
14694 break;
14695#if EAGAIN != EWOULDBLOCK
14696 case EWOULDBLOCK:
14697 c = rb_eEWOULDBLOCKWaitWritable;
14698 break;
14699#endif
14700 case EINPROGRESS:
14701 c = rb_eEINPROGRESSWaitWritable;
14702 break;
14703 default:
14705 }
14706 break;
14707 case RB_IO_WAIT_READABLE:
14708 switch (n) {
14709 case EAGAIN:
14710 c = rb_eEAGAINWaitReadable;
14711 break;
14712#if EAGAIN != EWOULDBLOCK
14713 case EWOULDBLOCK:
14714 c = rb_eEWOULDBLOCKWaitReadable;
14715 break;
14716#endif
14717 case EINPROGRESS:
14718 c = rb_eEINPROGRESSWaitReadable;
14719 break;
14720 default:
14722 }
14723 break;
14724 default:
14725 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14726 }
14728}
14729
14730static VALUE
14731get_LAST_READ_LINE(ID _x, VALUE *_y)
14732{
14733 return rb_lastline_get();
14734}
14735
14736static void
14737set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14738{
14739 rb_lastline_set(val);
14740}
14741
14742/*
14743 * Document-class: IOError
14744 *
14745 * Raised when an IO operation fails.
14746 *
14747 * File.open("/etc/hosts") {|f| f << "example"}
14748 * #=> IOError: not opened for writing
14749 *
14750 * File.open("/etc/hosts") {|f| f.close; f.read }
14751 * #=> IOError: closed stream
14752 *
14753 * Note that some IO failures raise <code>SystemCallError</code>s
14754 * and these are not subclasses of IOError:
14755 *
14756 * File.open("does/not/exist")
14757 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14758 */
14759
14760/*
14761 * Document-class: EOFError
14762 *
14763 * Raised by some IO operations when reaching the end of file. Many IO
14764 * methods exist in two forms,
14765 *
14766 * one that returns +nil+ when the end of file is reached, the other
14767 * raises EOFError.
14768 *
14769 * EOFError is a subclass of IOError.
14770 *
14771 * file = File.open("/etc/hosts")
14772 * file.read
14773 * file.gets #=> nil
14774 * file.readline #=> EOFError: end of file reached
14775 * file.close
14776 */
14777
14778/*
14779 * Document-class: ARGF
14780 *
14781 * == \ARGF and +ARGV+
14782 *
14783 * The \ARGF object works with the array at global variable +ARGV+
14784 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14785 *
14786 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14787 *
14788 * Initially, it contains the command-line arguments and options
14789 * that are passed to the Ruby program;
14790 * the program can modify that array as it likes.
14791 *
14792 * - **ARGF** may be thought of as the <b>argument files</b> object.
14793 *
14794 * It can access file streams and/or the <tt>$stdin</tt> stream,
14795 * based on what it finds in +ARGV+.
14796 * This provides a convenient way for the command line
14797 * to specify streams for a Ruby program to read.
14798 *
14799 * == Reading
14800 *
14801 * \ARGF may read from _source_ streams,
14802 * which at any particular time are determined by the content of +ARGV+.
14803 *
14804 * === Simplest Case
14805 *
14806 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14807 * the source is <tt>$stdin</tt>:
14808 *
14809 * - \File +t.rb+:
14810 *
14811 * p ['ARGV', ARGV]
14812 * p ['ARGF.read', ARGF.read]
14813 *
14814 * - Commands and outputs
14815 * (see below for the content of files +foo.txt+ and +bar.txt+):
14816 *
14817 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14818 * ["ARGV", []]
14819 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14820 *
14821 * $ cat foo.txt bar.txt | ruby t.rb
14822 * ["ARGV", []]
14823 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14824 *
14825 * === About the Examples
14826 *
14827 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14828 *
14829 * $ cat foo.txt
14830 * Foo 0
14831 * Foo 1
14832 * $ cat bar.txt
14833 * Bar 0
14834 * Bar 1
14835 * Bar 2
14836 * Bar 3
14837 *
14838 * === Sources in +ARGV+
14839 *
14840 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14841 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14842 * the sources are found in +ARGV+.
14843 *
14844 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14845 * and is one of:
14846 *
14847 * - The string path to a file that may be opened as a stream.
14848 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14849 *
14850 * Each element that is _not_ one of these
14851 * should be removed from +ARGV+ before \ARGF accesses that source.
14852 *
14853 * In the following example:
14854 *
14855 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14856 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14857 *
14858 * Example:
14859 *
14860 * - \File +t.rb+:
14861 *
14862 * # Print arguments (and options, if any) found on command line.
14863 * p ['ARGV', ARGV]
14864 *
14865 * - Command and output:
14866 *
14867 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14868 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14869 *
14870 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14871 *
14872 * - \File +t.rb+:
14873 *
14874 * p "ARGV: #{ARGV}"
14875 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
14876 *
14877 * - Command and output:
14878 *
14879 * $ ruby t.rb foo.txt bar.txt
14880 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14881 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14882 *
14883 * Because the value at +ARGV+ is an ordinary array,
14884 * you can manipulate it to control which sources \ARGF considers:
14885 *
14886 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14887 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14888 *
14889 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14890 * when all sources have been accessed, the array is empty:
14891 *
14892 * - \File +t.rb+:
14893 *
14894 * until ARGV.empty? && ARGF.eof?
14895 * p "ARGV: #{ARGV}"
14896 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14897 * end
14898 *
14899 * - Command and output:
14900 *
14901 * $ ruby t.rb foo.txt bar.txt
14902 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14903 * "Line: Foo 0\n"
14904 * "ARGV: [\"bar.txt\"]"
14905 * "Line: Foo 1\n"
14906 * "ARGV: [\"bar.txt\"]"
14907 * "Line: Bar 0\n"
14908 * "ARGV: []"
14909 * "Line: Bar 1\n"
14910 * "ARGV: []"
14911 * "Line: Bar 2\n"
14912 * "ARGV: []"
14913 * "Line: Bar 3\n"
14914 *
14915 * ==== Filepaths in +ARGV+
14916 *
14917 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14918 *
14919 * This program prints what it reads from files at the paths specified
14920 * on the command line:
14921 *
14922 * - \File +t.rb+:
14923 *
14924 * p ['ARGV', ARGV]
14925 * # Read and print all content from the specified sources.
14926 * p ['ARGF.read', ARGF.read]
14927 *
14928 * - Command and output:
14929 *
14930 * $ ruby t.rb foo.txt bar.txt
14931 * ["ARGV", [foo.txt, bar.txt]
14932 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14933 *
14934 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14935 *
14936 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14937 *
14938 * - \File +t.rb+:
14939 *
14940 * p ['ARGV', ARGV]
14941 * p ['ARGF.read', ARGF.read]
14942 *
14943 * - Command and output:
14944 *
14945 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14946 * ["ARGV", ["-"]]
14947 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14948 *
14949 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
14950 * (exception:
14951 * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
14952 *
14953 * - Command and output:
14954 *
14955 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
14956 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14957 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14958 *
14959 * ==== Mixtures and Repetitions in +ARGV+
14960 *
14961 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
14962 * and character <tt>'-'</tt>, including repetitions.
14963 *
14964 * ==== Modifications to +ARGV+
14965 *
14966 * The running Ruby program may make any modifications to the +ARGV+ array;
14967 * the current value of +ARGV+ affects \ARGF reading.
14968 *
14969 * ==== Empty +ARGV+
14970 *
14971 * For an empty +ARGV+, an \ARGF read method either returns +nil+
14972 * or raises an exception, depending on the specific method.
14973 *
14974 * === More Read Methods
14975 *
14976 * As seen above, method ARGF#read reads the content of all sources
14977 * into a single string.
14978 * Other \ARGF methods provide other ways to access that content;
14979 * these include:
14980 *
14981 * - Byte access: #each_byte, #getbyte, #readbyte.
14982 * - Character access: #each_char, #getc, #readchar.
14983 * - Codepoint access: #each_codepoint.
14984 * - Line access: #each_line, #gets, #readline, #readlines.
14985 * - Source access: #read, #read_nonblock, #readpartial.
14986 *
14987 * === About \Enumerable
14988 *
14989 * \ARGF includes module Enumerable.
14990 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
14991 *
14992 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
14993 * _not_ from +ARGV+;
14994 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
14995 * not an array of the strings from +ARGV+:
14996 *
14997 * - \File +t.rb+:
14998 *
14999 * p ['ARGV', ARGV]
15000 * p ['ARGF.entries', ARGF.entries]
15001 *
15002 * - Command and output:
15003 *
15004 * $ ruby t.rb foo.txt bar.txt
15005 * ["ARGV", ["foo.txt", "bar.txt"]]
15006 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15007 *
15008 * == Writing
15009 *
15010 * If <i>inplace mode</i> is in effect,
15011 * \ARGF may write to target streams,
15012 * which at any particular time are determined by the content of ARGV.
15013 *
15014 * Methods about inplace mode:
15015 *
15016 * - #inplace_mode
15017 * - #inplace_mode=
15018 * - #to_write_io
15019 *
15020 * Methods for writing:
15021 *
15022 * - #print
15023 * - #printf
15024 * - #putc
15025 * - #puts
15026 * - #write
15027 *
15028 */
15029
15030/*
15031 * An instance of class \IO (commonly called a _stream_)
15032 * represents an input/output stream in the underlying operating system.
15033 * Class \IO is the basis for input and output in Ruby.
15034 *
15035 * Class File is the only class in the Ruby core that is a subclass of \IO.
15036 * Some classes in the Ruby standard library are also subclasses of \IO;
15037 * these include TCPSocket and UDPSocket.
15038 *
15039 * The global constant ARGF (also accessible as <tt>$<</tt>)
15040 * provides an IO-like stream that allows access to all file paths
15041 * found in ARGV (or found in STDIN if ARGV is empty).
15042 * ARGF is not itself a subclass of \IO.
15043 *
15044 * Class StringIO provides an IO-like stream that handles a String.
15045 * StringIO is not itself a subclass of \IO.
15046 *
15047 * Important objects based on \IO include:
15048 *
15049 * - $stdin.
15050 * - $stdout.
15051 * - $stderr.
15052 * - Instances of class File.
15053 *
15054 * An instance of \IO may be created using:
15055 *
15056 * - IO.new: returns a new \IO object for the given integer file descriptor.
15057 * - IO.open: passes a new \IO object to the given block.
15058 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15059 * of a newly-launched subprocess.
15060 * - Kernel#open: Returns a new \IO object connected to a given source:
15061 * stream, file, or subprocess.
15062 *
15063 * Like a File stream, an \IO stream has:
15064 *
15065 * - A read/write mode, which may be read-only, write-only, or read/write;
15066 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
15067 * - A data mode, which may be text-only or binary;
15068 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15069 * - Internal and external encodings;
15070 * see {Encodings}[rdoc-ref:File@Encodings].
15071 *
15072 * And like other \IO streams, it has:
15073 *
15074 * - A position, which determines where in the stream the next
15075 * read or write is to occur;
15076 * see {Position}[rdoc-ref:IO@Position].
15077 * - A line number, which is a special, line-oriented, "position"
15078 * (different from the position mentioned above);
15079 * see {Line Number}[rdoc-ref:IO@Line+Number].
15080 *
15081 * == Extension <tt>io/console</tt>
15082 *
15083 * Extension <tt>io/console</tt> provides numerous methods
15084 * for interacting with the console;
15085 * requiring it adds numerous methods to class \IO.
15086 *
15087 * == Example Files
15088 *
15089 * Many examples here use these variables:
15090 *
15091 * :include: doc/examples/files.rdoc
15092 *
15093 * == Open Options
15094 *
15095 * A number of \IO methods accept optional keyword arguments
15096 * that determine how a new stream is to be opened:
15097 *
15098 * - +:mode+: Stream mode.
15099 * - +:flags+: Integer file open flags;
15100 * If +mode+ is also given, the two are bitwise-ORed.
15101 * - +:external_encoding+: External encoding for the stream.
15102 * - +:internal_encoding+: Internal encoding for the stream.
15103 * <tt>'-'</tt> is a synonym for the default internal encoding.
15104 * If the value is +nil+ no conversion occurs.
15105 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15106 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15107 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15108 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15109 * when the stream closes; otherwise it remains open.
15110 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15111 * #path method.
15112 *
15113 * Also available are the options offered in String#encode,
15114 * which may control conversion between external and internal encoding.
15115 *
15116 * == Basic \IO
15117 *
15118 * You can perform basic stream \IO with these methods,
15119 * which typically operate on multi-byte strings:
15120 *
15121 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15122 * - IO#write: Writes zero or more strings to the stream;
15123 * each given object that is not already a string is converted via +to_s+.
15124 *
15125 * === Position
15126 *
15127 * An \IO stream has a nonnegative integer _position_,
15128 * which is the byte offset at which the next read or write is to occur.
15129 * A new stream has position zero (and line number zero);
15130 * method +rewind+ resets the position (and line number) to zero.
15131 *
15132 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15133 * Encoding::Converter instances used for that \IO.
15134 *
15135 * The relevant methods:
15136 *
15137 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15138 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15139 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15140 * relative to a given position +whence+
15141 * (indicating the beginning, end, or current position).
15142 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15143 *
15144 * === Open and Closed Streams
15145 *
15146 * A new \IO stream may be open for reading, open for writing, or both.
15147 *
15148 * A stream is automatically closed when claimed by the garbage collector.
15149 *
15150 * Attempted reading or writing on a closed stream raises an exception.
15151 *
15152 * The relevant methods:
15153 *
15154 * - IO#close: Closes the stream for both reading and writing.
15155 * - IO#close_read: Closes the stream for reading.
15156 * - IO#close_write: Closes the stream for writing.
15157 * - IO#closed?: Returns whether the stream is closed.
15158 *
15159 * === End-of-Stream
15160 *
15161 * You can query whether a stream is positioned at its end:
15162 *
15163 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15164 *
15165 * You can reposition to end-of-stream by using method IO#seek:
15166 *
15167 * f = File.new('t.txt')
15168 * f.eof? # => false
15169 * f.seek(0, :END)
15170 * f.eof? # => true
15171 * f.close
15172 *
15173 * Or by reading all stream content (which is slower than using IO#seek):
15174 *
15175 * f.rewind
15176 * f.eof? # => false
15177 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15178 * f.eof? # => true
15179 *
15180 * == Line \IO
15181 *
15182 * Class \IO supports line-oriented
15183 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15184 *
15185 * === Line Input
15186 *
15187 * Class \IO supports line-oriented input for
15188 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15189 *
15190 * ==== \File Line Input
15191 *
15192 * You can read lines from a file using these methods:
15193 *
15194 * - IO.foreach: Reads each line and passes it to the given block.
15195 * - IO.readlines: Reads and returns all lines in an array.
15196 *
15197 * For each of these methods:
15198 *
15199 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15200 * - Line parsing depends on the effective <i>line separator</i>;
15201 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15202 * - The length of each returned line depends on the effective <i>line limit</i>;
15203 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15204 *
15205 * ==== Stream Line Input
15206 *
15207 * You can read lines from an \IO stream using these methods:
15208 *
15209 * - IO#each_line: Reads each remaining line, passing it to the given block.
15210 * - IO#gets: Returns the next line.
15211 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15212 * - IO#readlines: Returns all remaining lines in an array.
15213 *
15214 * For each of these methods:
15215 *
15216 * - Reading may begin mid-line,
15217 * depending on the stream's _position_;
15218 * see {Position}[rdoc-ref:IO@Position].
15219 * - Line parsing depends on the effective <i>line separator</i>;
15220 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15221 * - The length of each returned line depends on the effective <i>line limit</i>;
15222 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15223 *
15224 * ===== Line Separator
15225 *
15226 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15227 * the string that determines what is considered a line;
15228 * it is sometimes called the <i>input record separator</i>.
15229 *
15230 * The default line separator is taken from global variable <tt>$/</tt>,
15231 * whose initial value is <tt>"\n"</tt>.
15232 *
15233 * Generally, the line to be read next is all data
15234 * from the current {position}[rdoc-ref:IO@Position]
15235 * to the next line separator
15236 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15237 *
15238 * f = File.new('t.txt')
15239 * # Method gets with no sep argument returns the next line, according to $/.
15240 * f.gets # => "First line\n"
15241 * f.gets # => "Second line\n"
15242 * f.gets # => "\n"
15243 * f.gets # => "Fourth line\n"
15244 * f.gets # => "Fifth line\n"
15245 * f.close
15246 *
15247 * You can use a different line separator by passing argument +sep+:
15248 *
15249 * f = File.new('t.txt')
15250 * f.gets('l') # => "First l"
15251 * f.gets('li') # => "ine\nSecond li"
15252 * f.gets('lin') # => "ne\n\nFourth lin"
15253 * f.gets # => "e\n"
15254 * f.close
15255 *
15256 * Or by setting global variable <tt>$/</tt>:
15257 *
15258 * f = File.new('t.txt')
15259 * $/ = 'l'
15260 * f.gets # => "First l"
15261 * f.gets # => "ine\nSecond l"
15262 * f.gets # => "ine\n\nFourth l"
15263 * f.close
15264 *
15265 * ===== Special Line Separator Values
15266 *
15267 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15268 * accepts two special values for parameter +sep+:
15269 *
15270 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15271 *
15272 * f = File.new('t.txt')
15273 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15274 * f.close
15275 *
15276 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15277 * (paragraphs being separated by two consecutive line separators):
15278 *
15279 * f = File.new('t.txt')
15280 * f.gets('') # => "First line\nSecond line\n\n"
15281 * f.gets('') # => "Fourth line\nFifth line\n"
15282 * f.close
15283 *
15284 * ===== Line Limit
15285 *
15286 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15287 * uses an integer <i>line limit</i>,
15288 * which restricts the number of bytes that may be returned.
15289 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15290 * than the limit).
15291 *
15292 * The default limit value is <tt>-1</tt>;
15293 * any negative limit value means that there is no limit.
15294 *
15295 * If there is no limit, the line is determined only by +sep+.
15296 *
15297 * # Text with 1-byte characters.
15298 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15299 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15300 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15301 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15302 * # No more than one line.
15303 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15304 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15305 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15306 *
15307 * # Text with 2-byte characters, which will not be split.
15308 * File.open('t.rus') {|f| f.gets(1).size } # => 1
15309 * File.open('t.rus') {|f| f.gets(2).size } # => 1
15310 * File.open('t.rus') {|f| f.gets(3).size } # => 2
15311 * File.open('t.rus') {|f| f.gets(4).size } # => 2
15312 *
15313 * ===== Line Separator and Line Limit
15314 *
15315 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15316 *
15317 * - Returns the next line as determined by line separator +sep+.
15318 * - But returns no more bytes than are allowed by the limit +limit+.
15319 *
15320 * Example:
15321 *
15322 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15323 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15324 *
15325 * ===== Line Number
15326 *
15327 * A readable \IO stream has a non-negative integer <i>line number</i>:
15328 *
15329 * - IO#lineno: Returns the line number.
15330 * - IO#lineno=: Resets and returns the line number.
15331 *
15332 * Unless modified by a call to method IO#lineno=,
15333 * the line number is the number of lines read
15334 * by certain line-oriented methods,
15335 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15336 *
15337 * - IO.foreach: Increments the line number on each call to the block.
15338 * - IO#each_line: Increments the line number on each call to the block.
15339 * - IO#gets: Increments the line number.
15340 * - IO#readline: Increments the line number.
15341 * - IO#readlines: Increments the line number for each line read.
15342 *
15343 * A new stream is initially has line number zero (and position zero);
15344 * method +rewind+ resets the line number (and position) to zero:
15345 *
15346 * f = File.new('t.txt')
15347 * f.lineno # => 0
15348 * f.gets # => "First line\n"
15349 * f.lineno # => 1
15350 * f.rewind
15351 * f.lineno # => 0
15352 * f.close
15353 *
15354 * Reading lines from a stream usually changes its line number:
15355 *
15356 * f = File.new('t.txt', 'r')
15357 * f.lineno # => 0
15358 * f.readline # => "This is line one.\n"
15359 * f.lineno # => 1
15360 * f.readline # => "This is the second line.\n"
15361 * f.lineno # => 2
15362 * f.readline # => "Here's the third line.\n"
15363 * f.lineno # => 3
15364 * f.eof? # => true
15365 * f.close
15366 *
15367 * Iterating over lines in a stream usually changes its line number:
15368 *
15369 * File.open('t.txt') do |f|
15370 * f.each_line do |line|
15371 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15372 * end
15373 * end
15374 *
15375 * Output:
15376 *
15377 * "position=11 eof?=false lineno=1"
15378 * "position=23 eof?=false lineno=2"
15379 * "position=24 eof?=false lineno=3"
15380 * "position=36 eof?=false lineno=4"
15381 * "position=47 eof?=true lineno=5"
15382 *
15383 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15384 * the line number does not affect where the next read or write will occur:
15385 *
15386 * f = File.new('t.txt')
15387 * f.lineno = 1000
15388 * f.lineno # => 1000
15389 * f.gets # => "First line\n"
15390 * f.lineno # => 1001
15391 * f.close
15392 *
15393 * Associated with the line number is the global variable <tt>$.</tt>:
15394 *
15395 * - When a stream is opened, <tt>$.</tt> is not set;
15396 * its value is left over from previous activity in the process:
15397 *
15398 * $. = 41
15399 * f = File.new('t.txt')
15400 * $. = 41
15401 * # => 41
15402 * f.close
15403 *
15404 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15405 *
15406 * f0 = File.new('t.txt')
15407 * f1 = File.new('t.dat')
15408 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15409 * $. # => 5
15410 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15411 * $. # => 1
15412 * f0.close
15413 * f1.close
15414 *
15415 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15416 *
15417 * f = File.new('t.txt')
15418 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15419 * $. # => 5
15420 * f.rewind
15421 * f.seek(0, :SET)
15422 * $. # => 5
15423 * f.close
15424 *
15425 * === Line Output
15426 *
15427 * You can write to an \IO stream line-by-line using this method:
15428 *
15429 * - IO#puts: Writes objects to the stream.
15430 *
15431 * == Character \IO
15432 *
15433 * You can process an \IO stream character-by-character using these methods:
15434 *
15435 * - IO#getc: Reads and returns the next character from the stream.
15436 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15437 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15438 * - IO#putc: Writes a character to the stream.
15439 * - IO#each_char: Reads each remaining character in the stream,
15440 * passing the character to the given block.
15441 *
15442 * == Byte \IO
15443 *
15444 * You can process an \IO stream byte-by-byte using these methods:
15445 *
15446 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15447 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15448 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15449 * - IO#each_byte: Reads each remaining byte in the stream,
15450 * passing the byte to the given block.
15451 *
15452 * == Codepoint \IO
15453 *
15454 * You can process an \IO stream codepoint-by-codepoint:
15455 *
15456 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15457 *
15458 * == What's Here
15459 *
15460 * First, what's elsewhere. Class \IO:
15461 *
15462 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15463 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15464 * which provides dozens of additional methods.
15465 *
15466 * Here, class \IO provides methods that are useful for:
15467 *
15468 * - {Creating}[rdoc-ref:IO@Creating]
15469 * - {Reading}[rdoc-ref:IO@Reading]
15470 * - {Writing}[rdoc-ref:IO@Writing]
15471 * - {Positioning}[rdoc-ref:IO@Positioning]
15472 * - {Iterating}[rdoc-ref:IO@Iterating]
15473 * - {Settings}[rdoc-ref:IO@Settings]
15474 * - {Querying}[rdoc-ref:IO@Querying]
15475 * - {Buffering}[rdoc-ref:IO@Buffering]
15476 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15477 * - {Other}[rdoc-ref:IO@Other]
15478 *
15479 * === Creating
15480 *
15481 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15482 * integer file descriptor.
15483 * - ::open: Creates a new \IO object.
15484 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15485 * - ::popen: Creates an \IO object to interact with a subprocess.
15486 * - ::select: Selects which given \IO instances are ready for reading,
15487 * writing, or have pending exceptions.
15488 *
15489 * === Reading
15490 *
15491 * - ::binread: Returns a binary string with all or a subset of bytes
15492 * from the given file.
15493 * - ::read: Returns a string with all or a subset of bytes from the given file.
15494 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15495 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15496 * - #getc: Returns the next character read from +self+ as a string.
15497 * - #gets: Returns the line read from +self+.
15498 * - #pread: Returns all or the next _n_ bytes read from +self+,
15499 * not updating the receiver's offset.
15500 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15501 * for a given _n_.
15502 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15503 * in non-block mode.
15504 * - #readbyte: Returns the next byte read from +self+;
15505 * same as #getbyte, but raises an exception on end-of-stream.
15506 * - #readchar: Returns the next character read from +self+;
15507 * same as #getc, but raises an exception on end-of-stream.
15508 * - #readline: Returns the next line read from +self+;
15509 * same as #getline, but raises an exception of end-of-stream.
15510 * - #readlines: Returns an array of all lines read read from +self+.
15511 * - #readpartial: Returns up to the given number of bytes from +self+.
15512 *
15513 * === Writing
15514 *
15515 * - ::binwrite: Writes the given string to the file at the given filepath,
15516 * in binary mode.
15517 * - ::write: Writes the given string to +self+.
15518 * - #<<: Appends the given string to +self+.
15519 * - #print: Prints last read line or given objects to +self+.
15520 * - #printf: Writes to +self+ based on the given format string and objects.
15521 * - #putc: Writes a character to +self+.
15522 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15523 * - #pwrite: Writes the given string at the given offset,
15524 * not updating the receiver's offset.
15525 * - #write: Writes one or more given strings to +self+.
15526 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15527 *
15528 * === Positioning
15529 *
15530 * - #lineno: Returns the current line number in +self+.
15531 * - #lineno=: Sets the line number is +self+.
15532 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15533 * - #pos=: Sets the byte offset in +self+.
15534 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15535 * - #rewind: Positions +self+ to the beginning of input.
15536 * - #seek: Sets the offset for +self+ relative to given position.
15537 *
15538 * === Iterating
15539 *
15540 * - ::foreach: Yields each line of given file to the block.
15541 * - #each (aliased as #each_line): Calls the given block
15542 * with each successive line in +self+.
15543 * - #each_byte: Calls the given block with each successive byte in +self+
15544 * as an integer.
15545 * - #each_char: Calls the given block with each successive character in +self+
15546 * as a string.
15547 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15548 * as an integer.
15549 *
15550 * === Settings
15551 *
15552 * - #autoclose=: Sets whether +self+ auto-closes.
15553 * - #binmode: Sets +self+ to binary mode.
15554 * - #close: Closes +self+.
15555 * - #close_on_exec=: Sets the close-on-exec flag.
15556 * - #close_read: Closes +self+ for reading.
15557 * - #close_write: Closes +self+ for writing.
15558 * - #set_encoding: Sets the encoding for +self+.
15559 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15560 * Unicode byte-order-mark.
15561 * - #sync=: Sets the sync-mode to the given value.
15562 *
15563 * === Querying
15564 *
15565 * - #autoclose?: Returns whether +self+ auto-closes.
15566 * - #binmode?: Returns whether +self+ is in binary mode.
15567 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15568 * - #closed?: Returns whether +self+ is closed.
15569 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15570 * - #external_encoding: Returns the external encoding object for +self+.
15571 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15572 * - #internal_encoding: Returns the internal encoding object for +self+.
15573 * - #pid: Returns the process ID of a child process associated with +self+,
15574 * if +self+ was created by ::popen.
15575 * - #stat: Returns the File::Stat object containing status information for +self+.
15576 * - #sync: Returns whether +self+ is in sync-mode.
15577 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15578 *
15579 * === Buffering
15580 *
15581 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15582 * - #flush: Flushes any buffered data within +self+ to the underlying
15583 * operating system.
15584 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15585 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15586 * - #ungetc: Prepends buffer for +self+ with given string.
15587 *
15588 * === Low-Level Access
15589 *
15590 * - ::sysopen: Opens the file given by its path,
15591 * returning the integer file descriptor.
15592 * - #advise: Announces the intention to access data from +self+ in a specific way.
15593 * - #fcntl: Passes a low-level command to the file specified
15594 * by the given file descriptor.
15595 * - #ioctl: Passes a low-level command to the device specified
15596 * by the given file descriptor.
15597 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15598 * - #sysseek: Sets the offset for +self+.
15599 * - #syswrite: Writes the given string to +self+ using a low-level write.
15600 *
15601 * === Other
15602 *
15603 * - ::copy_stream: Copies data from a source to a destination,
15604 * each of which is a filepath or an \IO-like object.
15605 * - ::try_convert: Returns a new \IO object resulting from converting
15606 * the given object.
15607 * - #inspect: Returns the string representation of +self+.
15608 *
15609 */
15610
15611void
15612Init_IO(void)
15613{
15614 VALUE rb_cARGF;
15615#ifdef __CYGWIN__
15616#include <sys/cygwin.h>
15617 static struct __cygwin_perfile pf[] =
15618 {
15619 {"", O_RDONLY | O_BINARY},
15620 {"", O_WRONLY | O_BINARY},
15621 {"", O_RDWR | O_BINARY},
15622 {"", O_APPEND | O_BINARY},
15623 {NULL, 0}
15624 };
15625 cygwin_internal(CW_PERFILE, pf);
15626#endif
15627
15630
15631 id_write = rb_intern_const("write");
15632 id_read = rb_intern_const("read");
15633 id_getc = rb_intern_const("getc");
15634 id_flush = rb_intern_const("flush");
15635 id_readpartial = rb_intern_const("readpartial");
15636 id_set_encoding = rb_intern_const("set_encoding");
15637 id_fileno = rb_intern_const("fileno");
15638
15639 rb_define_global_function("syscall", rb_f_syscall, -1);
15640
15641 rb_define_global_function("open", rb_f_open, -1);
15642 rb_define_global_function("printf", rb_f_printf, -1);
15643 rb_define_global_function("print", rb_f_print, -1);
15644 rb_define_global_function("putc", rb_f_putc, 1);
15645 rb_define_global_function("puts", rb_f_puts, -1);
15646 rb_define_global_function("gets", rb_f_gets, -1);
15647 rb_define_global_function("readline", rb_f_readline, -1);
15648 rb_define_global_function("select", rb_f_select, -1);
15649
15650 rb_define_global_function("readlines", rb_f_readlines, -1);
15651
15652 rb_define_global_function("`", rb_f_backquote, 1);
15653
15654 rb_define_global_function("p", rb_f_p, -1);
15655 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15656
15657 rb_cIO = rb_define_class("IO", rb_cObject);
15659
15660 /* Can be raised by IO operations when IO#timeout= is set. */
15662
15663 /* Readable event mask for IO#wait. */
15664 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15665 /* Writable event mask for IO#wait. */
15666 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15667 /* Priority event mask for IO#wait. */
15668 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15669
15670 /* exception to wait for reading. see IO.select. */
15672 /* exception to wait for writing. see IO.select. */
15674 /* exception to wait for reading by EAGAIN. see IO.select. */
15675 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15676 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15677 /* exception to wait for writing by EAGAIN. see IO.select. */
15678 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15679 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15680#if EAGAIN == EWOULDBLOCK
15681 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15682 /* same as IO::EAGAINWaitReadable */
15683 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15684 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15685 /* same as IO::EAGAINWaitWritable */
15686 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15687#else
15688 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15689 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15690 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15691 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15692 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15693 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15694#endif
15695 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15696 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15697 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15698 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15699 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15700 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15701
15702#if 0
15703 /* This is necessary only for forcing rdoc handle File::open */
15704 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15705#endif
15706
15707 rb_define_alloc_func(rb_cIO, io_alloc);
15708 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15709 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15710 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15711 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15712 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15713 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15714 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15715 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15716 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15717 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15718 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15719 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15720 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15721 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15722 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15723
15724 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15725
15727 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
15728
15729 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15730 rb_vm_register_global_object(rb_default_rs);
15731 rb_rs = rb_default_rs;
15733 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15734 rb_gvar_ractor_local("$/"); // not local but ractor safe
15735 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15736 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15737 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
15738
15739 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15740 rb_gvar_ractor_local("$_");
15741 rb_gvar_box_dynamic("$_");
15742
15743 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15744 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15745
15746 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15747 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15748 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15749 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15750
15751 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15752 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15753 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15754 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15755 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15756
15757 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15758 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15759
15760 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15761 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15762
15763 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15764 rb_define_alias(rb_cIO, "to_i", "fileno");
15765 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15766
15767 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15768 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15769
15770 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15771 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15772 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15773 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15774
15775 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15776 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15777
15778 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15779
15780 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15781 rb_define_method(rb_cIO, "read", io_read, -1);
15782 rb_define_method(rb_cIO, "write", io_write_m, -1);
15783 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15784 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15785 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15786 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15787 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15788 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15789 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15791 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15792 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15793 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15794 /* Set I/O position from the beginning */
15795 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15796 /* Set I/O position from the current position */
15797 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15798 /* Set I/O position from the end */
15799 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15800#ifdef SEEK_DATA
15801 /* Set I/O position to the next location containing data */
15802 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15803#endif
15804#ifdef SEEK_HOLE
15805 /* Set I/O position to the next hole */
15806 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15807#endif
15808 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15809 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15810 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15811 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15812 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15813
15814 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15815 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15816
15817 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15818 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15819 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15820 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15821
15822 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15823 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15824 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15825 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15826 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15827 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15828
15829 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15830 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15831 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15832
15833 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15834 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15835
15836 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15837
15838 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15839 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15840 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15841 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15842
15843 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15844 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15845
15846 rb_define_method(rb_cIO, "wait", io_wait, -1);
15847
15848 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15849 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15850 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15851
15852 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15853 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15854 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15855 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15856
15857 rb_gvar_ractor_local("$stdin");
15858 rb_gvar_ractor_local("$stdout");
15859 rb_gvar_ractor_local("$>");
15860 rb_gvar_ractor_local("$stderr");
15861
15863 rb_stdin = rb_io_prep_stdin();
15865 rb_stdout = rb_io_prep_stdout();
15867 rb_stderr = rb_io_prep_stderr();
15868
15869 orig_stdout = rb_stdout;
15870 orig_stderr = rb_stderr;
15871
15872 /* Holds the original stdin */
15874 /* Holds the original stdout */
15876 /* Holds the original stderr */
15878
15879#if 0
15880 /* Hack to get rdoc to regard ARGF as a class: */
15881 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15882#endif
15883
15884 rb_cARGF = rb_class_new(rb_cObject);
15885 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15886 rb_define_alloc_func(rb_cARGF, argf_alloc);
15887
15889
15890 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15891 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15892 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15893 rb_define_alias(rb_cARGF, "inspect", "to_s");
15894 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15895
15896 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15897 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15898 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15899 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15900 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15901 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15902 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15903 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15904 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15905
15906 rb_define_method(rb_cARGF, "read", argf_read, -1);
15907 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15908 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15909 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15910 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15911 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15912 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15913 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15914 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15915 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15916 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15917 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15918 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15919 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15920 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15921 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15922 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15923 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15924 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15925 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15926
15927 rb_define_method(rb_cARGF, "write", argf_write, -1);
15928 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15929 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15930 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15931 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15932
15933 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15934 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15935 rb_define_method(rb_cARGF, "file", argf_file, 0);
15936 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15937 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15938 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15939
15940 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15941 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15942
15943 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15944 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15945
15946 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15947 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15948 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15949
15950 argf = rb_class_new_instance(0, 0, rb_cARGF);
15951
15953 /*
15954 * ARGF is a stream designed for use in scripts that process files given
15955 * as command-line arguments or passed in via STDIN.
15956 *
15957 * See ARGF (the class) for more details.
15958 */
15960
15961 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15962 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15963 ARGF.filename = rb_str_new2("-");
15964
15965 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15966 rb_gvar_ractor_local("$-i");
15967
15968 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15969
15970#if defined (_WIN32) || defined(__CYGWIN__)
15971 atexit(pipe_atexit);
15972#endif
15973
15974 Init_File();
15975
15976 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
15977
15978 sym_mode = ID2SYM(rb_intern_const("mode"));
15979 sym_perm = ID2SYM(rb_intern_const("perm"));
15980 sym_flags = ID2SYM(rb_intern_const("flags"));
15981 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
15982 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
15983 sym_encoding = ID2SYM(rb_id_encoding());
15984 sym_open_args = ID2SYM(rb_intern_const("open_args"));
15985 sym_textmode = ID2SYM(rb_intern_const("textmode"));
15986 sym_binmode = ID2SYM(rb_intern_const("binmode"));
15987 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
15988 sym_normal = ID2SYM(rb_intern_const("normal"));
15989 sym_sequential = ID2SYM(rb_intern_const("sequential"));
15990 sym_random = ID2SYM(rb_intern_const("random"));
15991 sym_willneed = ID2SYM(rb_intern_const("willneed"));
15992 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
15993 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
15994 sym_SET = ID2SYM(rb_intern_const("SET"));
15995 sym_CUR = ID2SYM(rb_intern_const("CUR"));
15996 sym_END = ID2SYM(rb_intern_const("END"));
15997#ifdef SEEK_DATA
15998 sym_DATA = ID2SYM(rb_intern_const("DATA"));
15999#endif
16000#ifdef SEEK_HOLE
16001 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16002#endif
16003 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16004 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16005}
16006
16007#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
#define STRNCASECMP
@old{st_locale_insensitive_strncasecmp}
Definition ctype.h:103
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:117
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1685
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1478
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:853
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1509
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1614
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2843
int rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt,...)
Identical to rb_scan_args(), except it also accepts kw_splat.
Definition class.c:3146
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
Definition class.c:3133
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1010
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2922
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1676
#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:1684
#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 ECONV_NEWLINE_DECORATOR_WRITE_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_WRITE_MASK.
Definition transcode.h:531
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:111
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:520
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:109
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:518
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition transcode.h:538
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:519
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define ECONV_NEWLINE_DECORATOR_READ_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_READ_MASK.
Definition transcode.h:530
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1678
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
void rb_notimplement(void)
Definition error.c:3840
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:476
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:508
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1441
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:653
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3909
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
Definition io.c:14685
VALUE rb_eIOError
IOError exception.
Definition io.c:189
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1428
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3999
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3915
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:475
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1431
VALUE rb_eEOFError
EOFError exception.
Definition io.c:188
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14679
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2286
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1429
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1451
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:60
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3312
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:675
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2208
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2249
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:2237
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
VALUE rb_stdin
STDIN constant.
Definition io.c:201
VALUE rb_stderr
STDERR constant.
Definition io.c:201
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:264
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:582
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:686
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:191
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:192
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1342
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
Definition object.c:3293
VALUE rb_cFile
File class.
Definition file.c:191
VALUE rb_stdout
STDOUT constant.
Definition io.c:201
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3306
rb_encoding * rb_ascii8bit_encoding(void)
Queries the encoding that represents ASCII-8BIT a.k.a.
Definition encoding.c:1523
rb_encoding * rb_default_internal_encoding(void)
Queries the "default internal" encoding.
Definition encoding.c:1743
int rb_utf8_encindex(void)
Identical to rb_utf8_encoding(), except it returns the encoding's index instead of the encoding itsel...
Definition encoding.c:1541
VALUE rb_enc_default_external(void)
Identical to rb_default_external_encoding(), except it returns the Ruby-level counterpart instance of...
Definition encoding.c:1670
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
Definition encoding.h:571
rb_encoding * rb_default_external_encoding(void)
Queries the "default external" encoding.
Definition encoding.c:1656
rb_encoding * rb_locale_encoding(void)
Queries the encoding that represents the current locale.
Definition encoding.c:1586
rb_encoding * rb_usascii_encoding(void)
Queries the encoding that represents US-ASCII.
Definition encoding.c:1547
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1342
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3932
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:831
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
Definition transcode.c:2660
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
Definition transcode.c:2123
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
Definition transcode.c:1485
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
Definition transcode.h:69
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
Definition transcode.h:41
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1780
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1824
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
Definition transcode.c:1959
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
Definition transcode.c:2711
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
Definition transcode.c:2022
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
Definition transcode.c:2974
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4340
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4346
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1741
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1791
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1117
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
Definition vm_eval.c:1084
void rb_gc(void)
Triggers a GC process.
Definition gc.c:4260
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:242
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
ID rb_frame_this_func(void)
Queries the name of the Ruby level method that is calling this function.
Definition eval.c:1193
VALUE rb_hash_new(void)
Creates a new, empty hash object.
Definition hash.c:1464
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8615
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4326
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:8748
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2382
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9177
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:5191
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5097
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:9358
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 $\\endiskip.
Definition io.c:206
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2724
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:9157
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:6406
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6360
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5255
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7408
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10436
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:7291
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:7298
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5773
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:2048
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:2042
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:3102
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:3799
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1499
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1682
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1533
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:1001
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1518
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1996
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3567
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4269
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3389
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:3741
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2952
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3252
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3371
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:2746
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1718
#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:1515
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:1850
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1482
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:1635
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
Definition thread.c:5583
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:1465
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:3193
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1629
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1488
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2949
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:441
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:2030
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:500
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3416
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:285
#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:4048
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:855
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:6492
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:6625
#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_io_oflags_fmode(int oflags)
Converts an oflags (that rb_io_modestr_oflags() returns) to a fmode (that rb_io_mode_flags() returns)...
Definition io.c:6549
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:1621
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:7108
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:6774
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2927
#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:9404
#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:1682
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:1641
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:190
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h: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:3001
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:6899
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:5693
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:5881
struct rb_io_internal_buffer rb_io_buffer_t
Just another name of rb_io_buffer_t.
Definition io.h:125
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:2047
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
int rb_io_read_pending(rb_io_t *fptr)
Queries if the passed IO has any pending reads.
Definition io.c:1060
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:823
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3447
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1577
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:9270
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:1697
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:796
void rb_eof_error(void)
Utility function to raise rb_eEOFError.
Definition io.c:775
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1542
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7395
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1482
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_stderr(void)
Queries the standard error of the current Ractor that is calling this function.
Definition ractor.c:1105
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:1081
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:1141
VALUE rb_ractor_stdout(void)
Queries the standard output of the current Ractor that is calling this function.
Definition ractor.c:1093
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:1129
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:1117
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:2062
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition sprintf.c:209
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
Definition vm_eval.c:1417
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1372
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition off_t.h:55
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:409
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:450
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:80
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:205
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:508
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14645
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9056
#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:471
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:1006
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:522
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:756
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:982
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:742
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
Definition scheduler.h:72
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:786
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:1018
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread value inst...
Definition scheduler.c:479
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:994
VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread)
Identical to rb_fiber_scheduler_current_for_thread(), except it expects a threadptr instead of a thre...
Definition scheduler.c:484
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:762
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
Definition scheduler.c:1038
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:4546
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
@ RUBY_Qfalse
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
C99 shim for <stdbool.h>.
Ruby's File and IO.
Definition rfile.h:35
Definition io.c:236
Definition win32.h:230
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