Ruby 4.0.0dev (2025-12-20 revision d9c0d4c71cd3500b2307c518b423ee58eeff9ae5)
io.c (d9c0d4c71cd3500b2307c518b423ee58eeff9ae5)
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17#include "ruby/io/buffer.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <stddef.h>
22
23/* non-Linux poll may not work on all FDs */
24#if defined(HAVE_POLL)
25# if defined(__linux__)
26# define USE_POLL 1
27# endif
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29# define USE_POLL 1
30# endif
31#endif
32
33#ifndef USE_POLL
34# define USE_POLL 0
35#endif
36
37#undef free
38#define free(x) xfree(x)
39
40#if defined(DOSISH) || defined(__CYGWIN__)
41#include <io.h>
42#endif
43
44#include <sys/types.h>
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
49#endif
50
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
53#endif
54
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
56# define USE_SETVBUF
57#endif
58
59#ifdef __QNXNTO__
60#include <unix.h>
61#endif
62
63#include <sys/types.h>
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
65#include <sys/ioctl.h>
66#endif
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
68#include <fcntl.h>
69#elif defined(HAVE_SYS_FCNTL_H)
70#include <sys/fcntl.h>
71#endif
72
73#ifdef HAVE_SYS_TIME_H
74# include <sys/time.h>
75#endif
76
77#include <sys/stat.h>
78
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
81#endif
82
83#if !defined NOFILE
84# define NOFILE 64
85#endif
86
87#ifdef HAVE_UNISTD_H
88#include <unistd.h>
89#endif
90
91#ifdef HAVE_SYSCALL_H
92#include <syscall.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
95#endif
96
97#ifdef HAVE_SYS_UIO_H
98#include <sys/uio.h>
99#endif
100
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h> /* for WNOHANG on BSD */
103#endif
104
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
107
108# ifndef COPYFILE_STATE_COPIED
109/*
110 * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
111 * COPYFILE_STATE_COPIED. Since the only use of the former here
112 * requires the latter, we disable the former when the latter is undefined.
113 */
114# undef HAVE_FCOPYFILE
115# endif
116
117#endif
118
120#include "ccan/list/list.h"
121#include "dln.h"
122#include "encindex.h"
123#include "id.h"
124#include "internal.h"
125#include "internal/class.h"
126#include "internal/encoding.h"
127#include "internal/error.h"
128#include "internal/inits.h"
129#include "internal/io.h"
130#include "internal/numeric.h"
131#include "internal/object.h"
132#include "internal/process.h"
133#include "internal/thread.h"
134#include "internal/transcode.h"
135#include "internal/variable.h"
136#include "ruby/io.h"
137#include "ruby/io/buffer.h"
138#include "ruby/missing.h"
139#include "ruby/thread.h"
140#include "ruby/util.h"
141#include "ruby_atomic.h"
142#include "ruby/ractor.h"
143
144#if !USE_POLL
145# include "vm_core.h"
146#endif
147
148#include "builtin.h"
149
150#ifndef O_ACCMODE
151#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
152#endif
153
154#ifndef PIPE_BUF
155# ifdef _POSIX_PIPE_BUF
156# define PIPE_BUF _POSIX_PIPE_BUF
157# else
158# define PIPE_BUF 512 /* is this ok? */
159# endif
160#endif
161
162#ifndef EWOULDBLOCK
163# define EWOULDBLOCK EAGAIN
164#endif
165
166#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
167/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
168off_t __syscall(quad_t number, ...);
169#endif
170
171#define IO_RBUF_CAPA_MIN 8192
172#define IO_CBUF_CAPA_MIN (128*1024)
173#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174#define IO_WBUF_CAPA_MIN 8192
175
176#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
177
178/* define system APIs */
179#ifdef _WIN32
180#undef open
181#define open rb_w32_uopen
182#undef rename
183#define rename(f, t) rb_w32_urename((f), (t))
184#include "win32/file.h"
185#endif
186
193
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196static VALUE rb_eEWOULDBLOCKWaitReadable;
197static VALUE rb_eEWOULDBLOCKWaitWritable;
198static VALUE rb_eEINPROGRESSWaitWritable;
199static VALUE rb_eEINPROGRESSWaitReadable;
200
202static VALUE orig_stdout, orig_stderr;
203
205VALUE rb_rs;
208
209static VALUE argf;
210
211static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
212static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
213static VALUE sym_textmode, sym_binmode, sym_autoclose;
214static VALUE sym_SET, sym_CUR, sym_END;
215static VALUE sym_wait_readable, sym_wait_writable;
216#ifdef SEEK_DATA
217static VALUE sym_DATA;
218#endif
219#ifdef SEEK_HOLE
220static VALUE sym_HOLE;
221#endif
222
223static VALUE prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path);
224
225VALUE
226rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
227{
228 return rb_thread_io_blocking_call(io, function, argument, events);
229}
230
231VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
232{
233 return rb_io_blocking_region_wait(io, function, argument, 0);
234}
235
236struct argf {
237 VALUE filename, current_file;
238 long last_lineno; /* $. */
239 long lineno;
240 VALUE argv;
241 VALUE inplace;
242 struct rb_io_encoding encs;
243 int8_t init_p, next_p, binmode;
244};
245
246static rb_atomic_t max_file_descriptor = NOFILE;
247void
249{
250 rb_atomic_t afd = (rb_atomic_t)fd;
251 rb_atomic_t max_fd = max_file_descriptor;
252 int err;
253
254 if (fd < 0 || afd <= max_fd)
255 return;
256
257#if defined(HAVE_FCNTL) && defined(F_GETFL)
258 err = fcntl(fd, F_GETFL) == -1;
259#else
260 {
261 struct stat buf;
262 err = fstat(fd, &buf) != 0;
263 }
264#endif
265 if (err && errno == EBADF) {
266 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
267 }
268
269 while (max_fd < afd) {
270 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
271 }
272}
273
274void
275rb_maygvl_fd_fix_cloexec(int fd)
276{
277 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
278#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
279 int flags, flags2, ret;
280 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
281 if (flags == -1) {
282 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
283 }
284 if (fd <= 2)
285 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
286 else
287 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
288 if (flags != flags2) {
289 ret = fcntl(fd, F_SETFD, flags2);
290 if (ret != 0) {
291 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
292 }
293 }
294#endif
295}
296
297void
299{
300 rb_maygvl_fd_fix_cloexec(fd);
302}
303
304/* this is only called once */
305static int
306rb_fix_detect_o_cloexec(int fd)
307{
308#if defined(O_CLOEXEC) && defined(F_GETFD)
309 int flags = fcntl(fd, F_GETFD);
310
311 if (flags == -1)
312 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
313
314 if (flags & FD_CLOEXEC)
315 return 1;
316#endif /* fall through if O_CLOEXEC does not work: */
317 rb_maygvl_fd_fix_cloexec(fd);
318 return 0;
319}
320
321static inline bool
322io_again_p(int e)
323{
324 return (e == EWOULDBLOCK) || (e == EAGAIN);
325}
326
327int
328rb_cloexec_open(const char *pathname, int flags, mode_t mode)
329{
330 int ret;
331 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
332
333 static const int retry_interval = 0;
334 static const int retry_max_count = 10000;
335
336 int retry_count = 0;
337
338#ifdef O_CLOEXEC
339 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
340 flags |= O_CLOEXEC;
341#elif defined O_NOINHERIT
342 flags |= O_NOINHERIT;
343#endif
344
345 while ((ret = open(pathname, flags, mode)) == -1) {
346 int e = errno;
347 if (!io_again_p(e)) break;
348 if (retry_count++ >= retry_max_count) break;
349
350 sleep(retry_interval);
351 }
352
353 if (ret < 0) return ret;
354 if (ret <= 2 || o_cloexec_state == 0) {
355 rb_maygvl_fd_fix_cloexec(ret);
356 }
357 else if (o_cloexec_state > 0) {
358 return ret;
359 }
360 else {
361 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
362 }
363 return ret;
364}
365
366int
368{
369 /* Don't allocate standard file descriptors: 0, 1, 2 */
370 return rb_cloexec_fcntl_dupfd(oldfd, 3);
371}
372
373int
374rb_cloexec_dup2(int oldfd, int newfd)
375{
376 int ret;
377
378 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
379 * rb_cloexec_dup2 succeeds as dup2. */
380 if (oldfd == newfd) {
381 ret = newfd;
382 }
383 else {
384#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
385 static int try_dup3 = 1;
386 if (2 < newfd && try_dup3) {
387 ret = dup3(oldfd, newfd, O_CLOEXEC);
388 if (ret != -1)
389 return ret;
390 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
391 if (errno == ENOSYS) {
392 try_dup3 = 0;
393 ret = dup2(oldfd, newfd);
394 }
395 }
396 else {
397 ret = dup2(oldfd, newfd);
398 }
399#else
400 ret = dup2(oldfd, newfd);
401#endif
402 if (ret < 0) return ret;
403 }
404 rb_maygvl_fd_fix_cloexec(ret);
405 return ret;
406}
407
408static int
409rb_fd_set_nonblock(int fd)
410{
411#ifdef _WIN32
412 return rb_w32_set_nonblock(fd);
413#elif defined(F_GETFL)
414 int oflags = fcntl(fd, F_GETFL);
415
416 if (oflags == -1)
417 return -1;
418 if (oflags & O_NONBLOCK)
419 return 0;
420 oflags |= O_NONBLOCK;
421 return fcntl(fd, F_SETFL, oflags);
422#endif
423 return 0;
424}
425
426int
427rb_cloexec_pipe(int descriptors[2])
428{
429#ifdef HAVE_PIPE2
430 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
431#else
432 int result = pipe(descriptors);
433#endif
434
435 if (result < 0)
436 return result;
437
438#ifdef __CYGWIN__
439 if (result == 0 && descriptors[1] == -1) {
440 close(descriptors[0]);
441 descriptors[0] = -1;
442 errno = ENFILE;
443 return -1;
444 }
445#endif
446
447#ifndef HAVE_PIPE2
448 rb_maygvl_fd_fix_cloexec(descriptors[0]);
449 rb_maygvl_fd_fix_cloexec(descriptors[1]);
450
451#ifndef _WIN32
452 rb_fd_set_nonblock(descriptors[0]);
453 rb_fd_set_nonblock(descriptors[1]);
454#endif
455#endif
456
457 return result;
458}
459
460int
461rb_cloexec_fcntl_dupfd(int fd, int minfd)
462{
463 int ret;
464
465#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
466 static int try_dupfd_cloexec = 1;
467 if (try_dupfd_cloexec) {
468 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
469 if (ret != -1) {
470 if (ret <= 2)
471 rb_maygvl_fd_fix_cloexec(ret);
472 return ret;
473 }
474 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
475 if (errno == EINVAL) {
476 ret = fcntl(fd, F_DUPFD, minfd);
477 if (ret != -1) {
478 try_dupfd_cloexec = 0;
479 }
480 }
481 }
482 else {
483 ret = fcntl(fd, F_DUPFD, minfd);
484 }
485#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
486 ret = fcntl(fd, F_DUPFD, minfd);
487#else
488 ret = dup(fd);
489 if (ret >= 0 && ret < minfd) {
490 const int prev_fd = ret;
491 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
492 close(prev_fd);
493 }
494 return ret;
495#endif
496 if (ret < 0) return ret;
497 rb_maygvl_fd_fix_cloexec(ret);
498 return ret;
499}
500
501#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
502#define ARGF argf_of(argf)
503
504#define GetWriteIO(io) rb_io_get_write_io(io)
505
506#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
507#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
508#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
509#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
510
511#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
512#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
513#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
514
515#if defined(_WIN32)
516#define WAIT_FD_IN_WIN32(fptr) \
517 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
518#else
519#define WAIT_FD_IN_WIN32(fptr)
520#endif
521
522#define READ_CHECK(fptr) do {\
523 if (!READ_DATA_PENDING(fptr)) {\
524 WAIT_FD_IN_WIN32(fptr);\
525 rb_io_check_closed(fptr);\
526 }\
527} while(0)
528
529#ifndef S_ISSOCK
530# ifdef _S_ISSOCK
531# define S_ISSOCK(m) _S_ISSOCK(m)
532# else
533# ifdef _S_IFSOCK
534# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
535# else
536# ifdef S_IFSOCK
537# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
538# endif
539# endif
540# endif
541#endif
542
543static int io_fflush(rb_io_t *);
544static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
545static void clear_codeconv(rb_io_t *fptr);
546
547#define FMODE_SIGNAL_ON_EPIPE (1<<17)
548
549#define fptr_signal_on_epipe(fptr) \
550 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
551
552#define fptr_set_signal_on_epipe(fptr, flag) \
553 ((flag) ? \
554 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
555 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
556
557extern ID ruby_static_id_signo;
558
559NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
560static void
561rb_sys_fail_on_write(rb_io_t *fptr)
562{
563 int e = errno;
564 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
565#if defined EPIPE
566 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
567 const VALUE sig =
568# if defined SIGPIPE
569 INT2FIX(SIGPIPE) - INT2FIX(0) +
570# endif
571 INT2FIX(0);
572 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
573 }
574#endif
575 rb_exc_raise(errinfo);
576}
577
578#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
579#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
580#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
581# define RUBY_CRLF_ENVIRONMENT 1
582#else
583# define RUBY_CRLF_ENVIRONMENT 0
584#endif
585
586#if RUBY_CRLF_ENVIRONMENT
587/* Windows */
588# define DEFAULT_TEXTMODE FMODE_TEXTMODE
589# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
590/*
591 * CRLF newline is set as default newline decorator.
592 * If only CRLF newline conversion is needed, we use binary IO process
593 * with OS's text mode for IO performance improvement.
594 * If encoding conversion is needed or a user sets text mode, we use encoding
595 * conversion IO process and universal newline decorator by default.
596 */
597#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
598#define WRITECONV_MASK ( \
599 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
600 ECONV_STATEFUL_DECORATOR_MASK|\
601 0)
602#define NEED_WRITECONV(fptr) ( \
603 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
604 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
605 0)
606#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
607
608#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
609 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
610 if (((fptr)->mode & FMODE_READABLE) &&\
611 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
612 setmode((fptr)->fd, O_BINARY);\
613 }\
614 else {\
615 setmode((fptr)->fd, O_TEXT);\
616 }\
617 }\
618} while(0)
619
620#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
621 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
622 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
623 }\
624} while(0)
625
626/*
627 * IO unread with taking care of removed '\r' in text mode.
628 */
629static void
630io_unread(rb_io_t *fptr, bool discard_rbuf)
631{
632 rb_off_t r, pos;
633 ssize_t read_size;
634 long i;
635 long newlines = 0;
636 long extra_max;
637 char *p;
638 char *buf;
639
640 rb_io_check_closed(fptr);
641 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
642 return;
643 }
644
645 errno = 0;
646 if (!rb_w32_fd_is_text(fptr->fd)) {
647 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
648 if (r < 0 && errno) {
649 if (errno == ESPIPE)
650 fptr->mode |= FMODE_DUPLEX;
651 if (!discard_rbuf) return;
652 }
653
654 goto end;
655 }
656
657 pos = lseek(fptr->fd, 0, SEEK_CUR);
658 if (pos < 0 && errno) {
659 if (errno == ESPIPE)
660 fptr->mode |= FMODE_DUPLEX;
661 if (!discard_rbuf) goto end;
662 }
663
664 /* add extra offset for removed '\r' in rbuf */
665 extra_max = (long)(pos - fptr->rbuf.len);
666 p = fptr->rbuf.ptr + fptr->rbuf.off;
667
668 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
669 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
670 newlines++;
671 }
672
673 for (i = 0; i < fptr->rbuf.len; i++) {
674 if (*p == '\n') newlines++;
675 if (extra_max == newlines) break;
676 p++;
677 }
678
679 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
680 while (newlines >= 0) {
681 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
682 if (newlines == 0) break;
683 if (r < 0) {
684 newlines--;
685 continue;
686 }
687 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
688 if (read_size < 0) {
689 int e = errno;
690 free(buf);
691 rb_syserr_fail_path(e, fptr->pathv);
692 }
693 if (read_size == fptr->rbuf.len) {
694 lseek(fptr->fd, r, SEEK_SET);
695 break;
696 }
697 else {
698 newlines--;
699 }
700 }
701 free(buf);
702 end:
703 fptr->rbuf.off = 0;
704 fptr->rbuf.len = 0;
705 clear_codeconv(fptr);
706 return;
707}
708
709/*
710 * We use io_seek to back cursor position when changing mode from text to binary,
711 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
712 * conversion for working properly with mode change.
713 *
714 * Return previous translation mode.
715 */
716static inline int
717set_binary_mode_with_seek_cur(rb_io_t *fptr)
718{
719 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
720
721 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
722 return setmode(fptr->fd, O_BINARY);
723 }
724 flush_before_seek(fptr, false);
725 return setmode(fptr->fd, O_BINARY);
726}
727#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
728
729#else
730/* Unix */
731# define DEFAULT_TEXTMODE 0
732#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
733#define NEED_WRITECONV(fptr) ( \
734 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
735 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
736 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
737 0)
738#define SET_BINARY_MODE(fptr) (void)(fptr)
739#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
740#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
741#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
742#endif
743
744#if !defined HAVE_SHUTDOWN && !defined shutdown
745#define shutdown(a,b) 0
746#endif
747
748#if defined(_WIN32)
749#define is_socket(fd, path) rb_w32_is_socket(fd)
750#elif !defined(S_ISSOCK)
751#define is_socket(fd, path) 0
752#else
753static int
754is_socket(int fd, VALUE path)
755{
756 struct stat sbuf;
757 if (fstat(fd, &sbuf) < 0)
758 rb_sys_fail_path(path);
759 return S_ISSOCK(sbuf.st_mode);
760}
761#endif
762
763static const char closed_stream[] = "closed stream";
764
765static void
766io_fd_check_closed(int fd)
767{
768 if (fd < 0) {
769 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
770 rb_raise(rb_eIOError, closed_stream);
771 }
772}
773
774void
775rb_eof_error(void)
776{
777 rb_raise(rb_eEOFError, "end of file reached");
778}
779
780VALUE
782{
783 rb_check_frozen(io);
784 return io;
785}
786
787void
789{
790 if (!fptr) {
791 rb_raise(rb_eIOError, "uninitialized stream");
792 }
793}
794
795void
797{
799 io_fd_check_closed(fptr->fd);
800}
801
802static rb_io_t *
803rb_io_get_fptr(VALUE io)
804{
805 rb_io_t *fptr = RFILE(io)->fptr;
807 return fptr;
808}
809
810VALUE
812{
813 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
814}
815
816VALUE
818{
819 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
820}
821
822VALUE
824{
825 VALUE write_io;
826 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
827 if (write_io) {
828 return write_io;
829 }
830 return io;
831}
832
833VALUE
835{
836 VALUE write_io;
837 rb_io_t *fptr = rb_io_get_fptr(io);
838 if (!RTEST(w)) {
839 w = 0;
840 }
841 else {
842 GetWriteIO(w);
843 }
844 write_io = fptr->tied_io_for_writing;
845 fptr->tied_io_for_writing = w;
846 return write_io ? write_io : Qnil;
847}
848
849/*
850 * call-seq:
851 * timeout -> duration or nil
852 *
853 * Get the internal timeout duration or nil if it was not set.
854 *
855 */
856VALUE
858{
859 rb_io_t *fptr = rb_io_get_fptr(self);
860
861 return fptr->timeout;
862}
863
864/*
865 * call-seq:
866 * timeout = duration -> duration
867 * timeout = nil -> nil
868 *
869 * Sets the internal timeout to the specified duration or nil. The timeout
870 * applies to all blocking operations where possible.
871 *
872 * When the operation performs longer than the timeout set, IO::TimeoutError
873 * is raised.
874 *
875 * This affects the following methods (but is not limited to): #gets, #puts,
876 * #read, #write, #wait_readable and #wait_writable. This also affects
877 * blocking socket operations like Socket#accept and Socket#connect.
878 *
879 * Some operations like File#open and IO#close are not affected by the
880 * timeout. A timeout during a write operation may leave the IO in an
881 * inconsistent state, e.g. data was partially written. Generally speaking, a
882 * timeout is a last ditch effort to prevent an application from hanging on
883 * slow I/O operations, such as those that occur during a slowloris attack.
884 */
885VALUE
887{
888 // Validate it:
889 if (RTEST(timeout)) {
890 rb_time_interval(timeout);
891 }
892
893 rb_io_t *fptr = rb_io_get_fptr(self);
894
895 fptr->timeout = timeout;
896
897 return self;
898}
899
900/*
901 * call-seq:
902 * IO.try_convert(object) -> new_io or nil
903 *
904 * Attempts to convert +object+ into an \IO object via method +to_io+;
905 * returns the new \IO object if successful, or +nil+ otherwise:
906 *
907 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
908 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
909 * IO.try_convert('STDOUT') # => nil
910 *
911 */
912static VALUE
913rb_io_s_try_convert(VALUE dummy, VALUE io)
914{
915 return rb_io_check_io(io);
916}
917
918#if !RUBY_CRLF_ENVIRONMENT
919static void
920io_unread(rb_io_t *fptr, bool discard_rbuf)
921{
922 rb_off_t r;
923 rb_io_check_closed(fptr);
924 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
925 return;
926 /* xxx: target position may be negative if buffer is filled by ungetc */
927 errno = 0;
928 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
929 if (r < 0 && errno) {
930 if (errno == ESPIPE)
931 fptr->mode |= FMODE_DUPLEX;
932 if (!discard_rbuf) return;
933 }
934 fptr->rbuf.off = 0;
935 fptr->rbuf.len = 0;
936 clear_codeconv(fptr);
937 return;
938}
939#endif
940
941static rb_encoding *io_input_encoding(rb_io_t *fptr);
942
943static void
944io_ungetbyte(VALUE str, rb_io_t *fptr)
945{
946 long len = RSTRING_LEN(str);
947
948 if (fptr->rbuf.ptr == NULL) {
949 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
950 fptr->rbuf.off = 0;
951 fptr->rbuf.len = 0;
952#if SIZEOF_LONG > SIZEOF_INT
953 if (len > INT_MAX)
954 rb_raise(rb_eIOError, "ungetbyte failed");
955#endif
956 if (len > min_capa)
957 fptr->rbuf.capa = (int)len;
958 else
959 fptr->rbuf.capa = min_capa;
960 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
961 }
962 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
963 rb_raise(rb_eIOError, "ungetbyte failed");
964 }
965 if (fptr->rbuf.off < len) {
966 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
967 fptr->rbuf.ptr+fptr->rbuf.off,
968 char, fptr->rbuf.len);
969 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
970 }
971 fptr->rbuf.off-=(int)len;
972 fptr->rbuf.len+=(int)len;
973 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
974}
975
976static rb_io_t *
977flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
978{
979 if (io_fflush(fptr) < 0)
980 rb_sys_fail_on_write(fptr);
981 io_unread(fptr, discard_rbuf);
982 errno = 0;
983 return fptr;
984}
985
986#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
987#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
988
989#ifndef SEEK_CUR
990# define SEEK_SET 0
991# define SEEK_CUR 1
992# define SEEK_END 2
993#endif
994
995void
997{
998 rb_io_check_closed(fptr);
999 if (!(fptr->mode & FMODE_READABLE)) {
1000 rb_raise(rb_eIOError, "not opened for reading");
1001 }
1002 if (fptr->wbuf.len) {
1003 if (io_fflush(fptr) < 0)
1004 rb_sys_fail_on_write(fptr);
1005 }
1006 if (fptr->tied_io_for_writing) {
1007 rb_io_t *wfptr;
1008 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1009 if (io_fflush(wfptr) < 0)
1010 rb_sys_fail_on_write(wfptr);
1011 }
1012}
1013
1014void
1016{
1018 if (READ_CHAR_PENDING(fptr)) {
1019 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1020 }
1021}
1022
1023void
1028
1029static rb_encoding*
1030io_read_encoding(rb_io_t *fptr)
1031{
1032 if (fptr->encs.enc) {
1033 return fptr->encs.enc;
1034 }
1035 return rb_default_external_encoding();
1036}
1037
1038static rb_encoding*
1039io_input_encoding(rb_io_t *fptr)
1040{
1041 if (fptr->encs.enc2) {
1042 return fptr->encs.enc2;
1043 }
1044 return io_read_encoding(fptr);
1045}
1046
1047void
1049{
1050 rb_io_check_closed(fptr);
1051 if (!(fptr->mode & FMODE_WRITABLE)) {
1052 rb_raise(rb_eIOError, "not opened for writing");
1053 }
1054 if (fptr->rbuf.len) {
1055 io_unread(fptr, true);
1056 }
1057}
1058
1059int
1060rb_io_read_pending(rb_io_t *fptr)
1061{
1062 /* This function is used for bytes and chars. Confusing. */
1063 if (READ_CHAR_PENDING(fptr))
1064 return 1; /* should raise? */
1065 return READ_DATA_PENDING(fptr);
1066}
1067
1068void
1070{
1071 if (!READ_DATA_PENDING(fptr)) {
1072 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1073 }
1074 return;
1075}
1076
1077int
1078rb_gc_for_fd(int err)
1079{
1080 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1081 rb_gc();
1082 return 1;
1083 }
1084 return 0;
1085}
1086
1087/* try `expr` upto twice while it returns false and `errno`
1088 * is to GC. Each `errno`s are available as `first_errno` and
1089 * `retried_errno` respectively */
1090#define TRY_WITH_GC(expr) \
1091 for (int first_errno, retried_errno = 0, retried = 0; \
1092 (!retried && \
1093 !(expr) && \
1094 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1095 (retried_errno = errno, 1)); \
1096 (void)retried_errno, retried = 1)
1097
1098static int
1099ruby_dup(int orig)
1100{
1101 int fd = -1;
1102
1103 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1104 rb_syserr_fail(first_errno, 0);
1105 }
1106 rb_update_max_fd(fd);
1107 return fd;
1108}
1109
1110static VALUE
1111io_alloc(VALUE klass)
1112{
1113 NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
1114
1115 io->fptr = 0;
1116
1117 return (VALUE)io;
1118}
1119
1120#ifndef S_ISREG
1121# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1122#endif
1123
1125 VALUE th;
1126 rb_io_t *fptr;
1127 int nonblock;
1128 int fd;
1129
1130 void *buf;
1131 size_t capa;
1132 struct timeval *timeout;
1133};
1134
1136 VALUE th;
1137 rb_io_t *fptr;
1138 int nonblock;
1139 int fd;
1140
1141 const void *buf;
1142 size_t capa;
1143 struct timeval *timeout;
1144};
1145
1146#ifdef HAVE_WRITEV
1147struct io_internal_writev_struct {
1148 VALUE th;
1149 rb_io_t *fptr;
1150 int nonblock;
1151 int fd;
1152
1153 int iovcnt;
1154 const struct iovec *iov;
1155 struct timeval *timeout;
1156};
1157#endif
1158
1159static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1160
1166static inline int
1167io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1168{
1169 if (!timeout && rb_thread_mn_schedulable(thread)) {
1170 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1171 return -1;
1172 }
1173
1174 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1175
1176 if (ready > 0) {
1177 return ready;
1178 }
1179 else if (ready == 0) {
1180 errno = ETIMEDOUT;
1181 return -1;
1182 }
1183
1184 // If there was an error BEFORE we started waiting, return it:
1185 if (error) {
1186 errno = error;
1187 return -1;
1188 }
1189 else {
1190 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1191 return ready;
1192 }
1193}
1194
1195static VALUE
1196internal_read_func(void *ptr)
1197{
1198 struct io_internal_read_struct *iis = ptr;
1199 ssize_t result;
1200
1201 if (iis->timeout && !iis->nonblock) {
1202 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1203 return -1;
1204 }
1205 }
1206
1207 retry:
1208 result = read(iis->fd, iis->buf, iis->capa);
1209
1210 if (result < 0 && !iis->nonblock) {
1211 if (io_again_p(errno)) {
1212 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1213 return -1;
1214 }
1215 else {
1216 goto retry;
1217 }
1218 }
1219 }
1220
1221 return result;
1222}
1223
1224#if defined __APPLE__
1225# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1226#else
1227# define do_write_retry(code) result = code
1228#endif
1229
1230static VALUE
1231internal_write_func(void *ptr)
1232{
1233 struct io_internal_write_struct *iis = ptr;
1234 ssize_t result;
1235
1236 if (iis->timeout && !iis->nonblock) {
1237 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1238 return -1;
1239 }
1240 }
1241
1242 retry:
1243 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1244
1245 if (result < 0 && !iis->nonblock) {
1246 int e = errno;
1247 if (io_again_p(e)) {
1248 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1249 return -1;
1250 }
1251 else {
1252 goto retry;
1253 }
1254 }
1255 }
1256
1257 return result;
1258}
1259
1260#ifdef HAVE_WRITEV
1261static VALUE
1262internal_writev_func(void *ptr)
1263{
1264 struct io_internal_writev_struct *iis = ptr;
1265 ssize_t result;
1266
1267 if (iis->timeout && !iis->nonblock) {
1268 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1269 return -1;
1270 }
1271 }
1272
1273 retry:
1274 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1275
1276 if (result < 0 && !iis->nonblock) {
1277 if (io_again_p(errno)) {
1278 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1279 return -1;
1280 }
1281 else {
1282 goto retry;
1283 }
1284 }
1285 }
1286
1287 return result;
1288}
1289#endif
1290
1291static ssize_t
1292rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1293{
1294 rb_thread_t *th = GET_THREAD();
1296 if (scheduler != Qnil) {
1297 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1298
1299 if (!UNDEF_P(result)) {
1301 }
1302 }
1303
1304 struct io_internal_read_struct iis = {
1305 .th = th->self,
1306 .fptr = fptr,
1307 .nonblock = 0,
1308 .fd = fptr->fd,
1309
1310 .buf = buf,
1311 .capa = count,
1312 .timeout = NULL,
1313 };
1314
1315 struct timeval timeout_storage;
1316
1317 if (fptr->timeout != Qnil) {
1318 timeout_storage = rb_time_interval(fptr->timeout);
1319 iis.timeout = &timeout_storage;
1320 }
1321
1322 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1323}
1324
1325static ssize_t
1326rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1327{
1328 rb_thread_t *th = GET_THREAD();
1330 if (scheduler != Qnil) {
1331 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1332
1333 if (!UNDEF_P(result)) {
1335 }
1336 }
1337
1338 struct io_internal_write_struct iis = {
1339 .th = th->self,
1340 .fptr = fptr,
1341 .nonblock = 0,
1342 .fd = fptr->fd,
1343
1344 .buf = buf,
1345 .capa = count,
1346 .timeout = NULL
1347 };
1348
1349 struct timeval timeout_storage;
1350
1351 if (fptr->timeout != Qnil) {
1352 timeout_storage = rb_time_interval(fptr->timeout);
1353 iis.timeout = &timeout_storage;
1354 }
1355
1356 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1357}
1358
1359#ifdef HAVE_WRITEV
1360static ssize_t
1361rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1362{
1363 if (!iovcnt) return 0;
1364
1365 rb_thread_t *th = GET_THREAD();
1366
1368 if (scheduler != Qnil) {
1369 // This path assumes at least one `iov`:
1370 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1371
1372 if (!UNDEF_P(result)) {
1374 }
1375 }
1376
1377 struct io_internal_writev_struct iis = {
1378 .th = th->self,
1379 .fptr = fptr,
1380 .nonblock = 0,
1381 .fd = fptr->fd,
1382
1383 .iov = iov,
1384 .iovcnt = iovcnt,
1385 .timeout = NULL
1386 };
1387
1388 struct timeval timeout_storage;
1389
1390 if (fptr->timeout != Qnil) {
1391 timeout_storage = rb_time_interval(fptr->timeout);
1392 iis.timeout = &timeout_storage;
1393 }
1394
1395 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1396}
1397#endif
1398
1399static VALUE
1400io_flush_buffer_sync(void *arg)
1401{
1402 rb_io_t *fptr = arg;
1403 long l = fptr->wbuf.len;
1404 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1405
1406 if (fptr->wbuf.len <= r) {
1407 fptr->wbuf.off = 0;
1408 fptr->wbuf.len = 0;
1409 return 0;
1410 }
1411
1412 if (0 <= r) {
1413 fptr->wbuf.off += (int)r;
1414 fptr->wbuf.len -= (int)r;
1415 errno = EAGAIN;
1416 }
1417
1418 return (VALUE)-1;
1419}
1420
1421static 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
1722 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
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 */
1746 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
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#ifdef _WIN32
2663 fptr->rbuf.capa--;
2664#endif
2665 }
2666 if (fptr->rbuf.len == 0) {
2667 retry:
2668 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2669
2670 if (r < 0) {
2671 if (fptr_wait_readable(fptr))
2672 goto retry;
2673
2674 int e = errno;
2675 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2676 if (!NIL_P(fptr->pathv)) {
2677 rb_str_append(path, fptr->pathv);
2678 }
2679
2680 rb_syserr_fail_path(e, path);
2681 }
2682 if (r > 0) rb_io_check_closed(fptr);
2683 fptr->rbuf.off = 0;
2684 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2685 if (r == 0)
2686 return -1; /* EOF */
2687 }
2688 return 0;
2689}
2690
2691/*
2692 * call-seq:
2693 * eof -> true or false
2694 *
2695 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2696 * see {Position}[rdoc-ref:IO@Position]:
2697 *
2698 * f = File.open('t.txt')
2699 * f.eof # => false
2700 * f.seek(0, :END) # => 0
2701 * f.eof # => true
2702 * f.close
2703 *
2704 * Raises an exception unless the stream is opened for reading;
2705 * see {Mode}[rdoc-ref:File@Access+Modes].
2706 *
2707 * If +self+ is a stream such as pipe or socket, this method
2708 * blocks until the other end sends some data or closes it:
2709 *
2710 * r, w = IO.pipe
2711 * Thread.new { sleep 1; w.close }
2712 * r.eof? # => true # After 1-second wait.
2713 *
2714 * r, w = IO.pipe
2715 * Thread.new { sleep 1; w.puts "a" }
2716 * r.eof? # => false # After 1-second wait.
2717 *
2718 * r, w = IO.pipe
2719 * r.eof? # blocks forever
2720 *
2721 * Note that this method reads data to the input byte buffer. So
2722 * IO#sysread may not behave as you intend with IO#eof?, unless you
2723 * call IO#rewind first (which is not available for some streams).
2724 */
2725
2726VALUE
2728{
2729 rb_io_t *fptr;
2730
2731 GetOpenFile(io, fptr);
2733
2734 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2735 if (READ_DATA_PENDING(fptr)) return Qfalse;
2736 READ_CHECK(fptr);
2737#if RUBY_CRLF_ENVIRONMENT
2738 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2739 return RBOOL(eof(fptr->fd));
2740 }
2741#endif
2742 return RBOOL(io_fillbuf(fptr) < 0);
2743}
2744
2745/*
2746 * call-seq:
2747 * sync -> true or false
2748 *
2749 * Returns the current sync mode of the stream.
2750 * When sync mode is true, all output is immediately flushed to the underlying
2751 * operating system and is not buffered by Ruby internally. See also #fsync.
2752 *
2753 * f = File.open('t.tmp', 'w')
2754 * f.sync # => false
2755 * f.sync = true
2756 * f.sync # => true
2757 * f.close
2758 *
2759 */
2760
2761static VALUE
2762rb_io_sync(VALUE io)
2763{
2764 rb_io_t *fptr;
2765
2766 io = GetWriteIO(io);
2767 GetOpenFile(io, fptr);
2768 return RBOOL(fptr->mode & FMODE_SYNC);
2769}
2770
2771#ifdef HAVE_FSYNC
2772
2773/*
2774 * call-seq:
2775 * sync = boolean -> boolean
2776 *
2777 * Sets the _sync_ _mode_ for the stream to the given value;
2778 * returns the given value.
2779 *
2780 * Values for the sync mode:
2781 *
2782 * - +true+: All output is immediately flushed to the
2783 * underlying operating system and is not buffered internally.
2784 * - +false+: Output may be buffered internally.
2785 *
2786 * Example;
2787 *
2788 * f = File.open('t.tmp', 'w')
2789 * f.sync # => false
2790 * f.sync = true
2791 * f.sync # => true
2792 * f.close
2793 *
2794 * Related: IO#fsync.
2795 *
2796 */
2797
2798static VALUE
2799rb_io_set_sync(VALUE io, VALUE sync)
2800{
2801 rb_io_t *fptr;
2802
2803 io = GetWriteIO(io);
2804 GetOpenFile(io, fptr);
2805 if (RTEST(sync)) {
2806 fptr->mode |= FMODE_SYNC;
2807 }
2808 else {
2809 fptr->mode &= ~FMODE_SYNC;
2810 }
2811 return sync;
2812}
2813
2814/*
2815 * call-seq:
2816 * fsync -> 0
2817 *
2818 * Immediately writes to disk all data buffered in the stream,
2819 * via the operating system's <tt>fsync(2)</tt>.
2820
2821 * Note this difference:
2822 *
2823 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2824 * but does not guarantee that the operating system actually writes the data to disk.
2825 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2826 * and that data is written to disk.
2827 *
2828 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2829 *
2830 */
2831
2832static VALUE
2833rb_io_fsync(VALUE io)
2834{
2835 rb_io_t *fptr;
2836
2837 io = GetWriteIO(io);
2838 GetOpenFile(io, fptr);
2839
2840 if (io_fflush(fptr) < 0)
2841 rb_sys_fail_on_write(fptr);
2842
2843 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2844 rb_sys_fail_path(fptr->pathv);
2845
2846 return INT2FIX(0);
2847}
2848#else
2849# define rb_io_fsync rb_f_notimplement
2850# define rb_io_sync rb_f_notimplement
2851static VALUE
2852rb_io_set_sync(VALUE io, VALUE sync)
2853{
2856}
2857#endif
2858
2859#ifdef HAVE_FDATASYNC
2860static VALUE
2861nogvl_fdatasync(void *ptr)
2862{
2863 rb_io_t *fptr = ptr;
2864
2865#ifdef _WIN32
2866 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2867 return 0;
2868#endif
2869 return (VALUE)fdatasync(fptr->fd);
2870}
2871
2872/*
2873 * call-seq:
2874 * fdatasync -> 0
2875 *
2876 * Immediately writes to disk all data buffered in the stream,
2877 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2878 * otherwise via <tt>fsync(2)</tt>, if supported;
2879 * otherwise raises an exception.
2880 *
2881 */
2882
2883static VALUE
2884rb_io_fdatasync(VALUE io)
2885{
2886 rb_io_t *fptr;
2887
2888 io = GetWriteIO(io);
2889 GetOpenFile(io, fptr);
2890
2891 if (io_fflush(fptr) < 0)
2892 rb_sys_fail_on_write(fptr);
2893
2894 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2895 return INT2FIX(0);
2896
2897 /* fall back */
2898 return rb_io_fsync(io);
2899}
2900#else
2901#define rb_io_fdatasync rb_io_fsync
2902#endif
2903
2904/*
2905 * call-seq:
2906 * fileno -> integer
2907 *
2908 * Returns the integer file descriptor for the stream:
2909 *
2910 * $stdin.fileno # => 0
2911 * $stdout.fileno # => 1
2912 * $stderr.fileno # => 2
2913 * File.open('t.txt').fileno # => 10
2914 * f.close
2915 *
2916 */
2917
2918static VALUE
2919rb_io_fileno(VALUE io)
2920{
2921 rb_io_t *fptr = RFILE(io)->fptr;
2922 int fd;
2923
2924 rb_io_check_closed(fptr);
2925 fd = fptr->fd;
2926 return INT2FIX(fd);
2927}
2928
2929int
2931{
2932 if (RB_TYPE_P(io, T_FILE)) {
2933 rb_io_t *fptr = RFILE(io)->fptr;
2934 rb_io_check_closed(fptr);
2935 return fptr->fd;
2936 }
2937 else {
2938 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2939 if (!UNDEF_P(fileno)) {
2940 return RB_NUM2INT(fileno);
2941 }
2942 }
2943
2944 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2945
2947}
2948
2949int
2950rb_io_mode(VALUE io)
2951{
2952 rb_io_t *fptr;
2953 GetOpenFile(io, fptr);
2954 return fptr->mode;
2955}
2956
2957/*
2958 * call-seq:
2959 * pid -> integer or nil
2960 *
2961 * Returns the process ID of a child process associated with the stream,
2962 * which will have been set by IO#popen, or +nil+ if the stream was not
2963 * created by IO#popen:
2964 *
2965 * pipe = IO.popen("-")
2966 * if pipe
2967 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2968 * else
2969 * $stderr.puts "In child, pid is #{$$}"
2970 * end
2971 *
2972 * Output:
2973 *
2974 * In child, pid is 26209
2975 * In parent, child pid is 26209
2976 *
2977 */
2978
2979static VALUE
2980rb_io_pid(VALUE io)
2981{
2982 rb_io_t *fptr;
2983
2984 GetOpenFile(io, fptr);
2985 if (!fptr->pid)
2986 return Qnil;
2987 return PIDT2NUM(fptr->pid);
2988}
2989
2990/*
2991 * call-seq:
2992 * path -> string or nil
2993 *
2994 * Returns the path associated with the IO, or +nil+ if there is no path
2995 * associated with the IO. It is not guaranteed that the path exists on
2996 * the filesystem.
2997 *
2998 * $stdin.path # => "<STDIN>"
2999 *
3000 * File.open("testfile") {|f| f.path} # => "testfile"
3001 */
3002
3003VALUE
3005{
3006 rb_io_t *fptr = RFILE(io)->fptr;
3007
3008 if (!fptr)
3009 return Qnil;
3010
3011 return rb_obj_dup(fptr->pathv);
3012}
3013
3014/*
3015 * call-seq:
3016 * inspect -> string
3017 *
3018 * Returns a string representation of +self+:
3019 *
3020 * f = File.open('t.txt')
3021 * f.inspect # => "#<File:t.txt>"
3022 * f.close
3023 *
3024 */
3025
3026static VALUE
3027rb_io_inspect(VALUE obj)
3028{
3029 rb_io_t *fptr;
3030 VALUE result;
3031 static const char closed[] = " (closed)";
3032
3033 fptr = RFILE(obj)->fptr;
3034 if (!fptr) return rb_any_to_s(obj);
3035 result = rb_str_new_cstr("#<");
3036 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3037 rb_str_cat2(result, ":");
3038 if (NIL_P(fptr->pathv)) {
3039 if (fptr->fd < 0) {
3040 rb_str_cat(result, closed+1, strlen(closed)-1);
3041 }
3042 else {
3043 rb_str_catf(result, "fd %d", fptr->fd);
3044 }
3045 }
3046 else {
3047 rb_str_append(result, fptr->pathv);
3048 if (fptr->fd < 0) {
3049 rb_str_cat(result, closed, strlen(closed));
3050 }
3051 }
3052 return rb_str_cat2(result, ">");
3053}
3054
3055/*
3056 * call-seq:
3057 * to_io -> self
3058 *
3059 * Returns +self+.
3060 *
3061 */
3062
3063static VALUE
3064rb_io_to_io(VALUE io)
3065{
3066 return io;
3067}
3068
3069/* reading functions */
3070static long
3071read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3072{
3073 int n;
3074
3075 n = READ_DATA_PENDING_COUNT(fptr);
3076 if (n <= 0) return 0;
3077 if (n > len) n = (int)len;
3078 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3079 fptr->rbuf.off += n;
3080 fptr->rbuf.len -= n;
3081 return n;
3082}
3083
3084static long
3085io_bufread(char *ptr, long len, rb_io_t *fptr)
3086{
3087 long offset = 0;
3088 long n = len;
3089 long c;
3090
3091 if (READ_DATA_PENDING(fptr) == 0) {
3092 while (n > 0) {
3093 again:
3094 rb_io_check_closed(fptr);
3095 c = rb_io_read_memory(fptr, ptr+offset, n);
3096 if (c == 0) break;
3097 if (c < 0) {
3098 if (fptr_wait_readable(fptr))
3099 goto again;
3100 return -1;
3101 }
3102 offset += c;
3103 if ((n -= c) <= 0) break;
3104 }
3105 return len - n;
3106 }
3107
3108 while (n > 0) {
3109 c = read_buffered_data(ptr+offset, n, fptr);
3110 if (c > 0) {
3111 offset += c;
3112 if ((n -= c) <= 0) break;
3113 }
3114 rb_io_check_closed(fptr);
3115 if (io_fillbuf(fptr) < 0) {
3116 break;
3117 }
3118 }
3119 return len - n;
3120}
3121
3122static int io_setstrbuf(VALUE *str, long len);
3123
3125 char *str_ptr;
3126 long len;
3127 rb_io_t *fptr;
3128};
3129
3130static VALUE
3131bufread_call(VALUE arg)
3132{
3133 struct bufread_arg *p = (struct bufread_arg *)arg;
3134 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3135 return Qundef;
3136}
3137
3138static long
3139io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3140{
3141 long len;
3142 struct bufread_arg arg;
3143
3144 io_setstrbuf(&str, offset + size);
3145 arg.str_ptr = RSTRING_PTR(str) + offset;
3146 arg.len = size;
3147 arg.fptr = fptr;
3148 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3149 len = arg.len;
3150 if (len < 0) rb_sys_fail_path(fptr->pathv);
3151 return len;
3152}
3153
3154static long
3155remain_size(rb_io_t *fptr)
3156{
3157 struct stat st;
3158 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3159 rb_off_t pos;
3160
3161 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3162#if defined(__HAIKU__)
3163 && (st.st_dev > 3)
3164#endif
3165 )
3166 {
3167 if (io_fflush(fptr) < 0)
3168 rb_sys_fail_on_write(fptr);
3169 pos = lseek(fptr->fd, 0, SEEK_CUR);
3170 if (st.st_size >= pos && pos >= 0) {
3171 siz += st.st_size - pos;
3172 if (siz > LONG_MAX) {
3173 rb_raise(rb_eIOError, "file too big for single read");
3174 }
3175 }
3176 }
3177 else {
3178 siz += BUFSIZ;
3179 }
3180 return (long)siz;
3181}
3182
3183static VALUE
3184io_enc_str(VALUE str, rb_io_t *fptr)
3185{
3186 rb_enc_associate(str, io_read_encoding(fptr));
3187 return str;
3188}
3189
3190static void
3191make_readconv(rb_io_t *fptr, int size)
3192{
3193 if (!fptr->readconv) {
3194 int ecflags;
3195 VALUE ecopts;
3196 const char *sname, *dname;
3197 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3198 ecopts = fptr->encs.ecopts;
3199 if (fptr->encs.enc2) {
3200 sname = rb_enc_name(fptr->encs.enc2);
3201 dname = rb_enc_name(io_read_encoding(fptr));
3202 }
3203 else {
3204 sname = dname = "";
3205 }
3206 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3207 if (!fptr->readconv)
3208 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3209 fptr->cbuf.off = 0;
3210 fptr->cbuf.len = 0;
3211 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3212 fptr->cbuf.capa = size;
3213 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3214 }
3215}
3216
3217#define MORE_CHAR_SUSPENDED Qtrue
3218#define MORE_CHAR_FINISHED Qnil
3219static VALUE
3220fill_cbuf(rb_io_t *fptr, int ec_flags)
3221{
3222 const unsigned char *ss, *sp, *se;
3223 unsigned char *ds, *dp, *de;
3225 int putbackable;
3226 int cbuf_len0;
3227 VALUE exc;
3228
3229 ec_flags |= ECONV_PARTIAL_INPUT;
3230
3231 if (fptr->cbuf.len == fptr->cbuf.capa)
3232 return MORE_CHAR_SUSPENDED; /* cbuf full */
3233 if (fptr->cbuf.len == 0)
3234 fptr->cbuf.off = 0;
3235 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3236 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3237 fptr->cbuf.off = 0;
3238 }
3239
3240 cbuf_len0 = fptr->cbuf.len;
3241
3242 while (1) {
3243 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3244 se = sp + fptr->rbuf.len;
3245 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3246 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3247 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3248 fptr->rbuf.off += (int)(sp - ss);
3249 fptr->rbuf.len -= (int)(sp - ss);
3250 fptr->cbuf.len += (int)(dp - ds);
3251
3252 putbackable = rb_econv_putbackable(fptr->readconv);
3253 if (putbackable) {
3254 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3255 fptr->rbuf.off -= putbackable;
3256 fptr->rbuf.len += putbackable;
3257 }
3258
3259 exc = rb_econv_make_exception(fptr->readconv);
3260 if (!NIL_P(exc))
3261 return exc;
3262
3263 if (cbuf_len0 != fptr->cbuf.len)
3264 return MORE_CHAR_SUSPENDED;
3265
3266 if (res == econv_finished) {
3267 return MORE_CHAR_FINISHED;
3268 }
3269
3270 if (res == econv_source_buffer_empty) {
3271 if (fptr->rbuf.len == 0) {
3272 READ_CHECK(fptr);
3273 if (io_fillbuf(fptr) < 0) {
3274 if (!fptr->readconv) {
3275 return MORE_CHAR_FINISHED;
3276 }
3277 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3278 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3279 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3280 fptr->cbuf.len += (int)(dp - ds);
3282 break;
3283 }
3284 }
3285 }
3286 }
3287 if (cbuf_len0 != fptr->cbuf.len)
3288 return MORE_CHAR_SUSPENDED;
3289
3290 return MORE_CHAR_FINISHED;
3291}
3292
3293static VALUE
3294more_char(rb_io_t *fptr)
3295{
3296 VALUE v;
3297 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3298 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3299 rb_exc_raise(v);
3300 return v;
3301}
3302
3303static VALUE
3304io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3305{
3306 VALUE str = Qnil;
3307 if (strp) {
3308 str = *strp;
3309 if (NIL_P(str)) {
3310 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3311 }
3312 else {
3313 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3314 }
3315 rb_enc_associate(str, fptr->encs.enc);
3316 }
3317 fptr->cbuf.off += len;
3318 fptr->cbuf.len -= len;
3319 /* xxx: set coderange */
3320 if (fptr->cbuf.len == 0)
3321 fptr->cbuf.off = 0;
3322 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3323 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3324 fptr->cbuf.off = 0;
3325 }
3326 return str;
3327}
3328
3329static int
3330io_setstrbuf(VALUE *str, long len)
3331{
3332#ifdef _WIN32
3333 if (len > 0)
3334 len = (len + 1) & ~1L; /* round up for wide char */
3335#endif
3336 if (NIL_P(*str)) {
3337 *str = rb_str_new(0, len);
3338 return TRUE;
3339 }
3340 else {
3341 VALUE s = StringValue(*str);
3342 rb_str_modify(s);
3343
3344 long clen = RSTRING_LEN(s);
3345 if (clen >= len) {
3346 return FALSE;
3347 }
3348 len -= clen;
3349 }
3350 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3352 }
3353 return FALSE;
3354}
3355
3356#define MAX_REALLOC_GAP 4096
3357static void
3358io_shrink_read_string(VALUE str, long n)
3359{
3360 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3361 rb_str_resize(str, n);
3362 }
3363}
3364
3365static void
3366io_set_read_length(VALUE str, long n, int shrinkable)
3367{
3368 if (RSTRING_LEN(str) != n) {
3369 rb_str_modify(str);
3370 rb_str_set_len(str, n);
3371 if (shrinkable) io_shrink_read_string(str, n);
3372 }
3373}
3374
3375static VALUE
3376read_all(rb_io_t *fptr, long siz, VALUE str)
3377{
3378 long bytes;
3379 long n;
3380 long pos;
3381 rb_encoding *enc;
3382 int cr;
3383 int shrinkable;
3384
3385 if (NEED_READCONV(fptr)) {
3386 int first = !NIL_P(str);
3387 SET_BINARY_MODE(fptr);
3388 shrinkable = io_setstrbuf(&str,0);
3389 make_readconv(fptr, 0);
3390 while (1) {
3391 VALUE v;
3392 if (fptr->cbuf.len) {
3393 if (first) rb_str_set_len(str, first = 0);
3394 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3395 }
3396 v = fill_cbuf(fptr, 0);
3397 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3398 if (fptr->cbuf.len) {
3399 if (first) rb_str_set_len(str, first = 0);
3400 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3401 }
3402 rb_exc_raise(v);
3403 }
3404 if (v == MORE_CHAR_FINISHED) {
3405 clear_readconv(fptr);
3406 if (first) rb_str_set_len(str, first = 0);
3407 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3408 return io_enc_str(str, fptr);
3409 }
3410 }
3411 }
3412
3413 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3414 bytes = 0;
3415 pos = 0;
3416
3417 enc = io_read_encoding(fptr);
3418 cr = 0;
3419
3420 if (siz == 0) siz = BUFSIZ;
3421 shrinkable = io_setstrbuf(&str, siz);
3422 for (;;) {
3423 READ_CHECK(fptr);
3424 n = io_fread(str, bytes, siz - bytes, fptr);
3425 if (n == 0 && bytes == 0) {
3426 rb_str_set_len(str, 0);
3427 break;
3428 }
3429 bytes += n;
3430 rb_str_set_len(str, bytes);
3431 if (cr != ENC_CODERANGE_BROKEN)
3432 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3433 if (bytes < siz) break;
3434 siz += BUFSIZ;
3435
3436 size_t capa = rb_str_capacity(str);
3437 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3438 if (capa < BUFSIZ) {
3439 capa = BUFSIZ;
3440 }
3441 else if (capa > IO_MAX_BUFFER_GROWTH) {
3442 capa = IO_MAX_BUFFER_GROWTH;
3443 }
3445 }
3446 }
3447 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3448 str = io_enc_str(str, fptr);
3449 ENC_CODERANGE_SET(str, cr);
3450 return str;
3451}
3452
3453void
3455{
3456 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3457 rb_sys_fail_path(fptr->pathv);
3458 }
3459}
3460
3461static VALUE
3462io_read_memory_call(VALUE arg)
3463{
3464 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3465
3466 VALUE scheduler = rb_fiber_scheduler_current();
3467 if (scheduler != Qnil) {
3468 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3469
3470 if (!UNDEF_P(result)) {
3471 // This is actually returned as a pseudo-VALUE and later cast to a long:
3473 }
3474 }
3475
3476 if (iis->nonblock) {
3477 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3478 }
3479 else {
3480 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3481 }
3482}
3483
3484static long
3485io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3486{
3487 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3488}
3489
3490#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3491
3492static VALUE
3493io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3494{
3495 rb_io_t *fptr;
3496 VALUE length, str;
3497 long n, len;
3498 struct io_internal_read_struct iis;
3499 int shrinkable;
3500
3501 rb_scan_args(argc, argv, "11", &length, &str);
3502
3503 if ((len = NUM2LONG(length)) < 0) {
3504 rb_raise(rb_eArgError, "negative length %ld given", len);
3505 }
3506
3507 shrinkable = io_setstrbuf(&str, len);
3508
3509 GetOpenFile(io, fptr);
3511
3512 if (len == 0) {
3513 io_set_read_length(str, 0, shrinkable);
3514 return str;
3515 }
3516
3517 if (!nonblock)
3518 READ_CHECK(fptr);
3519 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3520 if (n <= 0) {
3521 again:
3522 if (nonblock) {
3523 rb_io_set_nonblock(fptr);
3524 }
3525 io_setstrbuf(&str, len);
3526 iis.th = rb_thread_current();
3527 iis.fptr = fptr;
3528 iis.nonblock = nonblock;
3529 iis.fd = fptr->fd;
3530 iis.buf = RSTRING_PTR(str);
3531 iis.capa = len;
3532 iis.timeout = NULL;
3533 n = io_read_memory_locktmp(str, &iis);
3534 if (n < 0) {
3535 int e = errno;
3536 if (!nonblock && fptr_wait_readable(fptr))
3537 goto again;
3538 if (nonblock && (io_again_p(e))) {
3539 if (no_exception)
3540 return sym_wait_readable;
3541 else
3542 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3543 e, "read would block");
3544 }
3545 rb_syserr_fail_path(e, fptr->pathv);
3546 }
3547 }
3548 io_set_read_length(str, n, shrinkable);
3549
3550 if (n == 0)
3551 return Qnil;
3552 else
3553 return str;
3554}
3555
3556/*
3557 * call-seq:
3558 * readpartial(maxlen) -> string
3559 * readpartial(maxlen, out_string) -> out_string
3560 *
3561 * Reads up to +maxlen+ bytes from the stream;
3562 * returns a string (either a new string or the given +out_string+).
3563 * Its encoding is:
3564 *
3565 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3566 * - ASCII-8BIT, otherwise.
3567 *
3568 * - Contains +maxlen+ bytes from the stream, if available.
3569 * - Otherwise contains all available bytes, if any available.
3570 * - Otherwise is an empty string.
3571 *
3572 * With the single non-negative integer argument +maxlen+ given,
3573 * returns a new string:
3574 *
3575 * f = File.new('t.txt')
3576 * f.readpartial(20) # => "First line\nSecond l"
3577 * f.readpartial(20) # => "ine\n\nFourth line\n"
3578 * f.readpartial(20) # => "Fifth line\n"
3579 * f.readpartial(20) # Raises EOFError.
3580 * f.close
3581 *
3582 * With both argument +maxlen+ and string argument +out_string+ given,
3583 * returns modified +out_string+:
3584 *
3585 * f = File.new('t.txt')
3586 * s = 'foo'
3587 * f.readpartial(20, s) # => "First line\nSecond l"
3588 * s = 'bar'
3589 * f.readpartial(0, s) # => ""
3590 * f.close
3591 *
3592 * This method is useful for a stream such as a pipe, a socket, or a tty.
3593 * It blocks only when no data is immediately available.
3594 * This means that it blocks only when _all_ of the following are true:
3595 *
3596 * - The byte buffer in the stream is empty.
3597 * - The content of the stream is empty.
3598 * - The stream is not at EOF.
3599 *
3600 * When blocked, the method waits for either more data or EOF on the stream:
3601 *
3602 * - If more data is read, the method returns the data.
3603 * - If EOF is reached, the method raises EOFError.
3604 *
3605 * When not blocked, the method responds immediately:
3606 *
3607 * - Returns data from the buffer if there is any.
3608 * - Otherwise returns data from the stream if there is any.
3609 * - Otherwise raises EOFError if the stream has reached EOF.
3610 *
3611 * Note that this method is similar to sysread. The differences are:
3612 *
3613 * - If the byte buffer is not empty, read from the byte buffer
3614 * instead of "sysread for buffered IO (IOError)".
3615 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3616 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3617 * readpartial retries the system call.
3618 *
3619 * The latter means that readpartial is non-blocking-flag insensitive.
3620 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3621 * if the fd is blocking mode.
3622 *
3623 * Examples:
3624 *
3625 * # # Returned Buffer Content Pipe Content
3626 * r, w = IO.pipe #
3627 * w << 'abc' # "" "abc".
3628 * r.readpartial(4096) # => "abc" "" ""
3629 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3630 *
3631 * # # Returned Buffer Content Pipe Content
3632 * r, w = IO.pipe #
3633 * w << 'abc' # "" "abc"
3634 * w.close # "" "abc" EOF
3635 * r.readpartial(4096) # => "abc" "" EOF
3636 * r.readpartial(4096) # raises EOFError
3637 *
3638 * # # Returned Buffer Content Pipe Content
3639 * r, w = IO.pipe #
3640 * w << "abc\ndef\n" # "" "abc\ndef\n"
3641 * r.gets # => "abc\n" "def\n" ""
3642 * w << "ghi\n" # "def\n" "ghi\n"
3643 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3644 * r.readpartial(4096) # => "ghi\n" "" ""
3645 *
3646 */
3647
3648static VALUE
3649io_readpartial(int argc, VALUE *argv, VALUE io)
3650{
3651 VALUE ret;
3652
3653 ret = io_getpartial(argc, argv, io, Qnil, 0);
3654 if (NIL_P(ret))
3655 rb_eof_error();
3656 return ret;
3657}
3658
3659static VALUE
3660io_nonblock_eof(int no_exception)
3661{
3662 if (!no_exception) {
3663 rb_eof_error();
3664 }
3665 return Qnil;
3666}
3667
3668/* :nodoc: */
3669static VALUE
3670io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3671{
3672 rb_io_t *fptr;
3673 long n, len;
3674 struct io_internal_read_struct iis;
3675 int shrinkable;
3676
3677 if ((len = NUM2LONG(length)) < 0) {
3678 rb_raise(rb_eArgError, "negative length %ld given", len);
3679 }
3680
3681 shrinkable = io_setstrbuf(&str, len);
3682 rb_bool_expected(ex, "exception", TRUE);
3683
3684 GetOpenFile(io, fptr);
3686
3687 if (len == 0) {
3688 io_set_read_length(str, 0, shrinkable);
3689 return str;
3690 }
3691
3692 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3693 if (n <= 0) {
3694 rb_fd_set_nonblock(fptr->fd);
3695 shrinkable |= io_setstrbuf(&str, len);
3696 iis.fptr = fptr;
3697 iis.nonblock = 1;
3698 iis.fd = fptr->fd;
3699 iis.buf = RSTRING_PTR(str);
3700 iis.capa = len;
3701 iis.timeout = NULL;
3702 n = io_read_memory_locktmp(str, &iis);
3703 if (n < 0) {
3704 int e = errno;
3705 if (io_again_p(e)) {
3706 if (!ex) return sym_wait_readable;
3707 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3708 e, "read would block");
3709 }
3710 rb_syserr_fail_path(e, fptr->pathv);
3711 }
3712 }
3713 io_set_read_length(str, n, shrinkable);
3714
3715 if (n == 0) {
3716 if (!ex) return Qnil;
3717 rb_eof_error();
3718 }
3719
3720 return str;
3721}
3722
3723/* :nodoc: */
3724static VALUE
3725io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3726{
3727 rb_io_t *fptr;
3728 long n;
3729
3730 if (!RB_TYPE_P(str, T_STRING))
3731 str = rb_obj_as_string(str);
3732 rb_bool_expected(ex, "exception", TRUE);
3733
3734 io = GetWriteIO(io);
3735 GetOpenFile(io, fptr);
3737
3738 if (io_fflush(fptr) < 0)
3739 rb_sys_fail_on_write(fptr);
3740
3741 rb_fd_set_nonblock(fptr->fd);
3742 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3743 RB_GC_GUARD(str);
3744
3745 if (n < 0) {
3746 int e = errno;
3747 if (io_again_p(e)) {
3748 if (!ex) {
3749 return sym_wait_writable;
3750 }
3751 else {
3752 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3753 }
3754 }
3755 rb_syserr_fail_path(e, fptr->pathv);
3756 }
3757
3758 return LONG2FIX(n);
3759}
3760
3761/*
3762 * call-seq:
3763 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3764 *
3765 * Reads bytes from the stream; the stream must be opened for reading
3766 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3767 *
3768 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3769 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3770 *
3771 * Returns a string (either a new string or the given +out_string+)
3772 * containing the bytes read.
3773 * The encoding of the string depends on both +maxLen+ and +out_string+:
3774 *
3775 * - +maxlen+ is +nil+: uses internal encoding of +self+
3776 * (regardless of whether +out_string+ was given).
3777 * - +maxlen+ not +nil+:
3778 *
3779 * - +out_string+ given: encoding of +out_string+ not modified.
3780 * - +out_string+ not given: ASCII-8BIT is used.
3781 *
3782 * <b>Without Argument +out_string+</b>
3783 *
3784 * When argument +out_string+ is omitted,
3785 * the returned value is a new string:
3786 *
3787 * f = File.new('t.txt')
3788 * f.read
3789 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3790 * f.rewind
3791 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3792 * f.read(30) # => "rth line\r\nFifth line\r\n"
3793 * f.read(30) # => nil
3794 * f.close
3795 *
3796 * If +maxlen+ is zero, returns an empty string.
3797 *
3798 * <b> With Argument +out_string+</b>
3799 *
3800 * When argument +out_string+ is given,
3801 * the returned value is +out_string+, whose content is replaced:
3802 *
3803 * f = File.new('t.txt')
3804 * s = 'foo' # => "foo"
3805 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3806 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3807 * f.rewind
3808 * s = 'bar'
3809 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3810 * s # => "First line\r\nSecond line\r\n\r\nFou"
3811 * s = 'baz'
3812 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3813 * s # => "rth line\r\nFifth line\r\n"
3814 * s = 'bat'
3815 * f.read(30, s) # => nil
3816 * s # => ""
3817 * f.close
3818 *
3819 * Note that this method behaves like the fread() function in C.
3820 * This means it retries to invoke read(2) system calls to read data
3821 * with the specified maxlen (or until EOF).
3822 *
3823 * This behavior is preserved even if the stream is in non-blocking mode.
3824 * (This method is non-blocking-flag insensitive as other methods.)
3825 *
3826 * If you need the behavior like a single read(2) system call,
3827 * consider #readpartial, #read_nonblock, and #sysread.
3828 *
3829 * Related: IO#write.
3830 */
3831
3832static VALUE
3833io_read(int argc, VALUE *argv, VALUE io)
3834{
3835 rb_io_t *fptr;
3836 long n, len;
3837 VALUE length, str;
3838 int shrinkable;
3839#if RUBY_CRLF_ENVIRONMENT
3840 int previous_mode;
3841#endif
3842
3843 rb_scan_args(argc, argv, "02", &length, &str);
3844
3845 if (NIL_P(length)) {
3846 GetOpenFile(io, fptr);
3848 return read_all(fptr, remain_size(fptr), str);
3849 }
3850 len = NUM2LONG(length);
3851 if (len < 0) {
3852 rb_raise(rb_eArgError, "negative length %ld given", len);
3853 }
3854
3855 shrinkable = io_setstrbuf(&str,len);
3856
3857 GetOpenFile(io, fptr);
3859 if (len == 0) {
3860 io_set_read_length(str, 0, shrinkable);
3861 return str;
3862 }
3863
3864 READ_CHECK(fptr);
3865#if RUBY_CRLF_ENVIRONMENT
3866 previous_mode = set_binary_mode_with_seek_cur(fptr);
3867#endif
3868 n = io_fread(str, 0, len, fptr);
3869 io_set_read_length(str, n, shrinkable);
3870#if RUBY_CRLF_ENVIRONMENT
3871 if (previous_mode == O_TEXT) {
3872 setmode(fptr->fd, O_TEXT);
3873 }
3874#endif
3875 if (n == 0) return Qnil;
3876
3877 return str;
3878}
3879
3880static void
3881rscheck(const char *rsptr, long rslen, VALUE rs)
3882{
3883 if (!rs) return;
3884 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3885 rb_raise(rb_eRuntimeError, "rs modified");
3886}
3887
3888static const char *
3889search_delim(const char *p, long len, int delim, rb_encoding *enc)
3890{
3891 if (rb_enc_mbminlen(enc) == 1) {
3892 p = memchr(p, delim, len);
3893 if (p) return p + 1;
3894 }
3895 else {
3896 const char *end = p + len;
3897 while (p < end) {
3898 int r = rb_enc_precise_mbclen(p, end, enc);
3899 if (!MBCLEN_CHARFOUND_P(r)) {
3900 p += rb_enc_mbminlen(enc);
3901 continue;
3902 }
3903 int n = MBCLEN_CHARFOUND_LEN(r);
3904 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3905 return p + n;
3906 }
3907 p += n;
3908 }
3909 }
3910 return NULL;
3911}
3912
3913static int
3914appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3915{
3916 VALUE str = *strp;
3917 long limit = *lp;
3918
3919 if (NEED_READCONV(fptr)) {
3920 SET_BINARY_MODE(fptr);
3921 make_readconv(fptr, 0);
3922 do {
3923 const char *p, *e;
3924 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3925 if (searchlen) {
3926 p = READ_CHAR_PENDING_PTR(fptr);
3927 if (0 < limit && limit < searchlen)
3928 searchlen = (int)limit;
3929 e = search_delim(p, searchlen, delim, enc);
3930 if (e) {
3931 int len = (int)(e-p);
3932 if (NIL_P(str))
3933 *strp = str = rb_str_new(p, len);
3934 else
3935 rb_str_buf_cat(str, p, len);
3936 fptr->cbuf.off += len;
3937 fptr->cbuf.len -= len;
3938 limit -= len;
3939 *lp = limit;
3940 return delim;
3941 }
3942
3943 if (NIL_P(str))
3944 *strp = str = rb_str_new(p, searchlen);
3945 else
3946 rb_str_buf_cat(str, p, searchlen);
3947 fptr->cbuf.off += searchlen;
3948 fptr->cbuf.len -= searchlen;
3949 limit -= searchlen;
3950
3951 if (limit == 0) {
3952 *lp = limit;
3953 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3954 }
3955 }
3956 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3957 clear_readconv(fptr);
3958 *lp = limit;
3959 return EOF;
3960 }
3961
3962 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3963 do {
3964 long pending = READ_DATA_PENDING_COUNT(fptr);
3965 if (pending > 0) {
3966 const char *p = READ_DATA_PENDING_PTR(fptr);
3967 const char *e;
3968 long last;
3969
3970 if (limit > 0 && pending > limit) pending = limit;
3971 e = search_delim(p, pending, delim, enc);
3972 if (e) pending = e - p;
3973 if (!NIL_P(str)) {
3974 last = RSTRING_LEN(str);
3975 rb_str_resize(str, last + pending);
3976 }
3977 else {
3978 last = 0;
3979 *strp = str = rb_str_buf_new(pending);
3980 rb_str_set_len(str, pending);
3981 }
3982 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3983 limit -= pending;
3984 *lp = limit;
3985 if (e) return delim;
3986 if (limit == 0)
3987 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3988 }
3989 READ_CHECK(fptr);
3990 } while (io_fillbuf(fptr) >= 0);
3991 *lp = limit;
3992 return EOF;
3993}
3994
3995static inline int
3996swallow(rb_io_t *fptr, int term)
3997{
3998 if (NEED_READCONV(fptr)) {
3999 rb_encoding *enc = io_read_encoding(fptr);
4000 int needconv = rb_enc_mbminlen(enc) != 1;
4001 SET_BINARY_MODE(fptr);
4002 make_readconv(fptr, 0);
4003 do {
4004 size_t cnt;
4005 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4006 const char *p = READ_CHAR_PENDING_PTR(fptr);
4007 int i;
4008 if (!needconv) {
4009 if (*p != term) return TRUE;
4010 i = (int)cnt;
4011 while (--i && *++p == term);
4012 }
4013 else {
4014 const char *e = p + cnt;
4015 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
4016 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4017 i = (int)(e - p);
4018 }
4019 io_shift_cbuf(fptr, (int)cnt - i, NULL);
4020 }
4021 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4022 return FALSE;
4023 }
4024
4025 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4026 do {
4027 size_t cnt;
4028 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4029 char buf[1024];
4030 const char *p = READ_DATA_PENDING_PTR(fptr);
4031 int i;
4032 if (cnt > sizeof buf) cnt = sizeof buf;
4033 if (*p != term) return TRUE;
4034 i = (int)cnt;
4035 while (--i && *++p == term);
4036 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4037 rb_sys_fail_path(fptr->pathv);
4038 }
4039 READ_CHECK(fptr);
4040 } while (io_fillbuf(fptr) == 0);
4041 return FALSE;
4042}
4043
4044static VALUE
4045rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4046{
4047 VALUE str = Qnil;
4048 int len = 0;
4049 long pos = 0;
4050 int cr = 0;
4051
4052 do {
4053 int pending = READ_DATA_PENDING_COUNT(fptr);
4054
4055 if (pending > 0) {
4056 const char *p = READ_DATA_PENDING_PTR(fptr);
4057 const char *e;
4058 int chomplen = 0;
4059
4060 e = memchr(p, '\n', pending);
4061 if (e) {
4062 pending = (int)(e - p + 1);
4063 if (chomp) {
4064 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4065 }
4066 }
4067 if (NIL_P(str)) {
4068 str = rb_str_new(p, pending - chomplen);
4069 fptr->rbuf.off += pending;
4070 fptr->rbuf.len -= pending;
4071 }
4072 else {
4073 rb_str_resize(str, len + pending - chomplen);
4074 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4075 fptr->rbuf.off += chomplen;
4076 fptr->rbuf.len -= chomplen;
4077 if (pending == 1 && chomplen == 1 && len > 0) {
4078 if (RSTRING_PTR(str)[len-1] == '\r') {
4079 rb_str_resize(str, --len);
4080 break;
4081 }
4082 }
4083 }
4084 len += pending - chomplen;
4085 if (cr != ENC_CODERANGE_BROKEN)
4086 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4087 if (e) break;
4088 }
4089 READ_CHECK(fptr);
4090 } while (io_fillbuf(fptr) >= 0);
4091 if (NIL_P(str)) return Qnil;
4092
4093 str = io_enc_str(str, fptr);
4094 ENC_CODERANGE_SET(str, cr);
4095 fptr->lineno++;
4096
4097 return str;
4098}
4099
4101 VALUE io;
4102 VALUE rs;
4103 long limit;
4104 unsigned int chomp: 1;
4105};
4106
4107static void
4108extract_getline_opts(VALUE opts, struct getline_arg *args)
4109{
4110 int chomp = FALSE;
4111 if (!NIL_P(opts)) {
4112 static ID kwds[1];
4113 VALUE vchomp;
4114 if (!kwds[0]) {
4115 kwds[0] = rb_intern_const("chomp");
4116 }
4117 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4118 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4119 }
4120 args->chomp = chomp;
4121}
4122
4123static void
4124extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4125{
4126 VALUE rs = rb_rs, lim = Qnil;
4127
4128 if (argc == 1) {
4129 VALUE tmp = Qnil;
4130
4131 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4132 rs = tmp;
4133 }
4134 else {
4135 lim = argv[0];
4136 }
4137 }
4138 else if (2 <= argc) {
4139 rs = argv[0], lim = argv[1];
4140 if (!NIL_P(rs))
4141 StringValue(rs);
4142 }
4143 args->rs = rs;
4144 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4145}
4146
4147static void
4148check_getline_args(VALUE *rsp, long *limit, VALUE io)
4149{
4150 rb_io_t *fptr;
4151 VALUE rs = *rsp;
4152
4153 if (!NIL_P(rs)) {
4154 rb_encoding *enc_rs, *enc_io;
4155
4156 GetOpenFile(io, fptr);
4157 enc_rs = rb_enc_get(rs);
4158 enc_io = io_read_encoding(fptr);
4159 if (enc_io != enc_rs &&
4160 (!is_ascii_string(rs) ||
4161 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4162 if (rs == rb_default_rs) {
4163 rs = rb_enc_str_new(0, 0, enc_io);
4164 rb_str_buf_cat_ascii(rs, "\n");
4165 *rsp = rs;
4166 }
4167 else {
4168 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4169 rb_enc_name(enc_io),
4170 rb_enc_name(enc_rs));
4171 }
4172 }
4173 }
4174}
4175
4176static void
4177prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4178{
4179 VALUE opts;
4180 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4181 extract_getline_args(argc, argv, args);
4182 extract_getline_opts(opts, args);
4183 check_getline_args(&args->rs, &args->limit, io);
4184}
4185
4186static VALUE
4187rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4188{
4189 VALUE str = Qnil;
4190 int nolimit = 0;
4191 rb_encoding *enc;
4192
4194 if (NIL_P(rs) && limit < 0) {
4195 str = read_all(fptr, 0, Qnil);
4196 if (RSTRING_LEN(str) == 0) return Qnil;
4197 }
4198 else if (limit == 0) {
4199 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4200 }
4201 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4202 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4203 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4204 return rb_io_getline_fast(fptr, enc, chomp);
4205 }
4206 else {
4207 int c, newline = -1;
4208 const char *rsptr = 0;
4209 long rslen = 0;
4210 int rspara = 0;
4211 int extra_limit = 16;
4212 int chomp_cr = chomp;
4213
4214 SET_BINARY_MODE(fptr);
4215 enc = io_read_encoding(fptr);
4216
4217 if (!NIL_P(rs)) {
4218 rslen = RSTRING_LEN(rs);
4219 if (rslen == 0) {
4220 rsptr = "\n\n";
4221 rslen = 2;
4222 rspara = 1;
4223 swallow(fptr, '\n');
4224 rs = 0;
4225 if (!rb_enc_asciicompat(enc)) {
4226 rs = rb_usascii_str_new(rsptr, rslen);
4227 rs = rb_str_conv_enc(rs, 0, enc);
4228 OBJ_FREEZE(rs);
4229 rsptr = RSTRING_PTR(rs);
4230 rslen = RSTRING_LEN(rs);
4231 }
4232 newline = '\n';
4233 }
4234 else if (rb_enc_mbminlen(enc) == 1) {
4235 rsptr = RSTRING_PTR(rs);
4236 newline = (unsigned char)rsptr[rslen - 1];
4237 }
4238 else {
4239 rs = rb_str_conv_enc(rs, 0, enc);
4240 rsptr = RSTRING_PTR(rs);
4241 const char *e = rsptr + rslen;
4242 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4243 int n;
4244 newline = rb_enc_codepoint_len(last, e, &n, enc);
4245 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4246 }
4247 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4248 }
4249
4250 /* MS - Optimization */
4251 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4252 const char *s, *p, *pp, *e;
4253
4254 if (c == newline) {
4255 if (RSTRING_LEN(str) < rslen) continue;
4256 s = RSTRING_PTR(str);
4257 e = RSTRING_END(str);
4258 p = e - rslen;
4259 if (!at_char_boundary(s, p, e, enc)) continue;
4260 if (!rspara) rscheck(rsptr, rslen, rs);
4261 if (memcmp(p, rsptr, rslen) == 0) {
4262 if (chomp) {
4263 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4264 rb_str_set_len(str, p - s);
4265 }
4266 break;
4267 }
4268 }
4269 if (limit == 0) {
4270 s = RSTRING_PTR(str);
4271 p = RSTRING_END(str);
4272 pp = rb_enc_prev_char(s, p, p, enc);
4273 if (extra_limit && pp &&
4274 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4275 /* relax the limit while incomplete character.
4276 * extra_limit limits the relax length */
4277 limit = 1;
4278 extra_limit--;
4279 }
4280 else {
4281 nolimit = 1;
4282 break;
4283 }
4284 }
4285 }
4286
4287 if (rspara && c != EOF)
4288 swallow(fptr, '\n');
4289 if (!NIL_P(str))
4290 str = io_enc_str(str, fptr);
4291 }
4292
4293 if (!NIL_P(str) && !nolimit) {
4294 fptr->lineno++;
4295 }
4296
4297 return str;
4298}
4299
4300static VALUE
4301rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4302{
4303 rb_io_t *fptr;
4304 int old_lineno, new_lineno;
4305 VALUE str;
4306
4307 GetOpenFile(io, fptr);
4308 old_lineno = fptr->lineno;
4309 str = rb_io_getline_0(rs, limit, chomp, fptr);
4310 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4311 if (io == ARGF.current_file) {
4312 ARGF.lineno += new_lineno - old_lineno;
4313 ARGF.last_lineno = ARGF.lineno;
4314 }
4315 else {
4316 ARGF.last_lineno = new_lineno;
4317 }
4318 }
4319
4320 return str;
4321}
4322
4323static VALUE
4324rb_io_getline(int argc, VALUE *argv, VALUE io)
4325{
4326 struct getline_arg args;
4327
4328 prepare_getline_args(argc, argv, &args, io);
4329 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4330}
4331
4332VALUE
4334{
4335 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4336}
4337
4338VALUE
4339rb_io_gets_limit_internal(VALUE io, long limit)
4340{
4341 rb_io_t *fptr;
4342 GetOpenFile(io, fptr);
4343 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4344}
4345
4346VALUE
4347rb_io_gets_internal(VALUE io)
4348{
4349 return rb_io_gets_limit_internal(io, -1);
4350}
4351
4352/*
4353 * call-seq:
4354 * gets(sep = $/, chomp: false) -> string or nil
4355 * gets(limit, chomp: false) -> string or nil
4356 * gets(sep, limit, chomp: false) -> string or nil
4357 *
4358 * Reads and returns a line from the stream;
4359 * assigns the return value to <tt>$_</tt>.
4360 * See {Line IO}[rdoc-ref:IO@Line+IO].
4361 *
4362 * With no arguments given, returns the next line
4363 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4364 *
4365 * f = File.open('t.txt')
4366 * f.gets # => "First line\n"
4367 * $_ # => "First line\n"
4368 * f.gets # => "\n"
4369 * f.gets # => "Fourth line\n"
4370 * f.gets # => "Fifth line\n"
4371 * f.gets # => nil
4372 * f.close
4373 *
4374 * With only string argument +sep+ given,
4375 * returns the next line as determined by line separator +sep+,
4376 * or +nil+ if none;
4377 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4378 *
4379 * f = File.new('t.txt')
4380 * f.gets('l') # => "First l"
4381 * f.gets('li') # => "ine\nSecond li"
4382 * f.gets('lin') # => "ne\n\nFourth lin"
4383 * f.gets # => "e\n"
4384 * f.close
4385 *
4386 * The two special values for +sep+ are honored:
4387 *
4388 * f = File.new('t.txt')
4389 * # Get all.
4390 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4391 * f.rewind
4392 * # Get paragraph (up to two line separators).
4393 * f.gets('') # => "First line\nSecond line\n\n"
4394 * f.close
4395 *
4396 * With only integer argument +limit+ given,
4397 * limits the number of bytes in the line;
4398 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4399 *
4400 * # No more than one line.
4401 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4402 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4403 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4404 *
4405 * With arguments +sep+ and +limit+ given,
4406 * combines the two behaviors
4407 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4408 *
4409 * Optional keyword argument +chomp+ specifies whether line separators
4410 * are to be omitted:
4411 *
4412 * f = File.open('t.txt')
4413 * # Chomp the lines.
4414 * f.gets(chomp: true) # => "First line"
4415 * f.gets(chomp: true) # => "Second line"
4416 * f.gets(chomp: true) # => ""
4417 * f.gets(chomp: true) # => "Fourth line"
4418 * f.gets(chomp: true) # => "Fifth line"
4419 * f.gets(chomp: true) # => nil
4420 * f.close
4421 *
4422 */
4423
4424static VALUE
4425rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4426{
4427 VALUE str;
4428
4429 str = rb_io_getline(argc, argv, io);
4430 rb_lastline_set(str);
4431
4432 return str;
4433}
4434
4435/*
4436 * call-seq:
4437 * lineno -> integer
4438 *
4439 * Returns the current line number for the stream;
4440 * see {Line Number}[rdoc-ref:IO@Line+Number].
4441 *
4442 */
4443
4444static VALUE
4445rb_io_lineno(VALUE io)
4446{
4447 rb_io_t *fptr;
4448
4449 GetOpenFile(io, fptr);
4451 return INT2NUM(fptr->lineno);
4452}
4453
4454/*
4455 * call-seq:
4456 * lineno = integer -> integer
4457 *
4458 * Sets and returns the line number for the stream;
4459 * see {Line Number}[rdoc-ref:IO@Line+Number].
4460 *
4461 */
4462
4463static VALUE
4464rb_io_set_lineno(VALUE io, VALUE lineno)
4465{
4466 rb_io_t *fptr;
4467
4468 GetOpenFile(io, fptr);
4470 fptr->lineno = NUM2INT(lineno);
4471 return lineno;
4472}
4473
4474/* :nodoc: */
4475static VALUE
4476io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4477{
4478 long limit = -1;
4479 if (NIL_P(lim)) {
4480 VALUE tmp = Qnil;
4481 // If sep is specified, but it's not a string and not nil, then assume
4482 // it's the limit (it should be an integer)
4483 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4484 // If the user has specified a non-nil / non-string value
4485 // for the separator, we assume it's the limit and set the
4486 // separator to default: rb_rs.
4487 lim = sep;
4488 limit = NUM2LONG(lim);
4489 sep = rb_rs;
4490 }
4491 else {
4492 sep = tmp;
4493 }
4494 }
4495 else {
4496 if (!NIL_P(sep)) StringValue(sep);
4497 limit = NUM2LONG(lim);
4498 }
4499
4500 check_getline_args(&sep, &limit, io);
4501
4502 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4503 rb_lastline_set_up(line, 1);
4504
4505 if (NIL_P(line)) {
4506 rb_eof_error();
4507 }
4508 return line;
4509}
4510
4511static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4512
4513/*
4514 * call-seq:
4515 * readlines(sep = $/, chomp: false) -> array
4516 * readlines(limit, chomp: false) -> array
4517 * readlines(sep, limit, chomp: false) -> array
4518 *
4519 * Reads and returns all remaining line from the stream;
4520 * does not modify <tt>$_</tt>.
4521 * See {Line IO}[rdoc-ref:IO@Line+IO].
4522 *
4523 * With no arguments given, returns lines
4524 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4525 *
4526 * f = File.new('t.txt')
4527 * f.readlines
4528 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4529 * f.readlines # => []
4530 * f.close
4531 *
4532 * With only string argument +sep+ given,
4533 * returns lines as determined by line separator +sep+,
4534 * or +nil+ if none;
4535 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4536 *
4537 * f = File.new('t.txt')
4538 * f.readlines('li')
4539 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4540 * f.close
4541 *
4542 * The two special values for +sep+ are honored:
4543 *
4544 * f = File.new('t.txt')
4545 * # Get all into one string.
4546 * f.readlines(nil)
4547 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4548 * # Get paragraphs (up to two line separators).
4549 * f.rewind
4550 * f.readlines('')
4551 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4552 * f.close
4553 *
4554 * With only integer argument +limit+ given,
4555 * limits the number of bytes in each line;
4556 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4557 *
4558 * f = File.new('t.txt')
4559 * f.readlines(8)
4560 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4561 * f.close
4562 *
4563 * With arguments +sep+ and +limit+ given,
4564 * combines the two behaviors
4565 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4566 *
4567 * Optional keyword argument +chomp+ specifies whether line separators
4568 * are to be omitted:
4569 *
4570 * f = File.new('t.txt')
4571 * f.readlines(chomp: true)
4572 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4573 * f.close
4574 *
4575 */
4576
4577static VALUE
4578rb_io_readlines(int argc, VALUE *argv, VALUE io)
4579{
4580 struct getline_arg args;
4581
4582 prepare_getline_args(argc, argv, &args, io);
4583 return io_readlines(&args, io);
4584}
4585
4586static VALUE
4587io_readlines(const struct getline_arg *arg, VALUE io)
4588{
4589 VALUE line, ary;
4590
4591 if (arg->limit == 0)
4592 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4593 ary = rb_ary_new();
4594 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4595 rb_ary_push(ary, line);
4596 }
4597 return ary;
4598}
4599
4600/*
4601 * call-seq:
4602 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4603 * each_line(limit, chomp: false) {|line| ... } -> self
4604 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4605 * each_line -> enumerator
4606 *
4607 * Calls the block with each remaining line read from the stream;
4608 * returns +self+.
4609 * Does nothing if already at end-of-stream;
4610 * See {Line IO}[rdoc-ref:IO@Line+IO].
4611 *
4612 * With no arguments given, reads lines
4613 * as determined by line separator <tt>$/</tt>:
4614 *
4615 * f = File.new('t.txt')
4616 * f.each_line {|line| p line }
4617 * f.each_line {|line| fail 'Cannot happen' }
4618 * f.close
4619 *
4620 * Output:
4621 *
4622 * "First line\n"
4623 * "Second line\n"
4624 * "\n"
4625 * "Fourth line\n"
4626 * "Fifth line\n"
4627 *
4628 * With only string argument +sep+ given,
4629 * reads lines as determined by line separator +sep+;
4630 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4631 *
4632 * f = File.new('t.txt')
4633 * f.each_line('li') {|line| p line }
4634 * f.close
4635 *
4636 * Output:
4637 *
4638 * "First li"
4639 * "ne\nSecond li"
4640 * "ne\n\nFourth li"
4641 * "ne\nFifth li"
4642 * "ne\n"
4643 *
4644 * The two special values for +sep+ are honored:
4645 *
4646 * f = File.new('t.txt')
4647 * # Get all into one string.
4648 * f.each_line(nil) {|line| p line }
4649 * f.close
4650 *
4651 * Output:
4652 *
4653 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4654 *
4655 * f.rewind
4656 * # Get paragraphs (up to two line separators).
4657 * f.each_line('') {|line| p line }
4658 *
4659 * Output:
4660 *
4661 * "First line\nSecond line\n\n"
4662 * "Fourth line\nFifth line\n"
4663 *
4664 * With only integer argument +limit+ given,
4665 * limits the number of bytes in each line;
4666 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4667 *
4668 * f = File.new('t.txt')
4669 * f.each_line(8) {|line| p line }
4670 * f.close
4671 *
4672 * Output:
4673 *
4674 * "First li"
4675 * "ne\n"
4676 * "Second l"
4677 * "ine\n"
4678 * "\n"
4679 * "Fourth l"
4680 * "ine\n"
4681 * "Fifth li"
4682 * "ne\n"
4683 *
4684 * With arguments +sep+ and +limit+ given,
4685 * combines the two behaviors
4686 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4687 *
4688 * Optional keyword argument +chomp+ specifies whether line separators
4689 * are to be omitted:
4690 *
4691 * f = File.new('t.txt')
4692 * f.each_line(chomp: true) {|line| p line }
4693 * f.close
4694 *
4695 * Output:
4696 *
4697 * "First line"
4698 * "Second line"
4699 * ""
4700 * "Fourth line"
4701 * "Fifth line"
4702 *
4703 * Returns an Enumerator if no block is given.
4704 */
4705
4706static VALUE
4707rb_io_each_line(int argc, VALUE *argv, VALUE io)
4708{
4709 VALUE str;
4710 struct getline_arg args;
4711
4712 RETURN_ENUMERATOR(io, argc, argv);
4713 prepare_getline_args(argc, argv, &args, io);
4714 if (args.limit == 0)
4715 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4716 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4717 rb_yield(str);
4718 }
4719 return io;
4720}
4721
4722/*
4723 * call-seq:
4724 * each_byte {|byte| ... } -> self
4725 * each_byte -> enumerator
4726 *
4727 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4728 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4729 *
4730 * f = File.new('t.rus')
4731 * a = []
4732 * f.each_byte {|b| a << b }
4733 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4734 * f.close
4735 *
4736 * Returns an Enumerator if no block is given.
4737 *
4738 * Related: IO#each_char, IO#each_codepoint.
4739 *
4740 */
4741
4742static VALUE
4743rb_io_each_byte(VALUE io)
4744{
4745 rb_io_t *fptr;
4746
4747 RETURN_ENUMERATOR(io, 0, 0);
4748 GetOpenFile(io, fptr);
4749
4750 do {
4751 while (fptr->rbuf.len > 0) {
4752 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4753 fptr->rbuf.len--;
4754 rb_yield(INT2FIX(*p & 0xff));
4756 errno = 0;
4757 }
4758 READ_CHECK(fptr);
4759 } while (io_fillbuf(fptr) >= 0);
4760 return io;
4761}
4762
4763static VALUE
4764io_getc(rb_io_t *fptr, rb_encoding *enc)
4765{
4766 int r, n, cr = 0;
4767 VALUE str;
4768
4769 if (NEED_READCONV(fptr)) {
4770 rb_encoding *read_enc = io_read_encoding(fptr);
4771
4772 str = Qnil;
4773 SET_BINARY_MODE(fptr);
4774 make_readconv(fptr, 0);
4775
4776 while (1) {
4777 if (fptr->cbuf.len) {
4778 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4779 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4780 read_enc);
4781 if (!MBCLEN_NEEDMORE_P(r))
4782 break;
4783 if (fptr->cbuf.len == fptr->cbuf.capa) {
4784 rb_raise(rb_eIOError, "too long character");
4785 }
4786 }
4787
4788 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4789 if (fptr->cbuf.len == 0) {
4790 clear_readconv(fptr);
4791 return Qnil;
4792 }
4793 /* return an unit of an incomplete character just before EOF */
4794 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4795 fptr->cbuf.off += 1;
4796 fptr->cbuf.len -= 1;
4797 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4799 return str;
4800 }
4801 }
4802 if (MBCLEN_INVALID_P(r)) {
4803 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4804 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4805 read_enc);
4806 io_shift_cbuf(fptr, r, &str);
4808 }
4809 else {
4810 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4812 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4813 ISASCII(RSTRING_PTR(str)[0])) {
4814 cr = ENC_CODERANGE_7BIT;
4815 }
4816 }
4817 str = io_enc_str(str, fptr);
4818 ENC_CODERANGE_SET(str, cr);
4819 return str;
4820 }
4821
4822 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4823 if (io_fillbuf(fptr) < 0) {
4824 return Qnil;
4825 }
4826 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4827 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4828 fptr->rbuf.off += 1;
4829 fptr->rbuf.len -= 1;
4830 cr = ENC_CODERANGE_7BIT;
4831 }
4832 else {
4833 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4834 if (MBCLEN_CHARFOUND_P(r) &&
4835 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4836 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4837 fptr->rbuf.off += n;
4838 fptr->rbuf.len -= n;
4840 }
4841 else if (MBCLEN_NEEDMORE_P(r)) {
4842 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4843 fptr->rbuf.len = 0;
4844 getc_needmore:
4845 if (io_fillbuf(fptr) != -1) {
4846 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4847 fptr->rbuf.off++;
4848 fptr->rbuf.len--;
4849 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4850 if (MBCLEN_NEEDMORE_P(r)) {
4851 goto getc_needmore;
4852 }
4853 else if (MBCLEN_CHARFOUND_P(r)) {
4855 }
4856 }
4857 }
4858 else {
4859 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4860 fptr->rbuf.off++;
4861 fptr->rbuf.len--;
4862 }
4863 }
4864 if (!cr) cr = ENC_CODERANGE_BROKEN;
4865 str = io_enc_str(str, fptr);
4866 ENC_CODERANGE_SET(str, cr);
4867 return str;
4868}
4869
4870/*
4871 * call-seq:
4872 * each_char {|c| ... } -> self
4873 * each_char -> enumerator
4874 *
4875 * Calls the given block with each character in the stream; returns +self+.
4876 * See {Character IO}[rdoc-ref:IO@Character+IO].
4877 *
4878 * f = File.new('t.rus')
4879 * a = []
4880 * f.each_char {|c| a << c.ord }
4881 * a # => [1090, 1077, 1089, 1090]
4882 * f.close
4883 *
4884 * Returns an Enumerator if no block is given.
4885 *
4886 * Related: IO#each_byte, IO#each_codepoint.
4887 *
4888 */
4889
4890static VALUE
4891rb_io_each_char(VALUE io)
4892{
4893 rb_io_t *fptr;
4894 rb_encoding *enc;
4895 VALUE c;
4896
4897 RETURN_ENUMERATOR(io, 0, 0);
4898 GetOpenFile(io, fptr);
4900
4901 enc = io_input_encoding(fptr);
4902 READ_CHECK(fptr);
4903 while (!NIL_P(c = io_getc(fptr, enc))) {
4904 rb_yield(c);
4905 }
4906 return io;
4907}
4908
4909/*
4910 * call-seq:
4911 * each_codepoint {|c| ... } -> self
4912 * each_codepoint -> enumerator
4913 *
4914 * Calls the given block with each codepoint in the stream; returns +self+:
4915 *
4916 * f = File.new('t.rus')
4917 * a = []
4918 * f.each_codepoint {|c| a << c }
4919 * a # => [1090, 1077, 1089, 1090]
4920 * f.close
4921 *
4922 * Returns an Enumerator if no block is given.
4923 *
4924 * Related: IO#each_byte, IO#each_char.
4925 *
4926 */
4927
4928static VALUE
4929rb_io_each_codepoint(VALUE io)
4930{
4931 rb_io_t *fptr;
4932 rb_encoding *enc;
4933 unsigned int c;
4934 int r, n;
4935
4936 RETURN_ENUMERATOR(io, 0, 0);
4937 GetOpenFile(io, fptr);
4939
4940 READ_CHECK(fptr);
4941 enc = io_read_encoding(fptr);
4942 if (NEED_READCONV(fptr)) {
4943 SET_BINARY_MODE(fptr);
4944 r = 1; /* no invalid char yet */
4945 for (;;) {
4946 make_readconv(fptr, 0);
4947 for (;;) {
4948 if (fptr->cbuf.len) {
4949 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4950 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4951 enc);
4952 if (!MBCLEN_NEEDMORE_P(r))
4953 break;
4954 if (fptr->cbuf.len == fptr->cbuf.capa) {
4955 rb_raise(rb_eIOError, "too long character");
4956 }
4957 }
4958 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4959 clear_readconv(fptr);
4960 if (!MBCLEN_CHARFOUND_P(r)) {
4961 goto invalid;
4962 }
4963 return io;
4964 }
4965 }
4966 if (MBCLEN_INVALID_P(r)) {
4967 goto invalid;
4968 }
4969 n = MBCLEN_CHARFOUND_LEN(r);
4970 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4971 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4972 enc);
4973 fptr->cbuf.off += n;
4974 fptr->cbuf.len -= n;
4975 rb_yield(UINT2NUM(c));
4977 }
4978 }
4979 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4980 while (io_fillbuf(fptr) >= 0) {
4981 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4982 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4983 if (MBCLEN_CHARFOUND_P(r) &&
4984 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4985 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4986 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4987 fptr->rbuf.off += n;
4988 fptr->rbuf.len -= n;
4989 rb_yield(UINT2NUM(c));
4990 }
4991 else if (MBCLEN_INVALID_P(r)) {
4992 goto invalid;
4993 }
4994 else if (MBCLEN_NEEDMORE_P(r)) {
4995 char cbuf[8], *p = cbuf;
4996 int more = MBCLEN_NEEDMORE_LEN(r);
4997 if (more > numberof(cbuf)) goto invalid;
4998 more += n = fptr->rbuf.len;
4999 if (more > numberof(cbuf)) goto invalid;
5000 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
5001 (p += n, (more -= n) > 0)) {
5002 if (io_fillbuf(fptr) < 0) goto invalid;
5003 if ((n = fptr->rbuf.len) > more) n = more;
5004 }
5005 r = rb_enc_precise_mbclen(cbuf, p, enc);
5006 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
5007 c = rb_enc_codepoint(cbuf, p, enc);
5008 rb_yield(UINT2NUM(c));
5009 }
5010 else {
5011 continue;
5012 }
5014 }
5015 return io;
5016
5017 invalid:
5018 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
5020}
5021
5022/*
5023 * call-seq:
5024 * getc -> character or nil
5025 *
5026 * Reads and returns the next 1-character string from the stream;
5027 * returns +nil+ if already at end-of-stream.
5028 * See {Character IO}[rdoc-ref:IO@Character+IO].
5029 *
5030 * f = File.open('t.txt')
5031 * f.getc # => "F"
5032 * f.close
5033 * f = File.open('t.rus')
5034 * f.getc.ord # => 1090
5035 * f.close
5036 *
5037 * Related: IO#readchar (may raise EOFError).
5038 *
5039 */
5040
5041static VALUE
5042rb_io_getc(VALUE io)
5043{
5044 rb_io_t *fptr;
5045 rb_encoding *enc;
5046
5047 GetOpenFile(io, fptr);
5049
5050 enc = io_input_encoding(fptr);
5051 READ_CHECK(fptr);
5052 return io_getc(fptr, enc);
5053}
5054
5055/*
5056 * call-seq:
5057 * readchar -> string
5058 *
5059 * Reads and returns the next 1-character string from the stream;
5060 * raises EOFError if already at end-of-stream.
5061 * See {Character IO}[rdoc-ref:IO@Character+IO].
5062 *
5063 * f = File.open('t.txt')
5064 * f.readchar # => "F"
5065 * f.close
5066 * f = File.open('t.rus')
5067 * f.readchar.ord # => 1090
5068 * f.close
5069 *
5070 * Related: IO#getc (will not raise EOFError).
5071 *
5072 */
5073
5074static VALUE
5075rb_io_readchar(VALUE io)
5076{
5077 VALUE c = rb_io_getc(io);
5078
5079 if (NIL_P(c)) {
5080 rb_eof_error();
5081 }
5082 return c;
5083}
5084
5085/*
5086 * call-seq:
5087 * getbyte -> integer or nil
5088 *
5089 * Reads and returns the next byte (in range 0..255) from the stream;
5090 * returns +nil+ if already at end-of-stream.
5091 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5092 *
5093 * f = File.open('t.txt')
5094 * f.getbyte # => 70
5095 * f.close
5096 * f = File.open('t.rus')
5097 * f.getbyte # => 209
5098 * f.close
5099 *
5100 * Related: IO#readbyte (may raise EOFError).
5101 */
5102
5103VALUE
5105{
5106 rb_io_t *fptr;
5107 int c;
5108
5109 GetOpenFile(io, fptr);
5111 READ_CHECK(fptr);
5112 VALUE r_stdout = rb_ractor_stdout();
5113 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5114 rb_io_t *ofp;
5115 GetOpenFile(r_stdout, ofp);
5116 if (ofp->mode & FMODE_TTY) {
5117 rb_io_flush(r_stdout);
5118 }
5119 }
5120 if (io_fillbuf(fptr) < 0) {
5121 return Qnil;
5122 }
5123 fptr->rbuf.off++;
5124 fptr->rbuf.len--;
5125 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5126 return INT2FIX(c & 0xff);
5127}
5128
5129/*
5130 * call-seq:
5131 * readbyte -> integer
5132 *
5133 * Reads and returns the next byte (in range 0..255) from the stream;
5134 * raises EOFError if already at end-of-stream.
5135 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5136 *
5137 * f = File.open('t.txt')
5138 * f.readbyte # => 70
5139 * f.close
5140 * f = File.open('t.rus')
5141 * f.readbyte # => 209
5142 * f.close
5143 *
5144 * Related: IO#getbyte (will not raise EOFError).
5145 *
5146 */
5147
5148static VALUE
5149rb_io_readbyte(VALUE io)
5150{
5151 VALUE c = rb_io_getbyte(io);
5152
5153 if (NIL_P(c)) {
5154 rb_eof_error();
5155 }
5156 return c;
5157}
5158
5159/*
5160 * call-seq:
5161 * ungetbyte(integer) -> nil
5162 * ungetbyte(string) -> nil
5163 *
5164 * Pushes back ("unshifts") the given data onto the stream's buffer,
5165 * placing the data so that it is next to be read; returns +nil+.
5166 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5167 *
5168 * Note that:
5169 *
5170 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5171 * - Calling #rewind on the stream discards the pushed-back data.
5172 *
5173 * When argument +integer+ is given, uses only its low-order byte:
5174 *
5175 * File.write('t.tmp', '012')
5176 * f = File.open('t.tmp')
5177 * f.ungetbyte(0x41) # => nil
5178 * f.read # => "A012"
5179 * f.rewind
5180 * f.ungetbyte(0x4243) # => nil
5181 * f.read # => "C012"
5182 * f.close
5183 *
5184 * When argument +string+ is given, uses all bytes:
5185 *
5186 * File.write('t.tmp', '012')
5187 * f = File.open('t.tmp')
5188 * f.ungetbyte('A') # => nil
5189 * f.read # => "A012"
5190 * f.rewind
5191 * f.ungetbyte('BCDE') # => nil
5192 * f.read # => "BCDE012"
5193 * f.close
5194 *
5195 */
5196
5197VALUE
5199{
5200 rb_io_t *fptr;
5201
5202 GetOpenFile(io, fptr);
5204 switch (TYPE(b)) {
5205 case T_NIL:
5206 return Qnil;
5207 case T_FIXNUM:
5208 case T_BIGNUM: ;
5209 VALUE v = rb_int_modulo(b, INT2FIX(256));
5210 unsigned char c = NUM2INT(v) & 0xFF;
5211 b = rb_str_new((const char *)&c, 1);
5212 break;
5213 default:
5214 StringValue(b);
5215 }
5216 io_ungetbyte(b, fptr);
5217 return Qnil;
5218}
5219
5220/*
5221 * call-seq:
5222 * ungetc(integer) -> nil
5223 * ungetc(string) -> nil
5224 *
5225 * Pushes back ("unshifts") the given data onto the stream's buffer,
5226 * placing the data so that it is next to be read; returns +nil+.
5227 * See {Character IO}[rdoc-ref:IO@Character+IO].
5228 *
5229 * Note that:
5230 *
5231 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5232 * - Calling #rewind on the stream discards the pushed-back data.
5233 *
5234 * When argument +integer+ is given, interprets the integer as a character:
5235 *
5236 * File.write('t.tmp', '012')
5237 * f = File.open('t.tmp')
5238 * f.ungetc(0x41) # => nil
5239 * f.read # => "A012"
5240 * f.rewind
5241 * f.ungetc(0x0442) # => nil
5242 * f.getc.ord # => 1090
5243 * f.close
5244 *
5245 * When argument +string+ is given, uses all characters:
5246 *
5247 * File.write('t.tmp', '012')
5248 * f = File.open('t.tmp')
5249 * f.ungetc('A') # => nil
5250 * f.read # => "A012"
5251 * f.rewind
5252 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5253 * f.getc.ord # => 1090
5254 * f.getc.ord # => 1077
5255 * f.getc.ord # => 1089
5256 * f.getc.ord # => 1090
5257 * f.close
5258 *
5259 */
5260
5261VALUE
5263{
5264 rb_io_t *fptr;
5265 long len;
5266
5267 GetOpenFile(io, fptr);
5269 if (FIXNUM_P(c)) {
5270 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5271 }
5272 else if (RB_BIGNUM_TYPE_P(c)) {
5273 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5274 }
5275 else {
5276 StringValue(c);
5277 }
5278 if (NEED_READCONV(fptr)) {
5279 SET_BINARY_MODE(fptr);
5280 len = RSTRING_LEN(c);
5281#if SIZEOF_LONG > SIZEOF_INT
5282 if (len > INT_MAX)
5283 rb_raise(rb_eIOError, "ungetc failed");
5284#endif
5285 make_readconv(fptr, (int)len);
5286 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5287 rb_raise(rb_eIOError, "ungetc failed");
5288 if (fptr->cbuf.off < len) {
5289 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5290 fptr->cbuf.ptr+fptr->cbuf.off,
5291 char, fptr->cbuf.len);
5292 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5293 }
5294 fptr->cbuf.off -= (int)len;
5295 fptr->cbuf.len += (int)len;
5296 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5297 }
5298 else {
5299 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5300 io_ungetbyte(c, fptr);
5301 }
5302 return Qnil;
5303}
5304
5305/*
5306 * call-seq:
5307 * isatty -> true or false
5308 *
5309 * Returns +true+ if the stream is associated with a terminal device (tty),
5310 * +false+ otherwise:
5311 *
5312 * f = File.new('t.txt').isatty #=> false
5313 * f.close
5314 * f = File.new('/dev/tty').isatty #=> true
5315 * f.close
5316 *
5317 */
5318
5319static VALUE
5320rb_io_isatty(VALUE io)
5321{
5322 rb_io_t *fptr;
5323
5324 GetOpenFile(io, fptr);
5325 return RBOOL(isatty(fptr->fd) != 0);
5326}
5327
5328#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5329/*
5330 * call-seq:
5331 * close_on_exec? -> true or false
5332 *
5333 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5334 *
5335 * f = File.open('t.txt')
5336 * f.close_on_exec? # => true
5337 * f.close_on_exec = false
5338 * f.close_on_exec? # => false
5339 * f.close
5340 *
5341 */
5342
5343static VALUE
5344rb_io_close_on_exec_p(VALUE io)
5345{
5346 rb_io_t *fptr;
5347 VALUE write_io;
5348 int fd, ret;
5349
5350 write_io = GetWriteIO(io);
5351 if (io != write_io) {
5352 GetOpenFile(write_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 }
5358
5359 GetOpenFile(io, fptr);
5360 if (fptr && 0 <= (fd = fptr->fd)) {
5361 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5362 if (!(ret & FD_CLOEXEC)) return Qfalse;
5363 }
5364 return Qtrue;
5365}
5366#else
5367#define rb_io_close_on_exec_p rb_f_notimplement
5368#endif
5369
5370#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5371/*
5372 * call-seq:
5373 * self.close_on_exec = bool -> true or false
5374 *
5375 * Sets a close-on-exec flag.
5376 *
5377 * f = File.open(File::NULL)
5378 * f.close_on_exec = true
5379 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5380 * f.closed? #=> false
5381 *
5382 * Ruby sets close-on-exec flags of all file descriptors by default
5383 * since Ruby 2.0.0.
5384 * So you don't need to set by yourself.
5385 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5386 * if another thread use fork() and exec() (via system() method for example).
5387 * If you really needs file descriptor inheritance to child process,
5388 * use spawn()'s argument such as fd=>fd.
5389 */
5390
5391static VALUE
5392rb_io_set_close_on_exec(VALUE io, VALUE arg)
5393{
5394 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5395 rb_io_t *fptr;
5396 VALUE write_io;
5397 int fd, ret;
5398
5399 write_io = GetWriteIO(io);
5400 if (io != write_io) {
5401 GetOpenFile(write_io, fptr);
5402 if (fptr && 0 <= (fd = fptr->fd)) {
5403 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5404 if ((ret & FD_CLOEXEC) != flag) {
5405 ret = (ret & ~FD_CLOEXEC) | flag;
5406 ret = fcntl(fd, F_SETFD, ret);
5407 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5408 }
5409 }
5410
5411 }
5412
5413 GetOpenFile(io, fptr);
5414 if (fptr && 0 <= (fd = fptr->fd)) {
5415 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5416 if ((ret & FD_CLOEXEC) != flag) {
5417 ret = (ret & ~FD_CLOEXEC) | flag;
5418 ret = fcntl(fd, F_SETFD, ret);
5419 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5420 }
5421 }
5422 return Qnil;
5423}
5424#else
5425#define rb_io_set_close_on_exec rb_f_notimplement
5426#endif
5427
5428#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5429#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5430
5431static VALUE
5432finish_writeconv(rb_io_t *fptr, int noalloc)
5433{
5434 unsigned char *ds, *dp, *de;
5436
5437 if (!fptr->wbuf.ptr) {
5438 unsigned char buf[1024];
5439
5441 while (res == econv_destination_buffer_full) {
5442 ds = dp = buf;
5443 de = buf + sizeof(buf);
5444 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5445 while (dp-ds) {
5446 size_t remaining = dp-ds;
5447 long result = rb_io_write_memory(fptr, ds, remaining);
5448
5449 if (result > 0) {
5450 ds += result;
5451 if ((size_t)result == remaining) break;
5452 }
5453 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5454 if (fptr->fd < 0)
5455 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5456 }
5457 else {
5458 return noalloc ? Qtrue : INT2NUM(errno);
5459 }
5460 }
5461 if (res == econv_invalid_byte_sequence ||
5462 res == econv_incomplete_input ||
5464 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5465 }
5466 }
5467
5468 return Qnil;
5469 }
5470
5472 while (res == econv_destination_buffer_full) {
5473 if (fptr->wbuf.len == fptr->wbuf.capa) {
5474 if (io_fflush(fptr) < 0) {
5475 return noalloc ? Qtrue : INT2NUM(errno);
5476 }
5477 }
5478
5479 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5480 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5481 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5482 fptr->wbuf.len += (int)(dp - ds);
5483 if (res == econv_invalid_byte_sequence ||
5484 res == econv_incomplete_input ||
5486 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5487 }
5488 }
5489 return Qnil;
5490}
5491
5493 rb_io_t *fptr;
5494 int noalloc;
5495};
5496
5497static VALUE
5498finish_writeconv_sync(VALUE arg)
5499{
5500 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5501 return finish_writeconv(p->fptr, p->noalloc);
5502}
5503
5504static void*
5505nogvl_close(void *ptr)
5506{
5507 int *fd = ptr;
5508
5509 return (void*)(intptr_t)close(*fd);
5510}
5511
5512static int
5513maygvl_close(int fd, int keepgvl)
5514{
5515 if (keepgvl)
5516 return close(fd);
5517
5518 /*
5519 * close() may block for certain file types (NFS, SO_LINGER sockets,
5520 * inotify), so let other threads run.
5521 */
5522 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5523}
5524
5525static void*
5526nogvl_fclose(void *ptr)
5527{
5528 FILE *file = ptr;
5529
5530 return (void*)(intptr_t)fclose(file);
5531}
5532
5533static int
5534maygvl_fclose(FILE *file, int keepgvl)
5535{
5536 if (keepgvl)
5537 return fclose(file);
5538
5539 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5540}
5541
5542static void free_io_buffer(rb_io_buffer_t *buf);
5543
5544static void
5545fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5546{
5547 VALUE error = Qnil;
5548 int fd = fptr->fd;
5549 FILE *stdio_file = fptr->stdio_file;
5550 int mode = fptr->mode;
5551
5552 if (fptr->writeconv) {
5553 if (!NIL_P(fptr->write_lock) && !noraise) {
5554 struct finish_writeconv_arg arg;
5555 arg.fptr = fptr;
5556 arg.noalloc = noraise;
5557 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5558 }
5559 else {
5560 error = finish_writeconv(fptr, noraise);
5561 }
5562 }
5563 if (fptr->wbuf.len) {
5564 if (noraise) {
5565 io_flush_buffer_sync(fptr);
5566 }
5567 else {
5568 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5569 error = INT2NUM(errno);
5570 }
5571 }
5572 }
5573
5574 int done = 0;
5575
5576 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5577 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5578 done = 1;
5579 }
5580
5581 fptr->fd = -1;
5582 fptr->stdio_file = 0;
5584
5585 // Wait for blocking operations to ensure they do not hit EBADF:
5586 rb_thread_io_close_wait(fptr);
5587
5588 if (!done && stdio_file) {
5589 // stdio_file is deallocated anyway even if fclose failed.
5590 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5591 if (!noraise) {
5592 error = INT2NUM(errno);
5593 }
5594 }
5595
5596 done = 1;
5597 }
5598
5599 VALUE scheduler = rb_fiber_scheduler_current();
5600 if (!done && fd >= 0 && scheduler != Qnil) {
5601 VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
5602
5603 if (!UNDEF_P(result)) {
5604 done = RTEST(result);
5605 }
5606 }
5607
5608 if (!done && fd >= 0) {
5609 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5610 // We assumes it is closed.
5611
5612 keepgvl |= !(mode & FMODE_WRITABLE);
5613 keepgvl |= noraise;
5614 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5615 if (!noraise) {
5616 error = INT2NUM(errno);
5617 }
5618 }
5619
5620 done = 1;
5621 }
5622
5623 if (!NIL_P(error) && !noraise) {
5624 if (RB_INTEGER_TYPE_P(error))
5625 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5626 else
5627 rb_exc_raise(error);
5628 }
5629}
5630
5631static void
5632fptr_finalize(rb_io_t *fptr, int noraise)
5633{
5634 fptr_finalize_flush(fptr, noraise, FALSE);
5635 free_io_buffer(&fptr->rbuf);
5636 free_io_buffer(&fptr->wbuf);
5637 clear_codeconv(fptr);
5638}
5639
5640static void
5641rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5642{
5643 if (fptr->finalize) {
5644 (*fptr->finalize)(fptr, noraise);
5645 }
5646 else {
5647 fptr_finalize(fptr, noraise);
5648 }
5649}
5650
5651static void
5652free_io_buffer(rb_io_buffer_t *buf)
5653{
5654 if (buf->ptr) {
5655 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5656 buf->ptr = NULL;
5657 }
5658}
5659
5660static void
5661clear_readconv(rb_io_t *fptr)
5662{
5663 if (fptr->readconv) {
5664 rb_econv_close(fptr->readconv);
5665 fptr->readconv = NULL;
5666 }
5667 free_io_buffer(&fptr->cbuf);
5668}
5669
5670static void
5671clear_writeconv(rb_io_t *fptr)
5672{
5673 if (fptr->writeconv) {
5675 fptr->writeconv = NULL;
5676 }
5677 fptr->writeconv_initialized = 0;
5678}
5679
5680static void
5681clear_codeconv(rb_io_t *fptr)
5682{
5683 clear_readconv(fptr);
5684 clear_writeconv(fptr);
5685}
5686
5687static void
5688rb_io_fptr_cleanup_all(rb_io_t *fptr)
5689{
5690 fptr->pathv = Qnil;
5691 if (0 <= fptr->fd)
5692 rb_io_fptr_cleanup(fptr, TRUE);
5693 fptr->write_lock = Qnil;
5694 free_io_buffer(&fptr->rbuf);
5695 free_io_buffer(&fptr->wbuf);
5696 clear_codeconv(fptr);
5697}
5698
5699int
5701{
5702 if (!io) return 0;
5703 rb_io_fptr_cleanup_all(io);
5704 free(io);
5705
5706 return 1;
5707}
5708
5709size_t
5710rb_io_memsize(const rb_io_t *io)
5711{
5712 size_t size = sizeof(rb_io_t);
5713 size += io->rbuf.capa;
5714 size += io->wbuf.capa;
5715 size += io->cbuf.capa;
5716 if (io->readconv) size += rb_econv_memsize(io->readconv);
5717 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5718
5719 struct rb_io_blocking_operation *blocking_operation = 0;
5720
5721 // 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.
5722 rb_serial_t fork_generation = GET_VM()->fork_gen;
5723 if (io->fork_generation == fork_generation) {
5724 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5725 size += sizeof(struct rb_io_blocking_operation);
5726 }
5727 }
5728
5729 return size;
5730}
5731
5732#ifdef _WIN32
5733/* keep GVL while closing to prevent crash on Windows */
5734# define KEEPGVL TRUE
5735#else
5736# define KEEPGVL FALSE
5737#endif
5738
5739static rb_io_t *
5740io_close_fptr(VALUE io)
5741{
5742 rb_io_t *fptr;
5743 VALUE write_io;
5744 rb_io_t *write_fptr;
5745
5746 write_io = GetWriteIO(io);
5747 if (io != write_io) {
5748 write_fptr = RFILE(write_io)->fptr;
5749 if (write_fptr && 0 <= write_fptr->fd) {
5750 rb_io_fptr_cleanup(write_fptr, TRUE);
5751 }
5752 }
5753
5754 fptr = RFILE(io)->fptr;
5755 if (!fptr) return 0;
5756 if (fptr->fd < 0) return 0;
5757
5758 // This guards against multiple threads closing the same IO object:
5759 if (rb_thread_io_close_interrupt(fptr)) {
5760 /* calls close(fptr->fd): */
5761 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5762 }
5763
5764 rb_io_fptr_cleanup(fptr, FALSE);
5765 return fptr;
5766}
5767
5768static void
5769fptr_waitpid(rb_io_t *fptr, int nohang)
5770{
5771 int status;
5772 if (fptr->pid) {
5773 rb_last_status_clear();
5774 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5775 fptr->pid = 0;
5776 }
5777}
5778
5779VALUE
5781{
5782 rb_io_t *fptr = io_close_fptr(io);
5783 if (fptr) fptr_waitpid(fptr, 0);
5784 return Qnil;
5785}
5786
5787/*
5788 * call-seq:
5789 * close -> nil
5790 *
5791 * Closes the stream for both reading and writing
5792 * if open for either or both; returns +nil+.
5793 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5794 *
5795 * If the stream is open for writing, flushes any buffered writes
5796 * to the operating system before closing.
5797 *
5798 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5799 * (child exit status).
5800 *
5801 * It is not an error to close an IO object that has already been closed.
5802 * It just returns nil.
5803 *
5804 * Example:
5805 *
5806 * IO.popen('ruby', 'r+') do |pipe|
5807 * puts pipe.closed?
5808 * pipe.close
5809 * puts $?
5810 * puts pipe.closed?
5811 * end
5812 *
5813 * Output:
5814 *
5815 * false
5816 * pid 13760 exit 0
5817 * true
5818 *
5819 * Related: IO#close_read, IO#close_write, IO#closed?.
5820 */
5821
5822static VALUE
5823rb_io_close_m(VALUE io)
5824{
5825 rb_io_t *fptr = rb_io_get_fptr(io);
5826 if (fptr->fd < 0) {
5827 return Qnil;
5828 }
5829 rb_io_close(io);
5830 return Qnil;
5831}
5832
5833static VALUE
5834io_call_close(VALUE io)
5835{
5836 rb_check_funcall(io, rb_intern("close"), 0, 0);
5837 return io;
5838}
5839
5840static VALUE
5841ignore_closed_stream(VALUE io, VALUE exc)
5842{
5843 enum {mesg_len = sizeof(closed_stream)-1};
5844 VALUE mesg = rb_attr_get(exc, idMesg);
5845 if (!RB_TYPE_P(mesg, T_STRING) ||
5846 RSTRING_LEN(mesg) != mesg_len ||
5847 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5848 rb_exc_raise(exc);
5849 }
5850 return io;
5851}
5852
5853static VALUE
5854io_close(VALUE io)
5855{
5856 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5857 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5858 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5859 rb_eIOError, (VALUE)0);
5860 return io;
5861}
5862
5863/*
5864 * call-seq:
5865 * closed? -> true or false
5866 *
5867 * Returns +true+ if the stream is closed for both reading and writing,
5868 * +false+ otherwise.
5869 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5870 *
5871 * IO.popen('ruby', 'r+') do |pipe|
5872 * puts pipe.closed?
5873 * pipe.close_read
5874 * puts pipe.closed?
5875 * pipe.close_write
5876 * puts pipe.closed?
5877 * end
5878 *
5879 * Output:
5880 *
5881 * false
5882 * false
5883 * true
5884 *
5885 * Related: IO#close_read, IO#close_write, IO#close.
5886 */
5887VALUE
5889{
5890 rb_io_t *fptr;
5891 VALUE write_io;
5892 rb_io_t *write_fptr;
5893
5894 write_io = GetWriteIO(io);
5895 if (io != write_io) {
5896 write_fptr = RFILE(write_io)->fptr;
5897 if (write_fptr && 0 <= write_fptr->fd) {
5898 return Qfalse;
5899 }
5900 }
5901
5902 fptr = rb_io_get_fptr(io);
5903 return RBOOL(0 > fptr->fd);
5904}
5905
5906/*
5907 * call-seq:
5908 * close_read -> nil
5909 *
5910 * Closes the stream for reading if open for reading;
5911 * returns +nil+.
5912 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5913 *
5914 * If the stream was opened by IO.popen and is also closed for writing,
5915 * sets global variable <tt>$?</tt> (child exit status).
5916 *
5917 * Example:
5918 *
5919 * IO.popen('ruby', 'r+') do |pipe|
5920 * puts pipe.closed?
5921 * pipe.close_write
5922 * puts pipe.closed?
5923 * pipe.close_read
5924 * puts $?
5925 * puts pipe.closed?
5926 * end
5927 *
5928 * Output:
5929 *
5930 * false
5931 * false
5932 * pid 14748 exit 0
5933 * true
5934 *
5935 * Related: IO#close, IO#close_write, IO#closed?.
5936 */
5937
5938static VALUE
5939rb_io_close_read(VALUE io)
5940{
5941 rb_io_t *fptr;
5942 VALUE write_io;
5943
5944 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5945 if (fptr->fd < 0) return Qnil;
5946 if (is_socket(fptr->fd, fptr->pathv)) {
5947#ifndef SHUT_RD
5948# define SHUT_RD 0
5949#endif
5950 if (shutdown(fptr->fd, SHUT_RD) < 0)
5951 rb_sys_fail_path(fptr->pathv);
5952 fptr->mode &= ~FMODE_READABLE;
5953 if (!(fptr->mode & FMODE_WRITABLE))
5954 return rb_io_close(io);
5955 return Qnil;
5956 }
5957
5958 write_io = GetWriteIO(io);
5959 if (io != write_io) {
5960 rb_io_t *wfptr;
5961 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5962 wfptr->pid = fptr->pid;
5963 fptr->pid = 0;
5964 RFILE(io)->fptr = wfptr;
5965 /* bind to write_io temporarily to get rid of memory/fd leak */
5966 fptr->tied_io_for_writing = 0;
5967 RFILE(write_io)->fptr = fptr;
5968 rb_io_fptr_cleanup(fptr, FALSE);
5969 /* should not finalize fptr because another thread may be reading it */
5970 return Qnil;
5971 }
5972
5973 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5974 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5975 }
5976 return rb_io_close(io);
5977}
5978
5979/*
5980 * call-seq:
5981 * close_write -> nil
5982 *
5983 * Closes the stream for writing if open for writing;
5984 * returns +nil+.
5985 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5986 *
5987 * Flushes any buffered writes to the operating system before closing.
5988 *
5989 * If the stream was opened by IO.popen and is also closed for reading,
5990 * sets global variable <tt>$?</tt> (child exit status).
5991 *
5992 * IO.popen('ruby', 'r+') do |pipe|
5993 * puts pipe.closed?
5994 * pipe.close_read
5995 * puts pipe.closed?
5996 * pipe.close_write
5997 * puts $?
5998 * puts pipe.closed?
5999 * end
6000 *
6001 * Output:
6002 *
6003 * false
6004 * false
6005 * pid 15044 exit 0
6006 * true
6007 *
6008 * Related: IO#close, IO#close_read, IO#closed?.
6009 */
6010
6011static VALUE
6012rb_io_close_write(VALUE io)
6013{
6014 rb_io_t *fptr;
6015 VALUE write_io;
6016
6017 write_io = GetWriteIO(io);
6018 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6019 if (fptr->fd < 0) return Qnil;
6020 if (is_socket(fptr->fd, fptr->pathv)) {
6021#ifndef SHUT_WR
6022# define SHUT_WR 1
6023#endif
6024 if (shutdown(fptr->fd, SHUT_WR) < 0)
6025 rb_sys_fail_path(fptr->pathv);
6026 fptr->mode &= ~FMODE_WRITABLE;
6027 if (!(fptr->mode & FMODE_READABLE))
6028 return rb_io_close(write_io);
6029 return Qnil;
6030 }
6031
6032 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6033 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6034 }
6035
6036 if (io != write_io) {
6037 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6038 fptr->tied_io_for_writing = 0;
6039 }
6040 rb_io_close(write_io);
6041 return Qnil;
6042}
6043
6044/*
6045 * call-seq:
6046 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6047 *
6048 * Behaves like IO#seek, except that it:
6049 *
6050 * - Uses low-level system functions.
6051 * - Returns the new position.
6052 *
6053 */
6054
6055static VALUE
6056rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6057{
6058 VALUE offset, ptrname;
6059 int whence = SEEK_SET;
6060 rb_io_t *fptr;
6061 rb_off_t pos;
6062
6063 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6064 whence = interpret_seek_whence(ptrname);
6065 }
6066 pos = NUM2OFFT(offset);
6067 GetOpenFile(io, fptr);
6068 if ((fptr->mode & FMODE_READABLE) &&
6069 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6070 rb_raise(rb_eIOError, "sysseek for buffered IO");
6071 }
6072 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6073 rb_warn("sysseek for buffered IO");
6074 }
6075 errno = 0;
6076 pos = lseek(fptr->fd, pos, whence);
6077 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6078
6079 return OFFT2NUM(pos);
6080}
6081
6082/*
6083 * call-seq:
6084 * syswrite(object) -> integer
6085 *
6086 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6087 * returns the number bytes written.
6088 * If +object+ is not a string is converted via method to_s:
6089 *
6090 * f = File.new('t.tmp', 'w')
6091 * f.syswrite('foo') # => 3
6092 * f.syswrite(30) # => 2
6093 * f.syswrite(:foo) # => 3
6094 * f.close
6095 *
6096 * This methods should not be used with other stream-writer methods.
6097 *
6098 */
6099
6100static VALUE
6101rb_io_syswrite(VALUE io, VALUE str)
6102{
6103 VALUE tmp;
6104 rb_io_t *fptr;
6105 long n, len;
6106 const char *ptr;
6107
6108 if (!RB_TYPE_P(str, T_STRING))
6109 str = rb_obj_as_string(str);
6110
6111 io = GetWriteIO(io);
6112 GetOpenFile(io, fptr);
6114
6115 if (fptr->wbuf.len) {
6116 rb_warn("syswrite for buffered IO");
6117 }
6118
6119 tmp = rb_str_tmp_frozen_acquire(str);
6120 RSTRING_GETMEM(tmp, ptr, len);
6121 n = rb_io_write_memory(fptr, ptr, len);
6122 if (n < 0) rb_sys_fail_path(fptr->pathv);
6123 rb_str_tmp_frozen_release(str, tmp);
6124
6125 return LONG2FIX(n);
6126}
6127
6128/*
6129 * call-seq:
6130 * sysread(maxlen) -> string
6131 * sysread(maxlen, out_string) -> string
6132 *
6133 * Behaves like IO#readpartial, except that it uses low-level system functions.
6134 *
6135 * This method should not be used with other stream-reader methods.
6136 *
6137 */
6138
6139static VALUE
6140rb_io_sysread(int argc, VALUE *argv, VALUE io)
6141{
6142 VALUE len, str;
6143 rb_io_t *fptr;
6144 long n, ilen;
6145 struct io_internal_read_struct iis;
6146 int shrinkable;
6147
6148 rb_scan_args(argc, argv, "11", &len, &str);
6149 ilen = NUM2LONG(len);
6150
6151 shrinkable = io_setstrbuf(&str, ilen);
6152 if (ilen == 0) return str;
6153
6154 GetOpenFile(io, fptr);
6156
6157 if (READ_DATA_BUFFERED(fptr)) {
6158 rb_raise(rb_eIOError, "sysread for buffered IO");
6159 }
6160
6161 rb_io_check_closed(fptr);
6162
6163 io_setstrbuf(&str, ilen);
6164 iis.th = rb_thread_current();
6165 iis.fptr = fptr;
6166 iis.nonblock = 0;
6167 iis.fd = fptr->fd;
6168 iis.buf = RSTRING_PTR(str);
6169 iis.capa = ilen;
6170 iis.timeout = NULL;
6171 n = io_read_memory_locktmp(str, &iis);
6172
6173 if (n < 0) {
6174 rb_sys_fail_path(fptr->pathv);
6175 }
6176
6177 io_set_read_length(str, n, shrinkable);
6178
6179 if (n == 0 && ilen > 0) {
6180 rb_eof_error();
6181 }
6182
6183 return str;
6184}
6185
6187 struct rb_io *io;
6188 int fd;
6189 void *buf;
6190 size_t count;
6191 rb_off_t offset;
6192};
6193
6194static VALUE
6195internal_pread_func(void *_arg)
6196{
6197 struct prdwr_internal_arg *arg = _arg;
6198
6199 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6200}
6201
6202static VALUE
6203pread_internal_call(VALUE _arg)
6204{
6205 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6206
6207 VALUE scheduler = rb_fiber_scheduler_current();
6208 if (scheduler != Qnil) {
6209 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6210
6211 if (!UNDEF_P(result)) {
6213 }
6214 }
6215
6216 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6217}
6218
6219/*
6220 * call-seq:
6221 * pread(maxlen, offset) -> string
6222 * pread(maxlen, offset, out_string) -> string
6223 *
6224 * Behaves like IO#readpartial, except that it:
6225 *
6226 * - Reads at the given +offset+ (in bytes).
6227 * - Disregards, and does not modify, the stream's position
6228 * (see {Position}[rdoc-ref:IO@Position]).
6229 * - Bypasses any user space buffering in the stream.
6230 *
6231 * Because this method does not disturb the stream's state
6232 * (its position, in particular), +pread+ allows multiple threads and processes
6233 * to use the same \IO object for reading at various offsets.
6234 *
6235 * f = File.open('t.txt')
6236 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6237 * f.pos # => 52
6238 * # Read 12 bytes at offset 0.
6239 * f.pread(12, 0) # => "First line\n"
6240 * # Read 9 bytes at offset 8.
6241 * f.pread(9, 8) # => "ne\nSecon"
6242 * f.close
6243 *
6244 * Not available on some platforms.
6245 *
6246 */
6247static VALUE
6248rb_io_pread(int argc, VALUE *argv, VALUE io)
6249{
6250 VALUE len, offset, str;
6251 rb_io_t *fptr;
6252 ssize_t n;
6253 struct prdwr_internal_arg arg;
6254 int shrinkable;
6255
6256 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6257 arg.count = NUM2SIZET(len);
6258 arg.offset = NUM2OFFT(offset);
6259
6260 shrinkable = io_setstrbuf(&str, (long)arg.count);
6261 if (arg.count == 0) return str;
6262 arg.buf = RSTRING_PTR(str);
6263
6264 GetOpenFile(io, fptr);
6266
6267 arg.io = fptr;
6268 arg.fd = fptr->fd;
6269 rb_io_check_closed(fptr);
6270
6271 rb_str_locktmp(str);
6272 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6273
6274 if (n < 0) {
6275 rb_sys_fail_path(fptr->pathv);
6276 }
6277 io_set_read_length(str, n, shrinkable);
6278 if (n == 0 && arg.count > 0) {
6279 rb_eof_error();
6280 }
6281
6282 return str;
6283}
6284
6285static VALUE
6286internal_pwrite_func(void *_arg)
6287{
6288 struct prdwr_internal_arg *arg = _arg;
6289
6290 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6291}
6292
6293static VALUE
6294pwrite_internal_call(VALUE _arg)
6295{
6296 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6297
6298 VALUE scheduler = rb_fiber_scheduler_current();
6299 if (scheduler != Qnil) {
6300 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6301
6302 if (!UNDEF_P(result)) {
6304 }
6305 }
6306
6307 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
6308}
6309
6310/*
6311 * call-seq:
6312 * pwrite(object, offset) -> integer
6313 *
6314 * Behaves like IO#write, except that it:
6315 *
6316 * - Writes at the given +offset+ (in bytes).
6317 * - Disregards, and does not modify, the stream's position
6318 * (see {Position}[rdoc-ref:IO@Position]).
6319 * - Bypasses any user space buffering in the stream.
6320 *
6321 * Because this method does not disturb the stream's state
6322 * (its position, in particular), +pwrite+ allows multiple threads and processes
6323 * to use the same \IO object for writing at various offsets.
6324 *
6325 * f = File.open('t.tmp', 'w+')
6326 * # Write 6 bytes at offset 3.
6327 * f.pwrite('ABCDEF', 3) # => 6
6328 * f.rewind
6329 * f.read # => "\u0000\u0000\u0000ABCDEF"
6330 * f.close
6331 *
6332 * Not available on some platforms.
6333 *
6334 */
6335static VALUE
6336rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6337{
6338 rb_io_t *fptr;
6339 ssize_t n;
6340 struct prdwr_internal_arg arg;
6341 VALUE tmp;
6342
6343 if (!RB_TYPE_P(str, T_STRING))
6344 str = rb_obj_as_string(str);
6345
6346 arg.offset = NUM2OFFT(offset);
6347
6348 io = GetWriteIO(io);
6349 GetOpenFile(io, fptr);
6351
6352 arg.io = fptr;
6353 arg.fd = fptr->fd;
6354
6355 tmp = rb_str_tmp_frozen_acquire(str);
6356 arg.buf = RSTRING_PTR(tmp);
6357 arg.count = (size_t)RSTRING_LEN(tmp);
6358
6359 n = (ssize_t)pwrite_internal_call((VALUE)&arg);
6360 if (n < 0) rb_sys_fail_path(fptr->pathv);
6361 rb_str_tmp_frozen_release(str, tmp);
6362
6363 return SSIZET2NUM(n);
6364}
6365
6366VALUE
6368{
6369 rb_io_t *fptr;
6370
6371 GetOpenFile(io, fptr);
6372 if (fptr->readconv)
6374 if (fptr->writeconv)
6376 fptr->mode |= FMODE_BINMODE;
6377 fptr->mode &= ~FMODE_TEXTMODE;
6378 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6379#ifdef O_BINARY
6380 if (!fptr->readconv) {
6381 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6382 }
6383 else {
6384 setmode(fptr->fd, O_BINARY);
6385 }
6386#endif
6387 return io;
6388}
6389
6390static void
6391io_ascii8bit_binmode(rb_io_t *fptr)
6392{
6393 if (fptr->readconv) {
6394 rb_econv_close(fptr->readconv);
6395 fptr->readconv = NULL;
6396 }
6397 if (fptr->writeconv) {
6399 fptr->writeconv = NULL;
6400 }
6401 fptr->mode |= FMODE_BINMODE;
6402 fptr->mode &= ~FMODE_TEXTMODE;
6403 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6404
6405 fptr->encs.enc = rb_ascii8bit_encoding();
6406 fptr->encs.enc2 = NULL;
6407 fptr->encs.ecflags = 0;
6408 fptr->encs.ecopts = Qnil;
6409 clear_codeconv(fptr);
6410}
6411
6412VALUE
6414{
6415 rb_io_t *fptr;
6416
6417 GetOpenFile(io, fptr);
6418 io_ascii8bit_binmode(fptr);
6419
6420 return io;
6421}
6422
6423/*
6424 * call-seq:
6425 * binmode -> self
6426 *
6427 * Sets the stream's data mode as binary
6428 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6429 *
6430 * A stream's data mode may not be changed from binary to text.
6431 *
6432 */
6433
6434static VALUE
6435rb_io_binmode_m(VALUE io)
6436{
6437 VALUE write_io;
6438
6440
6441 write_io = GetWriteIO(io);
6442 if (write_io != io)
6443 rb_io_ascii8bit_binmode(write_io);
6444 return io;
6445}
6446
6447/*
6448 * call-seq:
6449 * binmode? -> true or false
6450 *
6451 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6452 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6453 *
6454 */
6455static VALUE
6456rb_io_binmode_p(VALUE io)
6457{
6458 rb_io_t *fptr;
6459 GetOpenFile(io, fptr);
6460 return RBOOL(fptr->mode & FMODE_BINMODE);
6461}
6462
6463static const char*
6464rb_io_fmode_modestr(enum rb_io_mode fmode)
6465{
6466 if (fmode & FMODE_APPEND) {
6467 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6468 return MODE_BTMODE("a+", "ab+", "at+");
6469 }
6470 return MODE_BTMODE("a", "ab", "at");
6471 }
6472 switch (fmode & FMODE_READWRITE) {
6473 default:
6474 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6475 case FMODE_READABLE:
6476 return MODE_BTMODE("r", "rb", "rt");
6477 case FMODE_WRITABLE:
6478 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6479 case FMODE_READWRITE:
6480 if (fmode & FMODE_CREATE) {
6481 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6482 }
6483 return MODE_BTMODE("r+", "rb+", "rt+");
6484 }
6485}
6486
6487static const char bom_prefix[] = "bom|";
6488static const char utf_prefix[] = "utf-";
6489enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6490enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6491
6492static int
6493io_encname_bom_p(const char *name, long len)
6494{
6495 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6496}
6497
6498enum rb_io_mode
6499rb_io_modestr_fmode(const char *modestr)
6500{
6501 enum rb_io_mode fmode = 0;
6502 const char *m = modestr, *p = NULL;
6503
6504 switch (*m++) {
6505 case 'r':
6506 fmode |= FMODE_READABLE;
6507 break;
6508 case 'w':
6510 break;
6511 case 'a':
6513 break;
6514 default:
6515 goto error;
6516 }
6517
6518 while (*m) {
6519 switch (*m++) {
6520 case 'b':
6521 fmode |= FMODE_BINMODE;
6522 break;
6523 case 't':
6524 fmode |= FMODE_TEXTMODE;
6525 break;
6526 case '+':
6527 fmode |= FMODE_READWRITE;
6528 break;
6529 case 'x':
6530 if (modestr[0] != 'w')
6531 goto error;
6532 fmode |= FMODE_EXCL;
6533 break;
6534 default:
6535 goto error;
6536 case ':':
6537 p = strchr(m, ':');
6538 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6539 fmode |= FMODE_SETENC_BY_BOM;
6540 goto finished;
6541 }
6542 }
6543
6544 finished:
6545 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6546 goto error;
6547
6548 return fmode;
6549
6550 error:
6551 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6553}
6554
6555int
6556rb_io_oflags_fmode(int oflags)
6557{
6558 enum rb_io_mode fmode = 0;
6559
6560 switch (oflags & O_ACCMODE) {
6561 case O_RDONLY:
6562 fmode = FMODE_READABLE;
6563 break;
6564 case O_WRONLY:
6565 fmode = FMODE_WRITABLE;
6566 break;
6567 case O_RDWR:
6568 fmode = FMODE_READWRITE;
6569 break;
6570 }
6571
6572 if (oflags & O_APPEND) {
6573 fmode |= FMODE_APPEND;
6574 }
6575 if (oflags & O_TRUNC) {
6576 fmode |= FMODE_TRUNC;
6577 }
6578 if (oflags & O_CREAT) {
6579 fmode |= FMODE_CREATE;
6580 }
6581 if (oflags & O_EXCL) {
6582 fmode |= FMODE_EXCL;
6583 }
6584#ifdef O_BINARY
6585 if (oflags & O_BINARY) {
6586 fmode |= FMODE_BINMODE;
6587 }
6588#endif
6589
6590 return fmode;
6591}
6592
6593static int
6594rb_io_fmode_oflags(enum rb_io_mode fmode)
6595{
6596 int oflags = 0;
6597
6598 switch (fmode & FMODE_READWRITE) {
6599 case FMODE_READABLE:
6600 oflags |= O_RDONLY;
6601 break;
6602 case FMODE_WRITABLE:
6603 oflags |= O_WRONLY;
6604 break;
6605 case FMODE_READWRITE:
6606 oflags |= O_RDWR;
6607 break;
6608 }
6609
6610 if (fmode & FMODE_APPEND) {
6611 oflags |= O_APPEND;
6612 }
6613 if (fmode & FMODE_TRUNC) {
6614 oflags |= O_TRUNC;
6615 }
6616 if (fmode & FMODE_CREATE) {
6617 oflags |= O_CREAT;
6618 }
6619 if (fmode & FMODE_EXCL) {
6620 oflags |= O_EXCL;
6621 }
6622#ifdef O_BINARY
6623 if (fmode & FMODE_BINMODE) {
6624 oflags |= O_BINARY;
6625 }
6626#endif
6627
6628 return oflags;
6629}
6630
6631int
6632rb_io_modestr_oflags(const char *modestr)
6633{
6634 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6635}
6636
6637static const char*
6638rb_io_oflags_modestr(int oflags)
6639{
6640#ifdef O_BINARY
6641# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6642#else
6643# define MODE_BINARY(a,b) (a)
6644#endif
6645 int accmode;
6646 if (oflags & O_EXCL) {
6647 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6648 }
6649 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6650 if (oflags & O_APPEND) {
6651 if (accmode == O_WRONLY) {
6652 return MODE_BINARY("a", "ab");
6653 }
6654 if (accmode == O_RDWR) {
6655 return MODE_BINARY("a+", "ab+");
6656 }
6657 }
6658 switch (accmode) {
6659 default:
6660 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6661 case O_RDONLY:
6662 return MODE_BINARY("r", "rb");
6663 case O_WRONLY:
6664 return MODE_BINARY("w", "wb");
6665 case O_RDWR:
6666 if (oflags & O_TRUNC) {
6667 return MODE_BINARY("w+", "wb+");
6668 }
6669 return MODE_BINARY("r+", "rb+");
6670 }
6671}
6672
6673/*
6674 * Convert external/internal encodings to enc/enc2
6675 * NULL => use default encoding
6676 * Qnil => no encoding specified (internal only)
6677 */
6678static void
6679rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6680{
6681 int default_ext = 0;
6682
6683 if (ext == NULL) {
6684 ext = rb_default_external_encoding();
6685 default_ext = 1;
6686 }
6687 if (rb_is_ascii8bit_enc(ext)) {
6688 /* If external is ASCII-8BIT, no transcoding */
6689 intern = NULL;
6690 }
6691 else if (intern == NULL) {
6692 intern = rb_default_internal_encoding();
6693 }
6694 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6695 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6696 /* No internal encoding => use external + no transcoding */
6697 *enc = (default_ext && intern != ext) ? NULL : ext;
6698 *enc2 = NULL;
6699 }
6700 else {
6701 *enc = intern;
6702 *enc2 = ext;
6703 }
6704}
6705
6706static void
6707unsupported_encoding(const char *name, rb_encoding *enc)
6708{
6709 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6710}
6711
6712static void
6713parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6714 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6715{
6716 const char *p;
6717 char encname[ENCODING_MAXNAMELEN+1];
6718 int idx, idx2;
6719 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6720 rb_encoding *ext_enc, *int_enc;
6721 long len;
6722
6723 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6724
6725 p = strrchr(estr, ':');
6726 len = p ? (p++ - estr) : (long)strlen(estr);
6727 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6728 estr += bom_prefix_len;
6729 len -= bom_prefix_len;
6730 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6731 fmode |= FMODE_SETENC_BY_BOM;
6732 }
6733 else {
6734 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6735 fmode &= ~FMODE_SETENC_BY_BOM;
6736 }
6737 }
6738 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6739 idx = -1;
6740 }
6741 else {
6742 if (p) {
6743 memcpy(encname, estr, len);
6744 encname[len] = '\0';
6745 estr = encname;
6746 }
6747 idx = rb_enc_find_index(estr);
6748 }
6749 if (fmode_p) *fmode_p = fmode;
6750
6751 if (idx >= 0)
6752 ext_enc = rb_enc_from_index(idx);
6753 else {
6754 if (idx != -2)
6755 unsupported_encoding(estr, estr_enc);
6756 ext_enc = NULL;
6757 }
6758
6759 int_enc = NULL;
6760 if (p) {
6761 if (*p == '-' && *(p+1) == '\0') {
6762 /* Special case - "-" => no transcoding */
6763 int_enc = (rb_encoding *)Qnil;
6764 }
6765 else {
6766 idx2 = rb_enc_find_index(p);
6767 if (idx2 < 0)
6768 unsupported_encoding(p, estr_enc);
6769 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6770 int_enc = (rb_encoding *)Qnil;
6771 }
6772 else
6773 int_enc = rb_enc_from_index(idx2);
6774 }
6775 }
6776
6777 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6778}
6779
6780int
6781rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6782{
6783 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6784 int extracted = 0;
6785 rb_encoding *extencoding = NULL;
6786 rb_encoding *intencoding = NULL;
6787
6788 if (!NIL_P(opt)) {
6789 VALUE v;
6790 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6791 if (v != Qnil) encoding = v;
6792 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6793 if (v != Qnil) extenc = v;
6794 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6795 if (!UNDEF_P(v)) intenc = v;
6796 }
6797 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6798 if (!NIL_P(ruby_verbose)) {
6799 int idx = rb_to_encoding_index(encoding);
6800 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6801 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6802 encoding, UNDEF_P(extenc) ? "internal" : "external");
6803 }
6804 encoding = Qnil;
6805 }
6806 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6807 extencoding = rb_to_encoding(extenc);
6808 }
6809 if (!UNDEF_P(intenc)) {
6810 if (NIL_P(intenc)) {
6811 /* internal_encoding: nil => no transcoding */
6812 intencoding = (rb_encoding *)Qnil;
6813 }
6814 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6815 char *p = StringValueCStr(tmp);
6816
6817 if (*p == '-' && *(p+1) == '\0') {
6818 /* Special case - "-" => no transcoding */
6819 intencoding = (rb_encoding *)Qnil;
6820 }
6821 else {
6822 intencoding = rb_to_encoding(intenc);
6823 }
6824 }
6825 else {
6826 intencoding = rb_to_encoding(intenc);
6827 }
6828 if (extencoding == intencoding) {
6829 intencoding = (rb_encoding *)Qnil;
6830 }
6831 }
6832 if (!NIL_P(encoding)) {
6833 extracted = 1;
6834 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6835 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6836 enc_p, enc2_p, fmode_p);
6837 }
6838 else {
6839 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6840 }
6841 }
6842 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6843 extracted = 1;
6844 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6845 }
6846 return extracted;
6847}
6848
6849static void
6850validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6851{
6852 enum rb_io_mode fmode = *fmode_p;
6853
6854 if ((fmode & FMODE_READABLE) &&
6855 !enc2 &&
6856 !(fmode & FMODE_BINMODE) &&
6857 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6858 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6859
6860 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6861 rb_raise(rb_eArgError, "newline decorator with binary mode");
6862 }
6863 if (!(fmode & FMODE_BINMODE) &&
6864 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6865 fmode |= FMODE_TEXTMODE;
6866 *fmode_p = fmode;
6867 }
6868#if !DEFAULT_TEXTMODE
6869 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6870 fmode &= ~FMODE_TEXTMODE;
6871 *fmode_p = fmode;
6872 }
6873#endif
6874}
6875
6876static void
6877extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
6878{
6879 if (!NIL_P(opthash)) {
6880 VALUE v;
6881 v = rb_hash_aref(opthash, sym_textmode);
6882 if (!NIL_P(v)) {
6883 if (*fmode & FMODE_TEXTMODE)
6884 rb_raise(rb_eArgError, "textmode specified twice");
6885 if (*fmode & FMODE_BINMODE)
6886 rb_raise(rb_eArgError, "both textmode and binmode specified");
6887 if (RTEST(v))
6888 *fmode |= FMODE_TEXTMODE;
6889 }
6890 v = rb_hash_aref(opthash, sym_binmode);
6891 if (!NIL_P(v)) {
6892 if (*fmode & FMODE_BINMODE)
6893 rb_raise(rb_eArgError, "binmode specified twice");
6894 if (*fmode & FMODE_TEXTMODE)
6895 rb_raise(rb_eArgError, "both textmode and binmode specified");
6896 if (RTEST(v))
6897 *fmode |= FMODE_BINMODE;
6898 }
6899
6900 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6901 rb_raise(rb_eArgError, "both textmode and binmode specified");
6902 }
6903}
6904
6905void
6906rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6907 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
6908{
6909 VALUE vmode;
6910 int oflags;
6911 enum rb_io_mode fmode;
6912 rb_encoding *enc, *enc2;
6913 int ecflags;
6914 VALUE ecopts;
6915 int has_enc = 0, has_vmode = 0;
6916 VALUE intmode;
6917
6918 vmode = *vmode_p;
6919
6920 /* Set to defaults */
6921 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6922
6923 vmode_handle:
6924 if (NIL_P(vmode)) {
6925 fmode = FMODE_READABLE;
6926 oflags = O_RDONLY;
6927 }
6928 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6929 vmode = intmode;
6930 oflags = NUM2INT(intmode);
6931 fmode = rb_io_oflags_fmode(oflags);
6932 }
6933 else {
6934 const char *p;
6935
6936 StringValue(vmode);
6937 p = StringValueCStr(vmode);
6938 fmode = rb_io_modestr_fmode(p);
6939 oflags = rb_io_fmode_oflags(fmode);
6940 p = strchr(p, ':');
6941 if (p) {
6942 has_enc = 1;
6943 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6944 }
6945 else {
6946 rb_encoding *e;
6947
6948 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6949 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6950 }
6951 }
6952
6953 if (NIL_P(opthash)) {
6954 ecflags = (fmode & FMODE_READABLE) ?
6957#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6958 ecflags |= (fmode & FMODE_WRITABLE) ?
6959 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6960 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6961#endif
6962 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6963 ecopts = Qnil;
6964 if (fmode & FMODE_BINMODE) {
6965#ifdef O_BINARY
6966 oflags |= O_BINARY;
6967#endif
6968 if (!has_enc)
6969 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6970 }
6971#if DEFAULT_TEXTMODE
6972 else if (NIL_P(vmode)) {
6973 fmode |= DEFAULT_TEXTMODE;
6974 }
6975#endif
6976 }
6977 else {
6978 VALUE v;
6979 if (!has_vmode) {
6980 v = rb_hash_aref(opthash, sym_mode);
6981 if (!NIL_P(v)) {
6982 if (!NIL_P(vmode)) {
6983 rb_raise(rb_eArgError, "mode specified twice");
6984 }
6985 has_vmode = 1;
6986 vmode = v;
6987 goto vmode_handle;
6988 }
6989 }
6990 v = rb_hash_aref(opthash, sym_flags);
6991 if (!NIL_P(v)) {
6992 v = rb_to_int(v);
6993 oflags |= NUM2INT(v);
6994 vmode = INT2NUM(oflags);
6995 fmode = rb_io_oflags_fmode(oflags);
6996 }
6997 extract_binmode(opthash, &fmode);
6998 if (fmode & FMODE_BINMODE) {
6999#ifdef O_BINARY
7000 oflags |= O_BINARY;
7001#endif
7002 if (!has_enc)
7003 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7004 }
7005#if DEFAULT_TEXTMODE
7006 else if (NIL_P(vmode)) {
7007 fmode |= DEFAULT_TEXTMODE;
7008 }
7009#endif
7010 v = rb_hash_aref(opthash, sym_perm);
7011 if (!NIL_P(v)) {
7012 if (vperm_p) {
7013 if (!NIL_P(*vperm_p)) {
7014 rb_raise(rb_eArgError, "perm specified twice");
7015 }
7016 *vperm_p = v;
7017 }
7018 else {
7019 /* perm no use, just ignore */
7020 }
7021 }
7022 ecflags = (fmode & FMODE_READABLE) ?
7025#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7026 ecflags |= (fmode & FMODE_WRITABLE) ?
7027 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7028 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7029#endif
7030
7031 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7032 if (has_enc) {
7033 rb_raise(rb_eArgError, "encoding specified twice");
7034 }
7035 }
7036 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7037 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7038 }
7039
7040 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7041
7042 *vmode_p = vmode;
7043
7044 *oflags_p = oflags;
7045 *fmode_p = fmode;
7046 convconfig_p->enc = enc;
7047 convconfig_p->enc2 = enc2;
7048 convconfig_p->ecflags = ecflags;
7049 convconfig_p->ecopts = ecopts;
7050}
7051
7053 VALUE fname;
7054 int oflags;
7055 mode_t perm;
7056};
7057
7058static void *
7059sysopen_func(void *ptr)
7060{
7061 const struct sysopen_struct *data = ptr;
7062 const char *fname = RSTRING_PTR(data->fname);
7063 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7064}
7065
7066static inline int
7067rb_sysopen_internal(struct sysopen_struct *data)
7068{
7069 int fd;
7070 do {
7071 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7072 } while (fd < 0 && errno == EINTR);
7073 if (0 <= fd)
7074 rb_update_max_fd(fd);
7075 return fd;
7076}
7077
7078static int
7079rb_sysopen(VALUE fname, int oflags, mode_t perm)
7080{
7081 int fd = -1;
7082 struct sysopen_struct data;
7083
7084 data.fname = rb_str_encode_ospath(fname);
7085 StringValueCStr(data.fname);
7086 data.oflags = oflags;
7087 data.perm = perm;
7088
7089 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7090 rb_syserr_fail_path(first_errno, fname);
7091 }
7092 return fd;
7093}
7094
7095static inline FILE *
7096fdopen_internal(int fd, const char *modestr)
7097{
7098 FILE *file;
7099
7100#if defined(__sun)
7101 errno = 0;
7102#endif
7103 file = fdopen(fd, modestr);
7104 if (!file) {
7105#ifdef _WIN32
7106 if (errno == 0) errno = EINVAL;
7107#elif defined(__sun)
7108 if (errno == 0) errno = EMFILE;
7109#endif
7110 }
7111 return file;
7112}
7113
7114FILE *
7115rb_fdopen(int fd, const char *modestr)
7116{
7117 FILE *file = 0;
7118
7119 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7120 rb_syserr_fail(first_errno, 0);
7121 }
7122
7123 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7124#ifdef USE_SETVBUF
7125 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7126 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7127#endif
7128 return file;
7129}
7130
7131static int
7132io_check_tty(rb_io_t *fptr)
7133{
7134 int t = isatty(fptr->fd);
7135 if (t)
7136 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7137 return t;
7138}
7139
7140static VALUE rb_io_internal_encoding(VALUE);
7141static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7142
7143static int
7144io_strip_bom(VALUE io)
7145{
7146 VALUE b1, b2, b3, b4;
7147 rb_io_t *fptr;
7148
7149 GetOpenFile(io, fptr);
7150 if (!(fptr->mode & FMODE_READABLE)) return 0;
7151 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7152 switch (b1) {
7153 case INT2FIX(0xEF):
7154 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7155 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7156 if (b3 == INT2FIX(0xBF)) {
7157 return rb_utf8_encindex();
7158 }
7159 rb_io_ungetbyte(io, b3);
7160 }
7161 rb_io_ungetbyte(io, b2);
7162 break;
7163
7164 case INT2FIX(0xFE):
7165 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7166 if (b2 == INT2FIX(0xFF)) {
7167 return ENCINDEX_UTF_16BE;
7168 }
7169 rb_io_ungetbyte(io, b2);
7170 break;
7171
7172 case INT2FIX(0xFF):
7173 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7174 if (b2 == INT2FIX(0xFE)) {
7175 b3 = rb_io_getbyte(io);
7176 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7177 if (b4 == INT2FIX(0)) {
7178 return ENCINDEX_UTF_32LE;
7179 }
7180 rb_io_ungetbyte(io, b4);
7181 }
7182 rb_io_ungetbyte(io, b3);
7183 return ENCINDEX_UTF_16LE;
7184 }
7185 rb_io_ungetbyte(io, b2);
7186 break;
7187
7188 case INT2FIX(0):
7189 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7190 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7191 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7192 if (b4 == INT2FIX(0xFF)) {
7193 return ENCINDEX_UTF_32BE;
7194 }
7195 rb_io_ungetbyte(io, b4);
7196 }
7197 rb_io_ungetbyte(io, b3);
7198 }
7199 rb_io_ungetbyte(io, b2);
7200 break;
7201 }
7202 rb_io_ungetbyte(io, b1);
7203 return 0;
7204}
7205
7206static rb_encoding *
7207io_set_encoding_by_bom(VALUE io)
7208{
7209 int idx = io_strip_bom(io);
7210 rb_io_t *fptr;
7211 rb_encoding *extenc = NULL;
7212
7213 GetOpenFile(io, fptr);
7214 if (idx) {
7215 extenc = rb_enc_from_index(idx);
7216 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7217 rb_io_internal_encoding(io), Qnil);
7218 }
7219 else {
7220 fptr->encs.enc2 = NULL;
7221 }
7222 return extenc;
7223}
7224
7225static VALUE
7226rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7227 const struct rb_io_encoding *convconfig, mode_t perm)
7228{
7229 VALUE pathv;
7230 rb_io_t *fptr;
7231 struct rb_io_encoding cc;
7232 if (!convconfig) {
7233 /* Set to default encodings */
7234 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7235 cc.ecflags = 0;
7236 cc.ecopts = Qnil;
7237 convconfig = &cc;
7238 }
7239 validate_enc_binmode(&fmode, convconfig->ecflags,
7240 convconfig->enc, convconfig->enc2);
7241
7242 MakeOpenFile(io, fptr);
7243 fptr->mode = fmode;
7244 fptr->encs = *convconfig;
7245 pathv = rb_str_new_frozen(filename);
7246#ifdef O_TMPFILE
7247 if (!(oflags & O_TMPFILE)) {
7248 fptr->pathv = pathv;
7249 }
7250#else
7251 fptr->pathv = pathv;
7252#endif
7253 fptr->fd = rb_sysopen(pathv, oflags, perm);
7254 io_check_tty(fptr);
7255 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7256
7257 return io;
7258}
7259
7260static VALUE
7261rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7262{
7263 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7264 const char *p = strchr(modestr, ':');
7265 struct rb_io_encoding convconfig;
7266
7267 if (p) {
7268 parse_mode_enc(p+1, rb_usascii_encoding(),
7269 &convconfig.enc, &convconfig.enc2, &fmode);
7270 }
7271 else {
7272 rb_encoding *e;
7273 /* Set to default encodings */
7274
7275 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7276 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7277 }
7278
7279 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7282#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7283 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7284 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7285 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7286#endif
7287 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7288 convconfig.ecopts = Qnil;
7289
7290 return rb_file_open_generic(io, filename,
7291 rb_io_fmode_oflags(fmode),
7292 fmode,
7293 &convconfig,
7294 0666);
7295}
7296
7297VALUE
7298rb_file_open_str(VALUE fname, const char *modestr)
7299{
7300 FilePathValue(fname);
7301 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7302}
7303
7304VALUE
7305rb_file_open(const char *fname, const char *modestr)
7306{
7307 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7308}
7309
7310#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7311static struct pipe_list {
7312 rb_io_t *fptr;
7313 struct pipe_list *next;
7314} *pipe_list;
7315
7316static void
7317pipe_add_fptr(rb_io_t *fptr)
7318{
7319 struct pipe_list *list;
7320
7321 list = ALLOC(struct pipe_list);
7322 list->fptr = fptr;
7323 list->next = pipe_list;
7324 pipe_list = list;
7325}
7326
7327static void
7328pipe_del_fptr(rb_io_t *fptr)
7329{
7330 struct pipe_list **prev = &pipe_list;
7331 struct pipe_list *tmp;
7332
7333 while ((tmp = *prev) != 0) {
7334 if (tmp->fptr == fptr) {
7335 *prev = tmp->next;
7336 free(tmp);
7337 return;
7338 }
7339 prev = &tmp->next;
7340 }
7341}
7342
7343#if defined (_WIN32) || defined(__CYGWIN__)
7344static void
7345pipe_atexit(void)
7346{
7347 struct pipe_list *list = pipe_list;
7348 struct pipe_list *tmp;
7349
7350 while (list) {
7351 tmp = list->next;
7352 rb_io_fptr_finalize(list->fptr);
7353 list = tmp;
7354 }
7355}
7356#endif
7357
7358static void
7359pipe_finalize(rb_io_t *fptr, int noraise)
7360{
7361#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7362 int status = 0;
7363 if (fptr->stdio_file) {
7364 status = pclose(fptr->stdio_file);
7365 }
7366 fptr->fd = -1;
7367 fptr->stdio_file = 0;
7368 rb_last_status_set(status, fptr->pid);
7369#else
7370 fptr_finalize(fptr, noraise);
7371#endif
7372 pipe_del_fptr(fptr);
7373}
7374#endif
7375
7376static void
7377fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7378{
7379#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7380 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7381
7382 if (old_finalize == orig->finalize) return;
7383#endif
7384
7385 fptr->finalize = orig->finalize;
7386
7387#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7388 if (old_finalize != pipe_finalize) {
7389 struct pipe_list *list;
7390 for (list = pipe_list; list; list = list->next) {
7391 if (list->fptr == fptr) break;
7392 }
7393 if (!list) pipe_add_fptr(fptr);
7394 }
7395 else {
7396 pipe_del_fptr(fptr);
7397 }
7398#endif
7399}
7400
7401void
7403{
7405 fptr->mode |= FMODE_SYNC;
7406}
7407
7408void
7409rb_io_unbuffered(rb_io_t *fptr)
7410{
7411 rb_io_synchronized(fptr);
7412}
7413
7414int
7415rb_pipe(int *pipes)
7416{
7417 int ret;
7418 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7419 if (ret == 0) {
7420 rb_update_max_fd(pipes[0]);
7421 rb_update_max_fd(pipes[1]);
7422 }
7423 return ret;
7424}
7425
7426#ifdef _WIN32
7427#define HAVE_SPAWNV 1
7428#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7429#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7430#endif
7431
7432#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7433struct popen_arg {
7434 VALUE execarg_obj;
7435 struct rb_execarg *eargp;
7436 int modef;
7437 int pair[2];
7438 int write_pair[2];
7439};
7440#endif
7441
7442#ifdef HAVE_WORKING_FORK
7443# ifndef __EMSCRIPTEN__
7444static void
7445popen_redirect(struct popen_arg *p)
7446{
7447 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7448 close(p->write_pair[1]);
7449 if (p->write_pair[0] != 0) {
7450 dup2(p->write_pair[0], 0);
7451 close(p->write_pair[0]);
7452 }
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 if (p->modef & FMODE_READABLE) {
7460 close(p->pair[0]);
7461 if (p->pair[1] != 1) {
7462 dup2(p->pair[1], 1);
7463 close(p->pair[1]);
7464 }
7465 }
7466 else {
7467 close(p->pair[1]);
7468 if (p->pair[0] != 0) {
7469 dup2(p->pair[0], 0);
7470 close(p->pair[0]);
7471 }
7472 }
7473}
7474# endif
7475
7476#if defined(__linux__)
7477/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7478 * Since /proc may not be available, linux_get_maxfd is just a hint.
7479 * This function, linux_get_maxfd, must be async-signal-safe.
7480 * I.e. opendir() is not usable.
7481 *
7482 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7483 * However they are easy to re-implement in async-signal-safe manner.
7484 * (Also note that there is missing/memcmp.c.)
7485 */
7486static int
7487linux_get_maxfd(void)
7488{
7489 int fd;
7490 char buf[4096], *p, *np, *e;
7491 ssize_t ss;
7492 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7493 if (fd < 0) return fd;
7494 ss = read(fd, buf, sizeof(buf));
7495 if (ss < 0) goto err;
7496 p = buf;
7497 e = buf + ss;
7498 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7499 (np = memchr(p, '\n', e-p)) != NULL) {
7500 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7501 int fdsize;
7502 p += sizeof("FDSize:")-1;
7503 *np = '\0';
7504 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7505 close(fd);
7506 return fdsize;
7507 }
7508 p = np+1;
7509 }
7510 /* fall through */
7511
7512 err:
7513 close(fd);
7514 return (int)ss;
7515}
7516#endif
7517
7518/* This function should be async-signal-safe. */
7519void
7520rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7521{
7522#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7523 int fd, ret;
7524 int max = (int)max_file_descriptor;
7525# ifdef F_MAXFD
7526 /* F_MAXFD is available since NetBSD 2.0. */
7527 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7528 if (ret != -1)
7529 maxhint = max = ret;
7530# elif defined(__linux__)
7531 ret = linux_get_maxfd();
7532 if (maxhint < ret)
7533 maxhint = ret;
7534 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7535# endif
7536 if (max < maxhint)
7537 max = maxhint;
7538 for (fd = lowfd; fd <= max; fd++) {
7539 if (!NIL_P(noclose_fds) &&
7540 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7541 continue;
7542 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7543 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7544 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7545 }
7546# define CONTIGUOUS_CLOSED_FDS 20
7547 if (ret != -1) {
7548 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7549 max = fd + CONTIGUOUS_CLOSED_FDS;
7550 }
7551 }
7552#endif
7553}
7554
7555# ifndef __EMSCRIPTEN__
7556static int
7557popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7558{
7559 struct popen_arg *p = (struct popen_arg*)pp;
7560
7561 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7562}
7563# endif
7564#endif
7565
7566#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7567static VALUE
7568rb_execarg_fixup_v(VALUE execarg_obj)
7569{
7570 rb_execarg_parent_start(execarg_obj);
7571 return Qnil;
7572}
7573#else
7574char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7575#endif
7576
7577#ifndef __EMSCRIPTEN__
7578static VALUE
7579pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7580 const struct rb_io_encoding *convconfig)
7581{
7582 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7583 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7584 rb_pid_t pid = 0;
7585 rb_io_t *fptr;
7586 VALUE port;
7587 rb_io_t *write_fptr;
7588 VALUE write_port;
7589#if defined(HAVE_WORKING_FORK)
7590 int status;
7591 char errmsg[80] = { '\0' };
7592#endif
7593#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7594 int state;
7595 struct popen_arg arg;
7596#endif
7597 int e = 0;
7598#if defined(HAVE_SPAWNV)
7599# if defined(HAVE_SPAWNVE)
7600# define DO_SPAWN(cmd, args, envp) ((args) ? \
7601 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7602 spawne(P_NOWAIT, (cmd), (envp)))
7603# else
7604# define DO_SPAWN(cmd, args, envp) ((args) ? \
7605 spawnv(P_NOWAIT, (cmd), (args)) : \
7606 spawn(P_NOWAIT, (cmd)))
7607# endif
7608# if !defined(HAVE_WORKING_FORK)
7609 char **args = NULL;
7610# if defined(HAVE_SPAWNVE)
7611 char **envp = NULL;
7612# endif
7613# endif
7614#endif
7615#if !defined(HAVE_WORKING_FORK)
7616 struct rb_execarg sarg, *sargp = &sarg;
7617#endif
7618 FILE *fp = 0;
7619 int fd = -1;
7620 int write_fd = -1;
7621#if !defined(HAVE_WORKING_FORK)
7622 const char *cmd = 0;
7623
7624 if (prog)
7625 cmd = StringValueCStr(prog);
7626#endif
7627
7628#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7629 arg.execarg_obj = execarg_obj;
7630 arg.eargp = eargp;
7631 arg.modef = fmode;
7632 arg.pair[0] = arg.pair[1] = -1;
7633 arg.write_pair[0] = arg.write_pair[1] = -1;
7634# if !defined(HAVE_WORKING_FORK)
7635 if (eargp && !eargp->use_shell) {
7636 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7637 }
7638# endif
7639 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7641 if (rb_pipe(arg.write_pair) < 0)
7642 rb_sys_fail_str(prog);
7643 if (rb_pipe(arg.pair) < 0) {
7644 e = errno;
7645 close(arg.write_pair[0]);
7646 close(arg.write_pair[1]);
7647 rb_syserr_fail_str(e, prog);
7648 }
7649 if (eargp) {
7650 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7651 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7652 }
7653 break;
7654 case FMODE_READABLE:
7655 if (rb_pipe(arg.pair) < 0)
7656 rb_sys_fail_str(prog);
7657 if (eargp)
7658 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7659 break;
7660 case FMODE_WRITABLE:
7661 if (rb_pipe(arg.pair) < 0)
7662 rb_sys_fail_str(prog);
7663 if (eargp)
7664 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7665 break;
7666 default:
7667 rb_sys_fail_str(prog);
7668 }
7669 if (!NIL_P(execarg_obj)) {
7670 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7671 if (state) {
7672 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7673 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7674 if (0 <= arg.pair[0]) close(arg.pair[0]);
7675 if (0 <= arg.pair[1]) close(arg.pair[1]);
7676 rb_execarg_parent_end(execarg_obj);
7677 rb_jump_tag(state);
7678 }
7679
7680# if defined(HAVE_WORKING_FORK)
7681 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7682# else
7683 rb_execarg_run_options(eargp, sargp, NULL, 0);
7684# if defined(HAVE_SPAWNVE)
7685 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7686# endif
7687 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7688 /* exec failed */
7689 switch (e = errno) {
7690 case EAGAIN:
7691# if EWOULDBLOCK != EAGAIN
7692 case EWOULDBLOCK:
7693# endif
7694 rb_thread_sleep(1);
7695 continue;
7696 }
7697 break;
7698 }
7699 if (eargp)
7700 rb_execarg_run_options(sargp, NULL, NULL, 0);
7701# endif
7702 rb_execarg_parent_end(execarg_obj);
7703 }
7704 else {
7705# if defined(HAVE_WORKING_FORK)
7706 pid = rb_call_proc__fork();
7707 if (pid == 0) { /* child */
7708 popen_redirect(&arg);
7709 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7710 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7711 return Qnil;
7712 }
7713# else
7715# endif
7716 }
7717
7718 /* parent */
7719 if (pid < 0) {
7720# if defined(HAVE_WORKING_FORK)
7721 e = errno;
7722# endif
7723 close(arg.pair[0]);
7724 close(arg.pair[1]);
7726 close(arg.write_pair[0]);
7727 close(arg.write_pair[1]);
7728 }
7729# if defined(HAVE_WORKING_FORK)
7730 if (errmsg[0])
7731 rb_syserr_fail(e, errmsg);
7732# endif
7733 rb_syserr_fail_str(e, prog);
7734 }
7735 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7736 close(arg.pair[1]);
7737 fd = arg.pair[0];
7738 close(arg.write_pair[0]);
7739 write_fd = arg.write_pair[1];
7740 }
7741 else if (fmode & FMODE_READABLE) {
7742 close(arg.pair[1]);
7743 fd = arg.pair[0];
7744 }
7745 else {
7746 close(arg.pair[0]);
7747 fd = arg.pair[1];
7748 }
7749#else
7750 cmd = rb_execarg_commandline(eargp, &prog);
7751 if (!NIL_P(execarg_obj)) {
7752 rb_execarg_parent_start(execarg_obj);
7753 rb_execarg_run_options(eargp, sargp, NULL, 0);
7754 }
7755 fp = popen(cmd, modestr);
7756 e = errno;
7757 if (eargp) {
7758 rb_execarg_parent_end(execarg_obj);
7759 rb_execarg_run_options(sargp, NULL, NULL, 0);
7760 }
7761 if (!fp) rb_syserr_fail_path(e, prog);
7762 fd = fileno(fp);
7763#endif
7764
7765 port = io_alloc(rb_cIO);
7766 MakeOpenFile(port, fptr);
7767 fptr->fd = fd;
7768 fptr->stdio_file = fp;
7769 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7770 if (convconfig) {
7771 fptr->encs = *convconfig;
7772#if RUBY_CRLF_ENVIRONMENT
7775 }
7776#endif
7777 }
7778 else {
7779 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7781 }
7782#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7783 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7784 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7785 }
7786#endif
7787 }
7788 fptr->pid = pid;
7789
7790 if (0 <= write_fd) {
7791 write_port = io_alloc(rb_cIO);
7792 MakeOpenFile(write_port, write_fptr);
7793 write_fptr->fd = write_fd;
7794 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7795 fptr->mode &= ~FMODE_WRITABLE;
7796 fptr->tied_io_for_writing = write_port;
7797 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7798 }
7799
7800#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7801 fptr->finalize = pipe_finalize;
7802 pipe_add_fptr(fptr);
7803#endif
7804 return port;
7805}
7806#else
7807static VALUE
7808pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7809 const struct rb_io_encoding *convconfig)
7810{
7811 rb_raise(rb_eNotImpError, "popen() is not available");
7812}
7813#endif
7814
7815static int
7816is_popen_fork(VALUE prog)
7817{
7818 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7819#if !defined(HAVE_WORKING_FORK)
7820 rb_raise(rb_eNotImpError,
7821 "fork() function is unimplemented on this machine");
7822#else
7823 return TRUE;
7824#endif
7825 }
7826 return FALSE;
7827}
7828
7829static VALUE
7830pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
7831 const struct rb_io_encoding *convconfig)
7832{
7833 int argc = 1;
7834 VALUE *argv = &prog;
7835 VALUE execarg_obj = Qnil;
7836
7837 if (!is_popen_fork(prog))
7838 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7839 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7840}
7841
7842static VALUE
7843pipe_close(VALUE io)
7844{
7845 rb_io_t *fptr = io_close_fptr(io);
7846 if (fptr) {
7847 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7848 }
7849 return Qnil;
7850}
7851
7852static VALUE popen_finish(VALUE port, VALUE klass);
7853
7854/*
7855 * call-seq:
7856 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7857 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7858 *
7859 * Executes the given command +cmd+ as a subprocess
7860 * whose $stdin and $stdout are connected to a new stream +io+.
7861 *
7862 * This method has potential security vulnerabilities if called with untrusted input;
7863 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
7864 *
7865 * If no block is given, returns the new stream,
7866 * which depending on given +mode+ may be open for reading, writing, or both.
7867 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7868 *
7869 * If a block is given, the stream is passed to the block
7870 * (again, open for reading, writing, or both);
7871 * when the block exits, the stream is closed,
7872 * the block's value is returned,
7873 * and the global variable <tt>$?</tt> is set to the child's exit status.
7874 *
7875 * Optional argument +mode+ may be any valid \IO mode.
7876 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7877 *
7878 * Required argument +cmd+ determines which of the following occurs:
7879 *
7880 * - The process forks.
7881 * - A specified program runs in a shell.
7882 * - A specified program runs with specified arguments.
7883 * - A specified program runs with specified arguments and a specified +argv0+.
7884 *
7885 * Each of these is detailed below.
7886 *
7887 * The optional hash argument +env+ specifies name/value pairs that are to be added
7888 * to the environment variables for the subprocess:
7889 *
7890 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7891 * pipe.puts 'puts ENV["FOO"]'
7892 * pipe.close_write
7893 * pipe.gets
7894 * end => "bar\n"
7895 *
7896 * Optional keyword arguments +opts+ specify:
7897 *
7898 * - {Open options}[rdoc-ref:IO@Open+Options].
7899 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7900 * - Options for Kernel#spawn.
7901 *
7902 * <b>Forked Process</b>
7903 *
7904 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7905 * IO.popen('-') do |pipe|
7906 * if pipe
7907 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7908 * else
7909 * $stderr.puts "In child, pid is #{$$}\n"
7910 * end
7911 * end
7912 *
7913 * Output:
7914 *
7915 * In parent, child pid is 26253
7916 * In child, pid is 26253
7917 *
7918 * Note that this is not supported on all platforms.
7919 *
7920 * <b>Shell Subprocess</b>
7921 *
7922 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7923 * the program named +cmd+ is run as a shell command:
7924 *
7925 * IO.popen('uname') do |pipe|
7926 * pipe.readlines
7927 * end
7928 *
7929 * Output:
7930 *
7931 * ["Linux\n"]
7932 *
7933 * Another example:
7934 *
7935 * IO.popen('/bin/sh', 'r+') do |pipe|
7936 * pipe.puts('ls')
7937 * pipe.close_write
7938 * $stderr.puts pipe.readlines.size
7939 * end
7940 *
7941 * Output:
7942 *
7943 * 213
7944 *
7945 * <b>Program Subprocess</b>
7946 *
7947 * When argument +cmd+ is an array of strings,
7948 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7949 *
7950 * IO.popen(['du', '..', '.']) do |pipe|
7951 * $stderr.puts pipe.readlines.size
7952 * end
7953 *
7954 * Output:
7955 *
7956 * 1111
7957 *
7958 * <b>Program Subprocess with <tt>argv0</tt></b>
7959 *
7960 * When argument +cmd+ is an array whose first element is a 2-element string array
7961 * and whose remaining elements (if any) are strings:
7962 *
7963 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7964 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7965 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7966 *
7967 * Example (sets <tt>$0</tt> to 'foo'):
7968 *
7969 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7970 *
7971 * <b>Some Special Examples</b>
7972 *
7973 * # Set IO encoding.
7974 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7975 * euc_jp_string = nkf_io.read
7976 * }
7977 *
7978 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7979 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7980 * ls_result_with_error = io.read
7981 * end
7982 *
7983 * # Use mixture of spawn options and IO options.
7984 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7985 * ls_result_with_error = io.read
7986 * end
7987 *
7988 * f = IO.popen("uname")
7989 * p f.readlines
7990 * f.close
7991 * puts "Parent is #{Process.pid}"
7992 * IO.popen("date") {|f| puts f.gets }
7993 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7994 * p $?
7995 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7996 * f.puts "bar"; f.close_write; puts f.gets
7997 * }
7998 *
7999 * Output (from last section):
8000 *
8001 * ["Linux\n"]
8002 * Parent is 21346
8003 * Thu Jan 15 22:41:19 JST 2009
8004 * 21346 is here, f is #<IO:fd 3>
8005 * 21352 is here, f is nil
8006 * #<Process::Status: pid 21352 exit 0>
8007 * <foo>bar;zot;
8008 *
8009 * Raises exceptions that IO.pipe and Kernel.spawn raise.
8010 *
8011 */
8012
8013static VALUE
8014rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
8015{
8016 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
8017
8018 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8019 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8020 switch (argc) {
8021 case 2:
8022 pmode = argv[1];
8023 case 1:
8024 pname = argv[0];
8025 break;
8026 default:
8027 {
8028 int ex = !NIL_P(opt);
8029 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8030 }
8031 }
8032 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8033}
8034
8035VALUE
8036rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8037{
8038 const char *modestr;
8039 VALUE tmp, execarg_obj = Qnil;
8040 int oflags;
8041 enum rb_io_mode fmode;
8042 struct rb_io_encoding convconfig;
8043
8044 tmp = rb_check_array_type(pname);
8045 if (!NIL_P(tmp)) {
8046 long len = RARRAY_LEN(tmp);
8047#if SIZEOF_LONG > SIZEOF_INT
8048 if (len > INT_MAX) {
8049 rb_raise(rb_eArgError, "too many arguments");
8050 }
8051#endif
8052 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8053 RB_GC_GUARD(tmp);
8054 }
8055 else {
8056 StringValue(pname);
8057 execarg_obj = Qnil;
8058 if (!is_popen_fork(pname))
8059 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8060 }
8061 if (!NIL_P(execarg_obj)) {
8062 if (!NIL_P(opt))
8063 opt = rb_execarg_extract_options(execarg_obj, opt);
8064 if (!NIL_P(env))
8065 rb_execarg_setenv(execarg_obj, env);
8066 }
8067 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8068 modestr = rb_io_oflags_modestr(oflags);
8069
8070 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8071}
8072
8073static VALUE
8074popen_finish(VALUE port, VALUE klass)
8075{
8076 if (NIL_P(port)) {
8077 /* child */
8078 if (rb_block_given_p()) {
8079 rb_protect(rb_yield, Qnil, NULL);
8080 rb_io_flush(rb_ractor_stdout());
8081 rb_io_flush(rb_ractor_stderr());
8082 _exit(0);
8083 }
8084 return Qnil;
8085 }
8086 RBASIC_SET_CLASS(port, klass);
8087 if (rb_block_given_p()) {
8088 return rb_ensure(rb_yield, port, pipe_close, port);
8089 }
8090 return port;
8091}
8092
8093#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8094struct popen_writer_arg {
8095 char *const *argv;
8096 struct popen_arg popen;
8097};
8098
8099static int
8100exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8101{
8102 struct popen_writer_arg *pw = arg;
8103 pw->popen.modef = FMODE_WRITABLE;
8104 popen_redirect(&pw->popen);
8105 execv(pw->argv[0], pw->argv);
8106 strlcpy(errmsg, strerror(errno), buflen);
8107 return -1;
8108}
8109#endif
8110
8111FILE *
8112ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8113{
8114#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8115# ifdef HAVE_WORKING_FORK
8116 struct popen_writer_arg pw;
8117 int *const write_pair = pw.popen.pair;
8118# else
8119 int write_pair[2];
8120# endif
8121
8122#ifdef HAVE_PIPE2
8123 int result = pipe2(write_pair, O_CLOEXEC);
8124#else
8125 int result = pipe(write_pair);
8126#endif
8127
8128 *pid = -1;
8129 if (result == 0) {
8130# ifdef HAVE_WORKING_FORK
8131 pw.argv = argv;
8132 int status;
8133 char errmsg[80] = {'\0'};
8134 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8135# else
8136 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8137 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8138# endif
8139 close(write_pair[0]);
8140 if (*pid < 0) {
8141 close(write_pair[1]);
8142 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8143 }
8144 else {
8145 return fdopen(write_pair[1], "w");
8146 }
8147 }
8148#endif
8149 return NULL;
8150}
8151
8152static VALUE
8153rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8154{
8155 int oflags;
8156 enum rb_io_mode fmode;
8157 struct rb_io_encoding convconfig;
8158 mode_t perm;
8159
8160 FilePathValue(fname);
8161
8162 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8163 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8164
8165 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8166
8167 return io;
8168}
8169
8170/*
8171 * Document-method: File::open
8172 *
8173 * call-seq:
8174 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8175 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8176 *
8177 * Creates a new File object, via File.new with the given arguments.
8178 *
8179 * With no block given, returns the File object.
8180 *
8181 * With a block given, calls the block with the File object
8182 * and returns the block's value.
8183 *
8184 */
8185
8186/*
8187 * Document-method: IO::open
8188 *
8189 * call-seq:
8190 * IO.open(fd, mode = 'r', **opts) -> io
8191 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8192 *
8193 * Creates a new \IO object, via IO.new with the given arguments.
8194 *
8195 * With no block given, returns the \IO object.
8196 *
8197 * With a block given, calls the block with the \IO object
8198 * and returns the block's value.
8199 *
8200 */
8201
8202static VALUE
8203rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8204{
8206
8207 if (rb_block_given_p()) {
8208 return rb_ensure(rb_yield, io, io_close, io);
8209 }
8210
8211 return io;
8212}
8213
8214/*
8215 * call-seq:
8216 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8217 *
8218 * Opens the file at the given path with the given mode and permissions;
8219 * returns the integer file descriptor.
8220 *
8221 * If the file is to be readable, it must exist;
8222 * if the file is to be writable and does not exist,
8223 * it is created with the given permissions:
8224 *
8225 * File.write('t.tmp', '') # => 0
8226 * IO.sysopen('t.tmp') # => 8
8227 * IO.sysopen('t.tmp', 'w') # => 9
8228 *
8229 *
8230 */
8231
8232static VALUE
8233rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8234{
8235 VALUE fname, vmode, vperm;
8236 VALUE intmode;
8237 int oflags, fd;
8238 mode_t perm;
8239
8240 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8241 FilePathValue(fname);
8242
8243 if (NIL_P(vmode))
8244 oflags = O_RDONLY;
8245 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8246 oflags = NUM2INT(intmode);
8247 else {
8248 StringValue(vmode);
8249 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8250 }
8251 if (NIL_P(vperm)) perm = 0666;
8252 else perm = NUM2MODET(vperm);
8253
8254 RB_GC_GUARD(fname) = rb_str_new4(fname);
8255 fd = rb_sysopen(fname, oflags, perm);
8256 return INT2NUM(fd);
8257}
8258
8259/*
8260 * call-seq:
8261 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8262 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8263 *
8264 * Creates an IO object connected to the given file.
8265 *
8266 * This method has potential security vulnerabilities if called with untrusted input;
8267 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
8268 *
8269 * With no block given, file stream is returned:
8270 *
8271 * open('t.txt') # => #<File:t.txt>
8272 *
8273 * With a block given, calls the block with the open file stream,
8274 * then closes the stream:
8275 *
8276 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8277 *
8278 * Output:
8279 *
8280 * #<File:t.txt>
8281 *
8282 * See File.open for details.
8283 *
8284 */
8285
8286static VALUE
8287rb_f_open(int argc, VALUE *argv, VALUE _)
8288{
8289 ID to_open = 0;
8290 int redirect = FALSE;
8291
8292 if (argc >= 1) {
8293 CONST_ID(to_open, "to_open");
8294 if (rb_respond_to(argv[0], to_open)) {
8295 redirect = TRUE;
8296 }
8297 else {
8298 VALUE tmp = argv[0];
8299 FilePathValue(tmp);
8300 if (NIL_P(tmp)) {
8301 redirect = TRUE;
8302 }
8303 else {
8304 argv[0] = tmp;
8305 }
8306 }
8307 }
8308 if (redirect) {
8309 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8310
8311 if (rb_block_given_p()) {
8312 return rb_ensure(rb_yield, io, io_close, io);
8313 }
8314 return io;
8315 }
8316 return rb_io_s_open(argc, argv, rb_cFile);
8317}
8318
8319static VALUE
8320rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8321 const struct rb_io_encoding *convconfig, mode_t perm)
8322{
8323 return rb_file_open_generic(io_alloc(klass), filename,
8324 oflags, fmode, convconfig, perm);
8325}
8326
8327static VALUE
8328rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8329{
8330 int oflags;
8331 enum rb_io_mode fmode;
8332 struct rb_io_encoding convconfig;
8333 mode_t perm;
8334
8335 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8336 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8337 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8338}
8339
8340static VALUE
8341io_reopen(VALUE io, VALUE nfile)
8342{
8343 rb_io_t *fptr, *orig;
8344 int fd, fd2;
8345 rb_off_t pos = 0;
8346
8347 nfile = rb_io_get_io(nfile);
8348 GetOpenFile(io, fptr);
8349 GetOpenFile(nfile, orig);
8350
8351 if (fptr == orig) return io;
8352 if (RUBY_IO_EXTERNAL_P(fptr)) {
8353 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8354 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8355 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8356 rb_raise(rb_eArgError,
8357 "%s can't change access mode from \"%s\" to \"%s\"",
8358 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8359 rb_io_fmode_modestr(orig->mode));
8360 }
8361 }
8362 if (fptr->mode & FMODE_WRITABLE) {
8363 if (io_fflush(fptr) < 0)
8364 rb_sys_fail_on_write(fptr);
8365 }
8366 else {
8367 flush_before_seek(fptr, true);
8368 }
8369 if (orig->mode & FMODE_READABLE) {
8370 pos = io_tell(orig);
8371 }
8372 if (orig->mode & FMODE_WRITABLE) {
8373 if (io_fflush(orig) < 0)
8374 rb_sys_fail_on_write(fptr);
8375 }
8376
8377 /* copy rb_io_t structure */
8378 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8379 fptr->encs = orig->encs;
8380 fptr->pid = orig->pid;
8381 fptr->lineno = orig->lineno;
8382 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8383 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8384 fptr_copy_finalizer(fptr, orig);
8385
8386 fd = fptr->fd;
8387 fd2 = orig->fd;
8388 if (fd != fd2) {
8389 // Interrupt all usage of the old file descriptor:
8390 rb_thread_io_close_interrupt(fptr);
8391 rb_thread_io_close_wait(fptr);
8392
8393 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8394 /* need to keep FILE objects of stdin, stdout and stderr */
8395 if (rb_cloexec_dup2(fd2, fd) < 0)
8396 rb_sys_fail_path(orig->pathv);
8397 rb_update_max_fd(fd);
8398 }
8399 else {
8400 fclose(fptr->stdio_file);
8401 fptr->stdio_file = 0;
8402 fptr->fd = -1;
8403 if (rb_cloexec_dup2(fd2, fd) < 0)
8404 rb_sys_fail_path(orig->pathv);
8405 rb_update_max_fd(fd);
8406 fptr->fd = fd;
8407 }
8408
8409 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8410 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8411 rb_sys_fail_path(fptr->pathv);
8412 }
8413 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8414 rb_sys_fail_path(orig->pathv);
8415 }
8416 }
8417 }
8418
8419 if (fptr->mode & FMODE_BINMODE) {
8420 rb_io_binmode(io);
8421 }
8422
8423 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8424 return io;
8425}
8426
8427#ifdef _WIN32
8428int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8429#else
8430static int
8431rb_freopen(VALUE fname, const char *mode, FILE *fp)
8432{
8433 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8434 RB_GC_GUARD(fname);
8435 return errno;
8436 }
8437 return 0;
8438}
8439#endif
8440
8441/*
8442 * call-seq:
8443 * reopen(other_io) -> self
8444 * reopen(path, mode = 'r', **opts) -> self
8445 *
8446 * Reassociates the stream with another stream,
8447 * which may be of a different class.
8448 * This method may be used to redirect an existing stream
8449 * to a new destination.
8450 *
8451 * With argument +other_io+ given, reassociates with that stream:
8452 *
8453 * # Redirect $stdin from a file.
8454 * f = File.open('t.txt')
8455 * $stdin.reopen(f)
8456 * f.close
8457 *
8458 * # Redirect $stdout to a file.
8459 * f = File.open('t.tmp', 'w')
8460 * $stdout.reopen(f)
8461 * f.close
8462 *
8463 * With argument +path+ given, reassociates with a new stream to that file path:
8464 *
8465 * $stdin.reopen('t.txt')
8466 * $stdout.reopen('t.tmp', 'w')
8467 *
8468 * Optional keyword arguments +opts+ specify:
8469 *
8470 * - {Open Options}[rdoc-ref:IO@Open+Options].
8471 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8472 *
8473 */
8474
8475static VALUE
8476rb_io_reopen(int argc, VALUE *argv, VALUE file)
8477{
8478 VALUE fname, nmode, opt;
8479 int oflags;
8480 rb_io_t *fptr;
8481
8482 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8483 VALUE tmp = rb_io_check_io(fname);
8484 if (!NIL_P(tmp)) {
8485 return io_reopen(file, tmp);
8486 }
8487 }
8488
8489 FilePathValue(fname);
8490 rb_io_taint_check(file);
8491 fptr = RFILE(file)->fptr;
8492 if (!fptr) {
8493 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8494 }
8495
8496 if (!NIL_P(nmode) || !NIL_P(opt)) {
8497 enum rb_io_mode fmode;
8498 struct rb_io_encoding convconfig;
8499
8500 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8501 if (RUBY_IO_EXTERNAL_P(fptr) &&
8502 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8503 (fptr->mode & FMODE_READWRITE)) {
8504 rb_raise(rb_eArgError,
8505 "%s can't change access mode from \"%s\" to \"%s\"",
8506 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8507 rb_io_fmode_modestr(fmode));
8508 }
8509 fptr->mode = fmode;
8510 fptr->encs = convconfig;
8511 }
8512 else {
8513 oflags = rb_io_fmode_oflags(fptr->mode);
8514 }
8515
8516 fptr->pathv = fname;
8517 if (fptr->fd < 0) {
8518 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8519 fptr->stdio_file = 0;
8520 return file;
8521 }
8522
8523 if (fptr->mode & FMODE_WRITABLE) {
8524 if (io_fflush(fptr) < 0)
8525 rb_sys_fail_on_write(fptr);
8526 }
8527 fptr->rbuf.off = fptr->rbuf.len = 0;
8528
8529 if (fptr->stdio_file) {
8530 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8531 rb_io_oflags_modestr(oflags),
8532 fptr->stdio_file);
8533 if (e) rb_syserr_fail_path(e, fptr->pathv);
8534 fptr->fd = fileno(fptr->stdio_file);
8535 rb_fd_fix_cloexec(fptr->fd);
8536#ifdef USE_SETVBUF
8537 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8538 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8539#endif
8540 if (fptr->stdio_file == stderr) {
8541 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8542 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8543 }
8544 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8545 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8546 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8547 }
8548 }
8549 else {
8550 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8551 int err = 0;
8552 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8553 err = errno;
8554 (void)close(tmpfd);
8555 if (err) {
8556 rb_syserr_fail_path(err, fptr->pathv);
8557 }
8558 }
8559
8560 return file;
8561}
8562
8563/* :nodoc: */
8564static VALUE
8565rb_io_init_copy(VALUE dest, VALUE io)
8566{
8567 rb_io_t *fptr, *orig;
8568 int fd;
8569 VALUE write_io;
8570 rb_off_t pos;
8571
8572 io = rb_io_get_io(io);
8573 if (!OBJ_INIT_COPY(dest, io)) return dest;
8574 GetOpenFile(io, orig);
8575 MakeOpenFile(dest, fptr);
8576
8577 rb_io_flush(io);
8578
8579 /* copy rb_io_t structure */
8580 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8581 fptr->encs = orig->encs;
8582 fptr->pid = orig->pid;
8583 fptr->lineno = orig->lineno;
8584 fptr->timeout = orig->timeout;
8585
8586 ccan_list_head_init(&fptr->blocking_operations);
8587 fptr->closing_ec = NULL;
8588 fptr->wakeup_mutex = Qnil;
8589 fptr->fork_generation = GET_VM()->fork_gen;
8590
8591 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8592 fptr_copy_finalizer(fptr, orig);
8593
8594 fd = ruby_dup(orig->fd);
8595 fptr->fd = fd;
8596 pos = io_tell(orig);
8597 if (0 <= pos)
8598 io_seek(fptr, pos, SEEK_SET);
8599 if (fptr->mode & FMODE_BINMODE) {
8600 rb_io_binmode(dest);
8601 }
8602
8603 write_io = GetWriteIO(io);
8604 if (io != write_io) {
8605 write_io = rb_obj_dup(write_io);
8606 fptr->tied_io_for_writing = write_io;
8607 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8608 }
8609
8610 return dest;
8611}
8612
8613/*
8614 * call-seq:
8615 * printf(format_string, *objects) -> nil
8616 *
8617 * Formats and writes +objects+ to the stream.
8618 *
8619 * For details on +format_string+, see
8620 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8621 *
8622 */
8623
8624VALUE
8625rb_io_printf(int argc, const VALUE *argv, VALUE out)
8626{
8627 rb_io_write(out, rb_f_sprintf(argc, argv));
8628 return Qnil;
8629}
8630
8631/*
8632 * call-seq:
8633 * printf(format_string, *objects) -> nil
8634 * printf(io, format_string, *objects) -> nil
8635 *
8636 * Equivalent to:
8637 *
8638 * io.write(sprintf(format_string, *objects))
8639 *
8640 * For details on +format_string+, see
8641 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8642 *
8643 * With the single argument +format_string+, formats +objects+ into the string,
8644 * then writes the formatted string to $stdout:
8645 *
8646 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8647 *
8648 * Output (on $stdout):
8649 *
8650 * 0024 24 24.00#
8651 *
8652 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8653 * then writes the formatted string to +io+:
8654 *
8655 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8656 *
8657 * Output (on $stderr):
8658 *
8659 * 0024 24 24.00# => nil
8660 *
8661 * With no arguments, does nothing.
8662 *
8663 */
8664
8665static VALUE
8666rb_f_printf(int argc, VALUE *argv, VALUE _)
8667{
8668 VALUE out;
8669
8670 if (argc == 0) return Qnil;
8671 if (RB_TYPE_P(argv[0], T_STRING)) {
8672 out = rb_ractor_stdout();
8673 }
8674 else {
8675 out = argv[0];
8676 argv++;
8677 argc--;
8678 }
8679 rb_io_write(out, rb_f_sprintf(argc, argv));
8680
8681 return Qnil;
8682}
8683
8684extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
8685
8686static void
8687deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8688{
8689 rb_deprecated_str_setter(val, id, &val);
8690 if (!NIL_P(val)) {
8691 if (rb_str_equal(val, rb_default_rs)) {
8692 val = rb_default_rs;
8693 }
8694 else {
8695 val = rb_str_frozen_bare_string(val);
8696 }
8697 }
8698 *var = val;
8699}
8700
8701/*
8702 * call-seq:
8703 * print(*objects) -> nil
8704 *
8705 * Writes the given objects to the stream; returns +nil+.
8706 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8707 * (<tt>$\</tt>), if it is not +nil+.
8708 * See {Line IO}[rdoc-ref:IO@Line+IO].
8709 *
8710 * With argument +objects+ given, for each object:
8711 *
8712 * - Converts via its method +to_s+ if not a string.
8713 * - Writes to the stream.
8714 * - If not the last object, writes the output field separator
8715 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8716 *
8717 * With default separators:
8718 *
8719 * f = File.open('t.tmp', 'w+')
8720 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8721 * p $OUTPUT_RECORD_SEPARATOR
8722 * p $OUTPUT_FIELD_SEPARATOR
8723 * f.print(*objects)
8724 * f.rewind
8725 * p f.read
8726 * f.close
8727 *
8728 * Output:
8729 *
8730 * nil
8731 * nil
8732 * "00.00/10+0izerozero"
8733 *
8734 * With specified separators:
8735 *
8736 * $\ = "\n"
8737 * $, = ','
8738 * f.rewind
8739 * f.print(*objects)
8740 * f.rewind
8741 * p f.read
8742 *
8743 * Output:
8744 *
8745 * "0,0.0,0/1,0+0i,zero,zero\n"
8746 *
8747 * With no argument given, writes the content of <tt>$_</tt>
8748 * (which is usually the most recent user input):
8749 *
8750 * f = File.open('t.tmp', 'w+')
8751 * gets # Sets $_ to the most recent user input.
8752 * f.print
8753 * f.close
8754 *
8755 */
8756
8757VALUE
8758rb_io_print(int argc, const VALUE *argv, VALUE out)
8759{
8760 int i;
8761 VALUE line;
8762
8763 /* if no argument given, print `$_' */
8764 if (argc == 0) {
8765 argc = 1;
8766 line = rb_lastline_get();
8767 argv = &line;
8768 }
8769 if (argc > 1 && !NIL_P(rb_output_fs)) {
8770 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8771 }
8772 for (i=0; i<argc; i++) {
8773 if (!NIL_P(rb_output_fs) && i>0) {
8774 rb_io_write(out, rb_output_fs);
8775 }
8776 rb_io_write(out, argv[i]);
8777 }
8778 if (argc > 0 && !NIL_P(rb_output_rs)) {
8779 rb_io_write(out, rb_output_rs);
8780 }
8781
8782 return Qnil;
8783}
8784
8785/*
8786 * call-seq:
8787 * print(*objects) -> nil
8788 *
8789 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8790 * this method is the straightforward way to write to <tt>$stdout</tt>.
8791 *
8792 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8793 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8794 * <tt>$\</tt>), if it is not +nil+.
8795 *
8796 * With argument +objects+ given, for each object:
8797 *
8798 * - Converts via its method +to_s+ if not a string.
8799 * - Writes to <tt>stdout</tt>.
8800 * - If not the last object, writes the output field separator
8801 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8802 *
8803 * With default separators:
8804 *
8805 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8806 * $OUTPUT_RECORD_SEPARATOR
8807 * $OUTPUT_FIELD_SEPARATOR
8808 * print(*objects)
8809 *
8810 * Output:
8811 *
8812 * nil
8813 * nil
8814 * 00.00/10+0izerozero
8815 *
8816 * With specified separators:
8817 *
8818 * $OUTPUT_RECORD_SEPARATOR = "\n"
8819 * $OUTPUT_FIELD_SEPARATOR = ','
8820 * print(*objects)
8821 *
8822 * Output:
8823 *
8824 * 0,0.0,0/1,0+0i,zero,zero
8825 *
8826 * With no argument given, writes the content of <tt>$_</tt>
8827 * (which is usually the most recent user input):
8828 *
8829 * gets # Sets $_ to the most recent user input.
8830 * print # Prints $_.
8831 *
8832 */
8833
8834static VALUE
8835rb_f_print(int argc, const VALUE *argv, VALUE _)
8836{
8837 rb_io_print(argc, argv, rb_ractor_stdout());
8838 return Qnil;
8839}
8840
8841/*
8842 * call-seq:
8843 * putc(object) -> object
8844 *
8845 * Writes a character to the stream.
8846 * See {Character IO}[rdoc-ref:IO@Character+IO].
8847 *
8848 * If +object+ is numeric, converts to integer if necessary,
8849 * then writes the character whose code is the
8850 * least significant byte;
8851 * if +object+ is a string, writes the first character:
8852 *
8853 * $stdout.putc "A"
8854 * $stdout.putc 65
8855 *
8856 * Output:
8857 *
8858 * AA
8859 *
8860 */
8861
8862static VALUE
8863rb_io_putc(VALUE io, VALUE ch)
8864{
8865 VALUE str;
8866 if (RB_TYPE_P(ch, T_STRING)) {
8867 str = rb_str_substr(ch, 0, 1);
8868 }
8869 else {
8870 char c = NUM2CHR(ch);
8871 str = rb_str_new(&c, 1);
8872 }
8873 rb_io_write(io, str);
8874 return ch;
8875}
8876
8877#define forward(obj, id, argc, argv) \
8878 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8879#define forward_public(obj, id, argc, argv) \
8880 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8881#define forward_current(id, argc, argv) \
8882 forward_public(ARGF.current_file, id, argc, argv)
8883
8884/*
8885 * call-seq:
8886 * putc(int) -> int
8887 *
8888 * Equivalent to:
8889 *
8890 * $stdout.putc(int)
8891 *
8892 * See IO#putc for important information regarding multi-byte characters.
8893 *
8894 */
8895
8896static VALUE
8897rb_f_putc(VALUE recv, VALUE ch)
8898{
8899 VALUE r_stdout = rb_ractor_stdout();
8900 if (recv == r_stdout) {
8901 return rb_io_putc(recv, ch);
8902 }
8903 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8904}
8905
8906
8907int
8908rb_str_end_with_asciichar(VALUE str, int c)
8909{
8910 long len = RSTRING_LEN(str);
8911 const char *ptr = RSTRING_PTR(str);
8912 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8913 int n;
8914
8915 if (len == 0) return 0;
8916 if ((n = rb_enc_mbminlen(enc)) == 1) {
8917 return ptr[len - 1] == c;
8918 }
8919 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8920}
8921
8922static VALUE
8923io_puts_ary(VALUE ary, VALUE out, int recur)
8924{
8925 VALUE tmp;
8926 long i;
8927
8928 if (recur) {
8929 tmp = rb_str_new2("[...]");
8930 rb_io_puts(1, &tmp, out);
8931 return Qtrue;
8932 }
8933 ary = rb_check_array_type(ary);
8934 if (NIL_P(ary)) return Qfalse;
8935 for (i=0; i<RARRAY_LEN(ary); i++) {
8936 tmp = RARRAY_AREF(ary, i);
8937 rb_io_puts(1, &tmp, out);
8938 }
8939 return Qtrue;
8940}
8941
8942/*
8943 * call-seq:
8944 * puts(*objects) -> nil
8945 *
8946 * Writes the given +objects+ to the stream, which must be open for writing;
8947 * returns +nil+.\
8948 * Writes a newline after each that does not already end with a newline sequence.
8949 * If called without arguments, writes a newline.
8950 * See {Line IO}[rdoc-ref:IO@Line+IO].
8951 *
8952 * Note that each added newline is the character <tt>"\n"<//tt>,
8953 * not the output record separator (<tt>$\</tt>).
8954 *
8955 * Treatment for each object:
8956 *
8957 * - String: writes the string.
8958 * - Neither string nor array: writes <tt>object.to_s</tt>.
8959 * - Array: writes each element of the array; arrays may be nested.
8960 *
8961 * To keep these examples brief, we define this helper method:
8962 *
8963 * def show(*objects)
8964 * # Puts objects to file.
8965 * f = File.new('t.tmp', 'w+')
8966 * f.puts(objects)
8967 * # Return file content.
8968 * f.rewind
8969 * p f.read
8970 * f.close
8971 * end
8972 *
8973 * # Strings without newlines.
8974 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8975 * # Strings, some with newlines.
8976 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8977 *
8978 * # Neither strings nor arrays:
8979 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8980 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8981 *
8982 * # Array of strings.
8983 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8984 * # Nested arrays.
8985 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8986 *
8987 */
8988
8989VALUE
8990rb_io_puts(int argc, const VALUE *argv, VALUE out)
8991{
8992 VALUE line, args[2];
8993
8994 /* if no argument given, print newline. */
8995 if (argc == 0) {
8996 rb_io_write(out, rb_default_rs);
8997 return Qnil;
8998 }
8999 for (int i = 0; i < argc; i++) {
9000 // Convert the argument to a string:
9001 if (RB_TYPE_P(argv[i], T_STRING)) {
9002 line = argv[i];
9003 }
9004 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9005 continue;
9006 }
9007 else {
9008 line = rb_obj_as_string(argv[i]);
9009 }
9010
9011 // Write the line:
9012 int n = 0;
9013 if (RSTRING_LEN(line) == 0) {
9014 args[n++] = rb_default_rs;
9015 }
9016 else {
9017 args[n++] = line;
9018 if (!rb_str_end_with_asciichar(line, '\n')) {
9019 args[n++] = rb_default_rs;
9020 }
9021 }
9022
9023 rb_io_writev(out, n, args);
9024 }
9025
9026 return Qnil;
9027}
9028
9029/*
9030 * call-seq:
9031 * puts(*objects) -> nil
9032 *
9033 * Equivalent to
9034 *
9035 * $stdout.puts(objects)
9036 */
9037
9038static VALUE
9039rb_f_puts(int argc, VALUE *argv, VALUE recv)
9040{
9041 VALUE r_stdout = rb_ractor_stdout();
9042 if (recv == r_stdout) {
9043 return rb_io_puts(argc, argv, recv);
9044 }
9045 return forward(r_stdout, rb_intern("puts"), argc, argv);
9046}
9047
9048static VALUE
9049rb_p_write(VALUE str)
9050{
9051 VALUE args[2];
9052 args[0] = str;
9053 args[1] = rb_default_rs;
9054 VALUE r_stdout = rb_ractor_stdout();
9055 if (RB_TYPE_P(r_stdout, T_FILE) &&
9056 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9057 io_writev(2, args, r_stdout);
9058 }
9059 else {
9060 rb_io_writev(r_stdout, 2, args);
9061 }
9062 return Qnil;
9063}
9064
9065void
9066rb_p(VALUE obj) /* for debug print within C code */
9067{
9068 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9069}
9070
9071static VALUE
9072rb_p_result(int argc, const VALUE *argv)
9073{
9074 VALUE ret = Qnil;
9075
9076 if (argc == 1) {
9077 ret = argv[0];
9078 }
9079 else if (argc > 1) {
9080 ret = rb_ary_new4(argc, argv);
9081 }
9082 VALUE r_stdout = rb_ractor_stdout();
9083 if (RB_TYPE_P(r_stdout, T_FILE)) {
9084 rb_uninterruptible(rb_io_flush, r_stdout);
9085 }
9086 return ret;
9087}
9088
9089/*
9090 * call-seq:
9091 * p(object) -> obj
9092 * p(*objects) -> array of objects
9093 * p -> nil
9094 *
9095 * For each object +obj+, executes:
9096 *
9097 * $stdout.write(obj.inspect, "\n")
9098 *
9099 * With one object given, returns the object;
9100 * with multiple objects given, returns an array containing the objects;
9101 * with no object given, returns +nil+.
9102 *
9103 * Examples:
9104 *
9105 * r = Range.new(0, 4)
9106 * p r # => 0..4
9107 * p [r, r, r] # => [0..4, 0..4, 0..4]
9108 * p # => nil
9109 *
9110 * Output:
9111 *
9112 * 0..4
9113 * [0..4, 0..4, 0..4]
9114 *
9115 * Kernel#p is designed for debugging purposes.
9116 * Ruby implementations may define Kernel#p to be uninterruptible
9117 * in whole or in part.
9118 * On CRuby, Kernel#p's writing of data is uninterruptible.
9119 */
9120
9121static VALUE
9122rb_f_p(int argc, VALUE *argv, VALUE self)
9123{
9124 int i;
9125 for (i=0; i<argc; i++) {
9126 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9127 rb_uninterruptible(rb_p_write, inspected);
9128 }
9129 return rb_p_result(argc, argv);
9130}
9131
9132/*
9133 * call-seq:
9134 * display(port = $>) -> nil
9135 *
9136 * Writes +self+ on the given port:
9137 *
9138 * 1.display
9139 * "cat".display
9140 * [ 4, 5, 6 ].display
9141 * puts
9142 *
9143 * Output:
9144 *
9145 * 1cat[4, 5, 6]
9146 *
9147 */
9148
9149static VALUE
9150rb_obj_display(int argc, VALUE *argv, VALUE self)
9151{
9152 VALUE out;
9153
9154 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9155 rb_io_write(out, self);
9156
9157 return Qnil;
9158}
9159
9160static int
9161rb_stderr_to_original_p(VALUE err)
9162{
9163 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9164}
9165
9166void
9167rb_write_error2(const char *mesg, long len)
9168{
9169 VALUE out = rb_ractor_stderr();
9170 if (rb_stderr_to_original_p(out)) {
9171#ifdef _WIN32
9172 if (isatty(fileno(stderr))) {
9173 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9174 }
9175#endif
9176 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9177 /* failed to write to stderr, what can we do? */
9178 return;
9179 }
9180 }
9181 else {
9182 rb_io_write(out, rb_str_new(mesg, len));
9183 }
9184}
9185
9186void
9187rb_write_error(const char *mesg)
9188{
9189 rb_write_error2(mesg, strlen(mesg));
9190}
9191
9192void
9193rb_write_error_str(VALUE mesg)
9194{
9195 VALUE out = rb_ractor_stderr();
9196 /* a stopgap measure for the time being */
9197 if (rb_stderr_to_original_p(out)) {
9198 size_t len = (size_t)RSTRING_LEN(mesg);
9199#ifdef _WIN32
9200 if (isatty(fileno(stderr))) {
9201 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9202 }
9203#endif
9204 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9205 RB_GC_GUARD(mesg);
9206 return;
9207 }
9208 }
9209 else {
9210 /* may unlock GVL, and */
9211 rb_io_write(out, mesg);
9212 }
9213}
9214
9215int
9216rb_stderr_tty_p(void)
9217{
9218 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9219 return isatty(fileno(stderr));
9220 return 0;
9221}
9222
9223static void
9224must_respond_to(ID mid, VALUE val, ID id)
9225{
9226 if (!rb_respond_to(val, mid)) {
9227 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9228 rb_id2str(id), rb_id2str(mid),
9229 rb_obj_class(val));
9230 }
9231}
9232
9233static void
9234stdin_setter(VALUE val, ID id, VALUE *ptr)
9235{
9237}
9238
9239static VALUE
9240stdin_getter(ID id, VALUE *ptr)
9241{
9242 return rb_ractor_stdin();
9243}
9244
9245static void
9246stdout_setter(VALUE val, ID id, VALUE *ptr)
9247{
9248 must_respond_to(id_write, val, id);
9250}
9251
9252static VALUE
9253stdout_getter(ID id, VALUE *ptr)
9254{
9255 return rb_ractor_stdout();
9256}
9257
9258static void
9259stderr_setter(VALUE val, ID id, VALUE *ptr)
9260{
9261 must_respond_to(id_write, val, id);
9263}
9264
9265static VALUE
9266stderr_getter(ID id, VALUE *ptr)
9267{
9268 return rb_ractor_stderr();
9269}
9270
9271static VALUE
9272allocate_and_open_new_file(VALUE klass)
9273{
9274 VALUE self = io_alloc(klass);
9275 rb_io_make_open_file(self);
9276 return self;
9277}
9278
9279VALUE
9280rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9281{
9282 int state;
9283 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9284 if (state) {
9285 /* if we raised an exception allocating an IO object, but the caller
9286 intended to transfer ownership of this FD to us, close the fd before
9287 raising the exception. Otherwise, we would leak a FD - the caller
9288 expects GC to close the file, but we never got around to assigning
9289 it to a rb_io. */
9290 if (!(mode & FMODE_EXTERNAL)) {
9291 maygvl_close(descriptor, 0);
9292 }
9293 rb_jump_tag(state);
9294 }
9295
9296
9297 rb_io_t *io = RFILE(self)->fptr;
9298 io->self = self;
9299 io->fd = descriptor;
9300 io->mode = mode;
9301
9302 /* At this point, Ruby fully owns the descriptor, and will close it when
9303 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9304 in the rest of this method. */
9305
9306 if (NIL_P(path)) {
9307 io->pathv = Qnil;
9308 }
9309 else {
9310 StringValue(path);
9311 io->pathv = rb_str_new_frozen(path);
9312 }
9313
9314 io->timeout = timeout;
9315
9316 ccan_list_head_init(&io->blocking_operations);
9317 io->closing_ec = NULL;
9318 io->wakeup_mutex = Qnil;
9319 io->fork_generation = GET_VM()->fork_gen;
9320
9321 if (encoding) {
9322 io->encs = *encoding;
9323 }
9324
9325 rb_update_max_fd(descriptor);
9326
9327 return self;
9328}
9329
9330static VALUE
9331prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9332{
9333 VALUE path_value = Qnil;
9334 rb_encoding *e;
9335 struct rb_io_encoding convconfig;
9336
9337 if (path) {
9338 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9339 }
9340
9341 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9342 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9343 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9346#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9347 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9348 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9349 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9350#endif
9351 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9352 convconfig.ecopts = Qnil;
9353
9354 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9355 rb_io_t*io = RFILE(self)->fptr;
9356
9357 if (!io_check_tty(io)) {
9358#ifdef __CYGWIN__
9359 io->mode |= FMODE_BINMODE;
9360 setmode(fd, O_BINARY);
9361#endif
9362 }
9363
9364 return self;
9365}
9366
9367VALUE
9368rb_io_fdopen(int fd, int oflags, const char *path)
9369{
9370 VALUE klass = rb_cIO;
9371
9372 if (path && strcmp(path, "-")) klass = rb_cFile;
9373 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9374}
9375
9376static VALUE
9377prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9378{
9379 rb_io_t *fptr;
9380 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9381
9382 GetOpenFile(io, fptr);
9384#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9385 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9386 if (fmode & FMODE_READABLE) {
9388 }
9389#endif
9390 fptr->stdio_file = f;
9391
9392 return io;
9393}
9394
9395VALUE
9396rb_io_prep_stdin(void)
9397{
9398 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9399}
9400
9401VALUE
9402rb_io_prep_stdout(void)
9403{
9404 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9405}
9406
9407VALUE
9408rb_io_prep_stderr(void)
9409{
9410 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9411}
9412
9413FILE *
9415{
9416 if (!fptr->stdio_file) {
9417 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9418 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9419 }
9420 return fptr->stdio_file;
9421}
9422
9423static inline void
9424rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9425{
9426 buf->ptr = NULL;
9427 buf->off = 0;
9428 buf->len = 0;
9429 buf->capa = 0;
9430}
9431
9432static inline rb_io_t *
9433rb_io_fptr_new(void)
9434{
9435 rb_io_t *fp = ALLOC(rb_io_t);
9436 fp->self = Qnil;
9437 fp->fd = -1;
9438 fp->stdio_file = NULL;
9439 fp->mode = 0;
9440 fp->pid = 0;
9441 fp->lineno = 0;
9442 fp->pathv = Qnil;
9443 fp->finalize = 0;
9444 rb_io_buffer_init(&fp->wbuf);
9445 rb_io_buffer_init(&fp->rbuf);
9446 rb_io_buffer_init(&fp->cbuf);
9447 fp->readconv = NULL;
9448 fp->writeconv = NULL;
9450 fp->writeconv_pre_ecflags = 0;
9452 fp->writeconv_initialized = 0;
9453 fp->tied_io_for_writing = 0;
9454 fp->encs.enc = NULL;
9455 fp->encs.enc2 = NULL;
9456 fp->encs.ecflags = 0;
9457 fp->encs.ecopts = Qnil;
9458 fp->write_lock = Qnil;
9459 fp->timeout = Qnil;
9460 ccan_list_head_init(&fp->blocking_operations);
9461 fp->closing_ec = NULL;
9462 fp->wakeup_mutex = Qnil;
9463 fp->fork_generation = GET_VM()->fork_gen;
9464 return fp;
9465}
9466
9467rb_io_t *
9468rb_io_make_open_file(VALUE obj)
9469{
9470 rb_io_t *fp = 0;
9471
9472 Check_Type(obj, T_FILE);
9473 if (RFILE(obj)->fptr) {
9474 rb_io_close(obj);
9475 rb_io_fptr_finalize(RFILE(obj)->fptr);
9476 RFILE(obj)->fptr = 0;
9477 }
9478 fp = rb_io_fptr_new();
9479 fp->self = obj;
9480 RFILE(obj)->fptr = fp;
9481 return fp;
9482}
9483
9484static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9485
9486/*
9487 * call-seq:
9488 * IO.new(fd, mode = 'r', **opts) -> io
9489 *
9490 * Creates and returns a new \IO object (file stream) from a file descriptor.
9491 *
9492 * \IO.new may be useful for interaction with low-level libraries.
9493 * For higher-level interactions, it may be simpler to create
9494 * the file stream using File.open.
9495 *
9496 * Argument +fd+ must be a valid file descriptor (integer):
9497 *
9498 * path = 't.tmp'
9499 * fd = IO.sysopen(path) # => 3
9500 * IO.new(fd) # => #<IO:fd 3>
9501 *
9502 * The new \IO object does not inherit encoding
9503 * (because the integer file descriptor does not have an encoding):
9504 *
9505 * fd = IO.sysopen('t.rus', 'rb')
9506 * io = IO.new(fd)
9507 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9508 *
9509 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9510 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9511 *
9512 * IO.new(fd, 'w') # => #<IO:fd 3>
9513 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9514 *
9515 * Optional keyword arguments +opts+ specify:
9516 *
9517 * - {Open Options}[rdoc-ref:IO@Open+Options].
9518 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9519 *
9520 * Examples:
9521 *
9522 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9523 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9524 *
9525 */
9526
9527static VALUE
9528rb_io_initialize(int argc, VALUE *argv, VALUE io)
9529{
9530 VALUE fnum, vmode;
9531 VALUE opt;
9532
9533 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9534 return io_initialize(io, fnum, vmode, opt);
9535}
9536
9537static VALUE
9538io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9539{
9540 rb_io_t *fp;
9541 int fd, oflags = O_RDONLY;
9542 enum rb_io_mode fmode;
9543 struct rb_io_encoding convconfig;
9544#if defined(HAVE_FCNTL) && defined(F_GETFL)
9545 int ofmode;
9546#else
9547 struct stat st;
9548#endif
9549
9550 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9551
9552 fd = NUM2INT(fnum);
9553 if (rb_reserved_fd_p(fd)) {
9554 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9555 }
9556#if defined(HAVE_FCNTL) && defined(F_GETFL)
9557 oflags = fcntl(fd, F_GETFL);
9558 if (oflags == -1) rb_sys_fail(0);
9559#else
9560 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9561#endif
9562 rb_update_max_fd(fd);
9563#if defined(HAVE_FCNTL) && defined(F_GETFL)
9564 ofmode = rb_io_oflags_fmode(oflags);
9565 if (NIL_P(vmode)) {
9566 fmode = ofmode;
9567 }
9568 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9569 VALUE error = INT2FIX(EINVAL);
9571 }
9572#endif
9573 VALUE path = Qnil;
9574
9575 if (!NIL_P(opt)) {
9576 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9577 fmode |= FMODE_EXTERNAL;
9578 }
9579
9580 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9581 if (!NIL_P(path)) {
9582 StringValue(path);
9583 path = rb_str_new_frozen(path);
9584 }
9585 }
9586
9587 MakeOpenFile(io, fp);
9588 fp->self = io;
9589 fp->fd = fd;
9590 fp->mode = fmode;
9591 fp->encs = convconfig;
9592 fp->pathv = path;
9593 fp->timeout = Qnil;
9594 ccan_list_head_init(&fp->blocking_operations);
9595 fp->closing_ec = NULL;
9596 fp->wakeup_mutex = Qnil;
9597 fp->fork_generation = GET_VM()->fork_gen;
9598 clear_codeconv(fp);
9599 io_check_tty(fp);
9600 if (fileno(stdin) == fd)
9601 fp->stdio_file = stdin;
9602 else if (fileno(stdout) == fd)
9603 fp->stdio_file = stdout;
9604 else if (fileno(stderr) == fd)
9605 fp->stdio_file = stderr;
9606
9607 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9608 return io;
9609}
9610
9611/*
9612 * call-seq:
9613 * set_encoding_by_bom -> encoding or nil
9614 *
9615 * If the stream begins with a BOM
9616 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9617 * consumes the BOM and sets the external encoding accordingly;
9618 * returns the result encoding if found, or +nil+ otherwise:
9619 *
9620 * File.write('t.tmp', "\u{FEFF}abc")
9621 * io = File.open('t.tmp', 'rb')
9622 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9623 * io.close
9624 *
9625 * File.write('t.tmp', 'abc')
9626 * io = File.open('t.tmp', 'rb')
9627 * io.set_encoding_by_bom # => nil
9628 * io.close
9629 *
9630 * Raises an exception if the stream is not binmode
9631 * or its encoding has already been set.
9632 *
9633 */
9634
9635static VALUE
9636rb_io_set_encoding_by_bom(VALUE io)
9637{
9638 rb_io_t *fptr;
9639
9640 GetOpenFile(io, fptr);
9641 if (!(fptr->mode & FMODE_BINMODE)) {
9642 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9643 }
9644 if (fptr->encs.enc2) {
9645 rb_raise(rb_eArgError, "encoding conversion is set");
9646 }
9647 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9648 rb_raise(rb_eArgError, "encoding is set to %s already",
9649 rb_enc_name(fptr->encs.enc));
9650 }
9651 if (!io_set_encoding_by_bom(io)) return Qnil;
9652 return rb_enc_from_encoding(fptr->encs.enc);
9653}
9654
9655/*
9656 * call-seq:
9657 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9658 *
9659 * Opens the file at the given +path+ according to the given +mode+;
9660 * creates and returns a new File object for that file.
9661 *
9662 * The new File object is buffered mode (or non-sync mode), unless
9663 * +filename+ is a tty.
9664 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9665 *
9666 * Argument +path+ must be a valid file path:
9667 *
9668 * f = File.new('/etc/fstab')
9669 * f.close
9670 * f = File.new('t.txt')
9671 * f.close
9672 *
9673 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9674 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9675 *
9676 * f = File.new('t.tmp', 'w')
9677 * f.close
9678 * f = File.new('t.tmp', File::RDONLY)
9679 * f.close
9680 *
9681 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9682 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9683 *
9684 * f = File.new('t.tmp', File::CREAT, 0644)
9685 * f.close
9686 * f = File.new('t.tmp', File::CREAT, 0444)
9687 * f.close
9688 *
9689 * Optional keyword arguments +opts+ specify:
9690 *
9691 * - {Open Options}[rdoc-ref:IO@Open+Options].
9692 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9693 *
9694 */
9695
9696static VALUE
9697rb_file_initialize(int argc, VALUE *argv, VALUE io)
9698{
9699 if (RFILE(io)->fptr) {
9700 rb_raise(rb_eRuntimeError, "reinitializing File");
9701 }
9702 VALUE fname, vmode, vperm, opt;
9703 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9704 if (posargc < 3) { /* perm is File only */
9705 VALUE fd = rb_check_to_int(fname);
9706
9707 if (!NIL_P(fd)) {
9708 return io_initialize(io, fd, vmode, opt);
9709 }
9710 }
9711 return rb_open_file(io, fname, vmode, vperm, opt);
9712}
9713
9714/* :nodoc: */
9715static VALUE
9716rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9717{
9718 if (rb_block_given_p()) {
9719 VALUE cname = rb_obj_as_string(klass);
9720
9721 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9722 cname, cname);
9723 }
9724 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9725}
9726
9727
9728/*
9729 * call-seq:
9730 * IO.for_fd(fd, mode = 'r', **opts) -> io
9731 *
9732 * Synonym for IO.new.
9733 *
9734 */
9735
9736static VALUE
9737rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9738{
9739 VALUE io = rb_obj_alloc(klass);
9740 rb_io_initialize(argc, argv, io);
9741 return io;
9742}
9743
9744/*
9745 * call-seq:
9746 * ios.autoclose? -> true or false
9747 *
9748 * Returns +true+ if the underlying file descriptor of _ios_ will be
9749 * closed at its finalization or at calling #close, otherwise +false+.
9750 */
9751
9752static VALUE
9753rb_io_autoclose_p(VALUE io)
9754{
9755 rb_io_t *fptr = RFILE(io)->fptr;
9756 rb_io_check_closed(fptr);
9757 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9758}
9759
9760/*
9761 * call-seq:
9762 * io.autoclose = bool -> true or false
9763 *
9764 * Sets auto-close flag.
9765 *
9766 * f = File.open(File::NULL)
9767 * IO.for_fd(f.fileno).close
9768 * f.gets # raises Errno::EBADF
9769 *
9770 * f = File.open(File::NULL)
9771 * g = IO.for_fd(f.fileno)
9772 * g.autoclose = false
9773 * g.close
9774 * f.gets # won't cause Errno::EBADF
9775 */
9776
9777static VALUE
9778rb_io_set_autoclose(VALUE io, VALUE autoclose)
9779{
9780 rb_io_t *fptr;
9781 GetOpenFile(io, fptr);
9782 if (!RTEST(autoclose))
9783 fptr->mode |= FMODE_EXTERNAL;
9784 else
9785 fptr->mode &= ~FMODE_EXTERNAL;
9786 return autoclose;
9787}
9788
9789static VALUE
9790io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9791{
9792 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9793
9794 if (!RB_TEST(result)) {
9795 return Qnil;
9796 }
9797
9798 int mask = RB_NUM2INT(result);
9799
9800 if (mask & event) {
9801 if (return_io)
9802 return io;
9803 else
9804 return result;
9805 }
9806 else {
9807 return Qfalse;
9808 }
9809}
9810
9811/*
9812 * call-seq:
9813 * io.wait_readable -> truthy or falsy
9814 * io.wait_readable(timeout) -> truthy or falsy
9815 *
9816 * Waits until IO is readable and returns a truthy value, or a falsy
9817 * value when times out. Returns a truthy value immediately when
9818 * buffered data is available.
9819 */
9820
9821static VALUE
9822io_wait_readable(int argc, VALUE *argv, VALUE io)
9823{
9824 rb_io_t *fptr;
9825
9826 RB_IO_POINTER(io, fptr);
9828
9829 if (rb_io_read_pending(fptr)) return Qtrue;
9830
9831 rb_check_arity(argc, 0, 1);
9832 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9833
9834 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9835}
9836
9837/*
9838 * call-seq:
9839 * io.wait_writable -> truthy or falsy
9840 * io.wait_writable(timeout) -> truthy or falsy
9841 *
9842 * Waits until IO is writable and returns a truthy value or a falsy
9843 * value when times out.
9844 */
9845static VALUE
9846io_wait_writable(int argc, VALUE *argv, VALUE io)
9847{
9848 rb_io_t *fptr;
9849
9850 RB_IO_POINTER(io, fptr);
9852
9853 rb_check_arity(argc, 0, 1);
9854 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9855
9856 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9857}
9858
9859/*
9860 * call-seq:
9861 * io.wait_priority -> truthy or falsy
9862 * io.wait_priority(timeout) -> truthy or falsy
9863 *
9864 * Waits until IO is priority and returns a truthy value or a falsy
9865 * value when times out. Priority data is sent and received using
9866 * the Socket::MSG_OOB flag and is typically limited to streams.
9867 */
9868static VALUE
9869io_wait_priority(int argc, VALUE *argv, VALUE io)
9870{
9871 rb_io_t *fptr = NULL;
9872
9873 RB_IO_POINTER(io, fptr);
9875
9876 if (rb_io_read_pending(fptr)) return Qtrue;
9877
9878 rb_check_arity(argc, 0, 1);
9879 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9880
9881 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9882}
9883
9884static int
9885wait_mode_sym(VALUE mode)
9886{
9887 if (mode == ID2SYM(rb_intern("r"))) {
9888 return RB_WAITFD_IN;
9889 }
9890 if (mode == ID2SYM(rb_intern("read"))) {
9891 return RB_WAITFD_IN;
9892 }
9893 if (mode == ID2SYM(rb_intern("readable"))) {
9894 return RB_WAITFD_IN;
9895 }
9896 if (mode == ID2SYM(rb_intern("w"))) {
9897 return RB_WAITFD_OUT;
9898 }
9899 if (mode == ID2SYM(rb_intern("write"))) {
9900 return RB_WAITFD_OUT;
9901 }
9902 if (mode == ID2SYM(rb_intern("writable"))) {
9903 return RB_WAITFD_OUT;
9904 }
9905 if (mode == ID2SYM(rb_intern("rw"))) {
9906 return RB_WAITFD_IN|RB_WAITFD_OUT;
9907 }
9908 if (mode == ID2SYM(rb_intern("read_write"))) {
9909 return RB_WAITFD_IN|RB_WAITFD_OUT;
9910 }
9911 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9912 return RB_WAITFD_IN|RB_WAITFD_OUT;
9913 }
9914
9915 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9916}
9917
9918static inline enum rb_io_event
9919io_event_from_value(VALUE value)
9920{
9921 int events = RB_NUM2INT(value);
9922
9923 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9924
9925 return events;
9926}
9927
9928/*
9929 * call-seq:
9930 * io.wait(events, timeout) -> event mask, false or nil
9931 * io.wait(*event_symbols[, timeout]) -> self, true, or false
9932 *
9933 * Waits until the IO becomes ready for the specified events and returns the
9934 * subset of events that become ready, or a falsy value when times out.
9935 *
9936 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9937 * +IO::PRIORITY+.
9938 *
9939 * Returns an event mask (truthy value) immediately when buffered data is
9940 * available.
9941 *
9942 * The second form: if one or more event symbols (+:read+, +:write+, or
9943 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
9944 * corresponding to those symbols. In this form, +timeout+ is optional, the
9945 * order of the arguments is arbitrary, and returns +io+ if any of the
9946 * events is ready.
9947 */
9948
9949static VALUE
9950io_wait(int argc, VALUE *argv, VALUE io)
9951{
9952 VALUE timeout = Qundef;
9953 enum rb_io_event events = 0;
9954 int return_io = 0;
9955
9956 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9957 // We'd prefer to return the actual mask, but this form would return the io itself:
9958 return_io = 1;
9959
9960 // Slow/messy path:
9961 for (int i = 0; i < argc; i += 1) {
9962 if (RB_SYMBOL_P(argv[i])) {
9963 events |= wait_mode_sym(argv[i]);
9964 }
9965 else if (UNDEF_P(timeout)) {
9966 rb_time_interval(timeout = argv[i]);
9967 }
9968 else {
9969 rb_raise(rb_eArgError, "timeout given more than once");
9970 }
9971 }
9972
9973 if (UNDEF_P(timeout)) timeout = Qnil;
9974
9975 if (events == 0) {
9976 events = RUBY_IO_READABLE;
9977 }
9978 }
9979 else /* argc == 2 and neither are symbols */ {
9980 // This is the fast path:
9981 events = io_event_from_value(argv[0]);
9982 timeout = argv[1];
9983 }
9984
9985 if (events & RUBY_IO_READABLE) {
9986 rb_io_t *fptr = NULL;
9987 RB_IO_POINTER(io, fptr);
9988
9989 if (rb_io_read_pending(fptr)) {
9990 // This was the original behaviour:
9991 if (return_io) return Qtrue;
9992 // New behaviour always returns an event mask:
9993 else return RB_INT2NUM(RUBY_IO_READABLE);
9994 }
9995 }
9996
9997 return io_wait_event(io, events, timeout, return_io);
9998}
9999
10000static void
10001argf_mark_and_move(void *ptr)
10002{
10003 struct argf *p = ptr;
10004 rb_gc_mark_and_move(&p->filename);
10005 rb_gc_mark_and_move(&p->current_file);
10006 rb_gc_mark_and_move(&p->argv);
10007 rb_gc_mark_and_move(&p->inplace);
10008 rb_gc_mark_and_move(&p->encs.ecopts);
10009}
10010
10011static size_t
10012argf_memsize(const void *ptr)
10013{
10014 const struct argf *p = ptr;
10015 size_t size = sizeof(*p);
10016 return size;
10017}
10018
10019static const rb_data_type_t argf_type = {
10020 "ARGF",
10021 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10022 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
10023};
10024
10025static inline void
10026argf_init(struct argf *p, VALUE v)
10027{
10028 p->filename = Qnil;
10029 p->current_file = Qnil;
10030 p->lineno = 0;
10031 p->argv = v;
10032}
10033
10034static VALUE
10035argf_alloc(VALUE klass)
10036{
10037 struct argf *p;
10038 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10039
10040 argf_init(p, Qnil);
10041 return argf;
10042}
10043
10044#undef rb_argv
10045
10046/* :nodoc: */
10047static VALUE
10048argf_initialize(VALUE argf, VALUE argv)
10049{
10050 memset(&ARGF, 0, sizeof(ARGF));
10051 argf_init(&ARGF, argv);
10052
10053 return argf;
10054}
10055
10056/* :nodoc: */
10057static VALUE
10058argf_initialize_copy(VALUE argf, VALUE orig)
10059{
10060 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10061 ARGF = argf_of(orig);
10062 ARGF.argv = rb_obj_dup(ARGF.argv);
10063 return argf;
10064}
10065
10066/*
10067 * call-seq:
10068 * ARGF.lineno = integer -> integer
10069 *
10070 * Sets the line number of ARGF as a whole to the given Integer.
10071 *
10072 * ARGF sets the line number automatically as you read data, so normally
10073 * you will not need to set it explicitly. To access the current line number
10074 * use ARGF.lineno.
10075 *
10076 * For example:
10077 *
10078 * ARGF.lineno #=> 0
10079 * ARGF.readline #=> "This is line 1\n"
10080 * ARGF.lineno #=> 1
10081 * ARGF.lineno = 0 #=> 0
10082 * ARGF.lineno #=> 0
10083 */
10084static VALUE
10085argf_set_lineno(VALUE argf, VALUE val)
10086{
10087 ARGF.lineno = NUM2INT(val);
10088 ARGF.last_lineno = ARGF.lineno;
10089 return val;
10090}
10091
10092/*
10093 * call-seq:
10094 * ARGF.lineno -> integer
10095 *
10096 * Returns the current line number of ARGF as a whole. This value
10097 * can be set manually with ARGF.lineno=.
10098 *
10099 * For example:
10100 *
10101 * ARGF.lineno #=> 0
10102 * ARGF.readline #=> "This is line 1\n"
10103 * ARGF.lineno #=> 1
10104 */
10105static VALUE
10106argf_lineno(VALUE argf)
10107{
10108 return INT2FIX(ARGF.lineno);
10109}
10110
10111static VALUE
10112argf_forward(int argc, VALUE *argv, VALUE argf)
10113{
10114 return forward_current(rb_frame_this_func(), argc, argv);
10115}
10116
10117#define next_argv() argf_next_argv(argf)
10118#define ARGF_GENERIC_INPUT_P() \
10119 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10120#define ARGF_FORWARD(argc, argv) do {\
10121 if (ARGF_GENERIC_INPUT_P())\
10122 return argf_forward((argc), (argv), argf);\
10123} while (0)
10124#define NEXT_ARGF_FORWARD(argc, argv) do {\
10125 if (!next_argv()) return Qnil;\
10126 ARGF_FORWARD((argc), (argv));\
10127} while (0)
10128
10129static void
10130argf_close(VALUE argf)
10131{
10132 VALUE file = ARGF.current_file;
10133 if (file == rb_stdin) return;
10134 if (RB_TYPE_P(file, T_FILE)) {
10135 rb_io_set_write_io(file, Qnil);
10136 }
10137 io_close(file);
10138 ARGF.init_p = -1;
10139}
10140
10141static int
10142argf_next_argv(VALUE argf)
10143{
10144 char *fn;
10145 rb_io_t *fptr;
10146 int stdout_binmode = 0;
10147 enum rb_io_mode fmode;
10148
10149 VALUE r_stdout = rb_ractor_stdout();
10150
10151 if (RB_TYPE_P(r_stdout, T_FILE)) {
10152 GetOpenFile(r_stdout, fptr);
10153 if (fptr->mode & FMODE_BINMODE)
10154 stdout_binmode = 1;
10155 }
10156
10157 if (ARGF.init_p == 0) {
10158 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10159 ARGF.next_p = 1;
10160 }
10161 else {
10162 ARGF.next_p = -1;
10163 }
10164 ARGF.init_p = 1;
10165 }
10166 else {
10167 if (NIL_P(ARGF.argv)) {
10168 ARGF.next_p = -1;
10169 }
10170 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10171 ARGF.next_p = 1;
10172 }
10173 }
10174
10175 if (ARGF.next_p == 1) {
10176 if (ARGF.init_p == 1) argf_close(argf);
10177 retry:
10178 if (RARRAY_LEN(ARGF.argv) > 0) {
10179 VALUE filename = rb_ary_shift(ARGF.argv);
10180 FilePathValue(filename);
10181 ARGF.filename = filename;
10182 filename = rb_str_encode_ospath(filename);
10183 fn = StringValueCStr(filename);
10184 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10185 ARGF.current_file = rb_stdin;
10186 if (ARGF.inplace) {
10187 rb_warn("Can't do inplace edit for stdio; skipping");
10188 goto retry;
10189 }
10190 }
10191 else {
10192 VALUE write_io = Qnil;
10193 int fr = rb_sysopen(filename, O_RDONLY, 0);
10194
10195 if (ARGF.inplace) {
10196 struct stat st;
10197#ifndef NO_SAFE_RENAME
10198 struct stat st2;
10199#endif
10200 VALUE str;
10201 int fw;
10202
10203 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10204 rb_io_close(r_stdout);
10205 }
10206 fstat(fr, &st);
10207 str = filename;
10208 if (!NIL_P(ARGF.inplace)) {
10209 VALUE suffix = ARGF.inplace;
10210 str = rb_str_dup(str);
10211 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10212 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10213 rb_enc_get(suffix), 0, Qnil))) {
10214 rb_str_append(str, suffix);
10215 }
10216#ifdef NO_SAFE_RENAME
10217 (void)close(fr);
10218 (void)unlink(RSTRING_PTR(str));
10219 if (rename(fn, RSTRING_PTR(str)) < 0) {
10220 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10221 filename, str, strerror(errno));
10222 goto retry;
10223 }
10224 fr = rb_sysopen(str, O_RDONLY, 0);
10225#else
10226 if (rename(fn, RSTRING_PTR(str)) < 0) {
10227 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10228 filename, str, strerror(errno));
10229 close(fr);
10230 goto retry;
10231 }
10232#endif
10233 }
10234 else {
10235#ifdef NO_SAFE_RENAME
10236 rb_fatal("Can't do inplace edit without backup");
10237#else
10238 if (unlink(fn) < 0) {
10239 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10240 filename, strerror(errno));
10241 close(fr);
10242 goto retry;
10243 }
10244#endif
10245 }
10246 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10247#ifndef NO_SAFE_RENAME
10248 fstat(fw, &st2);
10249#ifdef HAVE_FCHMOD
10250 fchmod(fw, st.st_mode);
10251#else
10252 chmod(fn, st.st_mode);
10253#endif
10254 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10255 int err;
10256#ifdef HAVE_FCHOWN
10257 err = fchown(fw, st.st_uid, st.st_gid);
10258#else
10259 err = chown(fn, st.st_uid, st.st_gid);
10260#endif
10261 if (err && getuid() == 0 && st2.st_uid == 0) {
10262 const char *wkfn = RSTRING_PTR(filename);
10263 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10264 filename, str, strerror(errno));
10265 (void)close(fr);
10266 (void)close(fw);
10267 (void)unlink(wkfn);
10268 goto retry;
10269 }
10270 }
10271#endif
10272 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10273 rb_ractor_stdout_set(write_io);
10274 if (stdout_binmode) rb_io_binmode(rb_stdout);
10275 }
10276 fmode = FMODE_READABLE;
10277 if (!ARGF.binmode) {
10278 fmode |= DEFAULT_TEXTMODE;
10279 }
10280 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10281 if (!NIL_P(write_io)) {
10282 rb_io_set_write_io(ARGF.current_file, write_io);
10283 }
10284 RB_GC_GUARD(filename);
10285 }
10286 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10287 GetOpenFile(ARGF.current_file, fptr);
10288 if (ARGF.encs.enc) {
10289 fptr->encs = ARGF.encs;
10290 clear_codeconv(fptr);
10291 }
10292 else {
10293 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10294 if (!ARGF.binmode) {
10296#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10297 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10298#endif
10299 }
10300 }
10301 ARGF.next_p = 0;
10302 }
10303 else {
10304 ARGF.next_p = 1;
10305 return FALSE;
10306 }
10307 }
10308 else if (ARGF.next_p == -1) {
10309 ARGF.current_file = rb_stdin;
10310 ARGF.filename = rb_str_new2("-");
10311 if (ARGF.inplace) {
10312 rb_warn("Can't do inplace edit for stdio");
10313 rb_ractor_stdout_set(orig_stdout);
10314 }
10315 }
10316 if (ARGF.init_p == -1) ARGF.init_p = 1;
10317 return TRUE;
10318}
10319
10320static VALUE
10321argf_getline(int argc, VALUE *argv, VALUE argf)
10322{
10323 VALUE line;
10324 long lineno = ARGF.lineno;
10325
10326 retry:
10327 if (!next_argv()) return Qnil;
10328 if (ARGF_GENERIC_INPUT_P()) {
10329 line = forward_current(idGets, argc, argv);
10330 }
10331 else {
10332 if (argc == 0 && rb_rs == rb_default_rs) {
10333 line = rb_io_gets(ARGF.current_file);
10334 }
10335 else {
10336 line = rb_io_getline(argc, argv, ARGF.current_file);
10337 }
10338 if (NIL_P(line) && ARGF.next_p != -1) {
10339 argf_close(argf);
10340 ARGF.next_p = 1;
10341 goto retry;
10342 }
10343 }
10344 if (!NIL_P(line)) {
10345 ARGF.lineno = ++lineno;
10346 ARGF.last_lineno = ARGF.lineno;
10347 }
10348 return line;
10349}
10350
10351static VALUE
10352argf_lineno_getter(ID id, VALUE *var)
10353{
10354 VALUE argf = *var;
10355 return INT2FIX(ARGF.last_lineno);
10356}
10357
10358static void
10359argf_lineno_setter(VALUE val, ID id, VALUE *var)
10360{
10361 VALUE argf = *var;
10362 int n = NUM2INT(val);
10363 ARGF.last_lineno = ARGF.lineno = n;
10364}
10365
10366void
10367rb_reset_argf_lineno(long n)
10368{
10369 ARGF.last_lineno = ARGF.lineno = n;
10370}
10371
10372static VALUE argf_gets(int, VALUE *, VALUE);
10373
10374/*
10375 * call-seq:
10376 * gets(sep=$/ [, getline_args]) -> string or nil
10377 * gets(limit [, getline_args]) -> string or nil
10378 * gets(sep, limit [, getline_args]) -> string or nil
10379 *
10380 * Returns (and assigns to <code>$_</code>) the next line from the list
10381 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10382 * no files are present on the command line. Returns +nil+ at end of
10383 * file. The optional argument specifies the record separator. The
10384 * separator is included with the contents of each record. A separator
10385 * of +nil+ reads the entire contents, and a zero-length separator
10386 * reads the input one paragraph at a time, where paragraphs are
10387 * divided by two consecutive newlines. If the first argument is an
10388 * integer, or optional second argument is given, the returning string
10389 * would not be longer than the given value in bytes. If multiple
10390 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10391 * the contents one file at a time.
10392 *
10393 * ARGV << "testfile"
10394 * print while gets
10395 *
10396 * <em>produces:</em>
10397 *
10398 * This is line one
10399 * This is line two
10400 * This is line three
10401 * And so on...
10402 *
10403 * The style of programming using <code>$_</code> as an implicit
10404 * parameter is gradually losing favor in the Ruby community.
10405 */
10406
10407static VALUE
10408rb_f_gets(int argc, VALUE *argv, VALUE recv)
10409{
10410 if (recv == argf) {
10411 return argf_gets(argc, argv, argf);
10412 }
10413 return forward(argf, idGets, argc, argv);
10414}
10415
10416/*
10417 * call-seq:
10418 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10419 * ARGF.gets(limit [, getline_args]) -> string or nil
10420 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10421 *
10422 * Returns the next line from the current file in ARGF.
10423 *
10424 * By default lines are assumed to be separated by <code>$/</code>;
10425 * to use a different character as a separator, supply it as a String
10426 * for the _sep_ argument.
10427 *
10428 * The optional _limit_ argument specifies how many characters of each line
10429 * to return. By default all characters are returned.
10430 *
10431 * See IO.readlines for details about getline_args.
10432 *
10433 */
10434static VALUE
10435argf_gets(int argc, VALUE *argv, VALUE argf)
10436{
10437 VALUE line;
10438
10439 line = argf_getline(argc, argv, argf);
10440 rb_lastline_set(line);
10441
10442 return line;
10443}
10444
10445VALUE
10447{
10448 VALUE line;
10449
10450 if (rb_rs != rb_default_rs) {
10451 return rb_f_gets(0, 0, argf);
10452 }
10453
10454 retry:
10455 if (!next_argv()) return Qnil;
10456 line = rb_io_gets(ARGF.current_file);
10457 if (NIL_P(line) && ARGF.next_p != -1) {
10458 rb_io_close(ARGF.current_file);
10459 ARGF.next_p = 1;
10460 goto retry;
10461 }
10462 rb_lastline_set(line);
10463 if (!NIL_P(line)) {
10464 ARGF.lineno++;
10465 ARGF.last_lineno = ARGF.lineno;
10466 }
10467
10468 return line;
10469}
10470
10471static VALUE argf_readline(int, VALUE *, VALUE);
10472
10473/*
10474 * call-seq:
10475 * readline(sep = $/, chomp: false) -> string
10476 * readline(limit, chomp: false) -> string
10477 * readline(sep, limit, chomp: false) -> string
10478 *
10479 * Equivalent to method Kernel#gets, except that it raises an exception
10480 * if called at end-of-stream:
10481 *
10482 * $ cat t.txt | ruby -e "p readlines; readline"
10483 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10484 * in `readline': end of file reached (EOFError)
10485 *
10486 * Optional keyword argument +chomp+ specifies whether line separators
10487 * are to be omitted.
10488 */
10489
10490static VALUE
10491rb_f_readline(int argc, VALUE *argv, VALUE recv)
10492{
10493 if (recv == argf) {
10494 return argf_readline(argc, argv, argf);
10495 }
10496 return forward(argf, rb_intern("readline"), argc, argv);
10497}
10498
10499
10500/*
10501 * call-seq:
10502 * ARGF.readline(sep=$/) -> string
10503 * ARGF.readline(limit) -> string
10504 * ARGF.readline(sep, limit) -> string
10505 *
10506 * Returns the next line from the current file in ARGF.
10507 *
10508 * By default lines are assumed to be separated by <code>$/</code>;
10509 * to use a different character as a separator, supply it as a String
10510 * for the _sep_ argument.
10511 *
10512 * The optional _limit_ argument specifies how many characters of each line
10513 * to return. By default all characters are returned.
10514 *
10515 * An EOFError is raised at the end of the file.
10516 */
10517static VALUE
10518argf_readline(int argc, VALUE *argv, VALUE argf)
10519{
10520 VALUE line;
10521
10522 if (!next_argv()) rb_eof_error();
10523 ARGF_FORWARD(argc, argv);
10524 line = argf_gets(argc, argv, argf);
10525 if (NIL_P(line)) {
10526 rb_eof_error();
10527 }
10528
10529 return line;
10530}
10531
10532static VALUE argf_readlines(int, VALUE *, VALUE);
10533
10534/*
10535 * call-seq:
10536 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10537 * readlines(limit, chomp: false, **enc_opts) -> array
10538 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10539 *
10540 * Returns an array containing the lines returned by calling
10541 * Kernel#gets until the end-of-stream is reached;
10542 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10543 *
10544 * With only string argument +sep+ given,
10545 * returns the remaining lines as determined by line separator +sep+,
10546 * or +nil+ if none;
10547 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10548 *
10549 * # Default separator.
10550 * $ cat t.txt | ruby -e "p readlines"
10551 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10552 *
10553 * # Specified separator.
10554 * $ cat t.txt | ruby -e "p readlines 'li'"
10555 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10556 *
10557 * # Get-all separator.
10558 * $ cat t.txt | ruby -e "p readlines nil"
10559 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10560 *
10561 * # Get-paragraph separator.
10562 * $ cat t.txt | ruby -e "p readlines ''"
10563 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10564 *
10565 * With only integer argument +limit+ given,
10566 * limits the number of bytes in the line;
10567 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10568 *
10569 * $cat t.txt | ruby -e "p readlines 10"
10570 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10571 *
10572 * $cat t.txt | ruby -e "p readlines 11"
10573 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10574 *
10575 * $cat t.txt | ruby -e "p readlines 12"
10576 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10577 *
10578 * With arguments +sep+ and +limit+ given,
10579 * combines the two behaviors
10580 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10581 *
10582 * Optional keyword argument +chomp+ specifies whether line separators
10583 * are to be omitted:
10584 *
10585 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10586 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10587 *
10588 * Optional keyword arguments +enc_opts+ specify encoding options;
10589 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10590 *
10591 */
10592
10593static VALUE
10594rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10595{
10596 if (recv == argf) {
10597 return argf_readlines(argc, argv, argf);
10598 }
10599 return forward(argf, rb_intern("readlines"), argc, argv);
10600}
10601
10602/*
10603 * call-seq:
10604 * ARGF.readlines(sep = $/, chomp: false) -> array
10605 * ARGF.readlines(limit, chomp: false) -> array
10606 * ARGF.readlines(sep, limit, chomp: false) -> array
10607 *
10608 * ARGF.to_a(sep = $/, chomp: false) -> array
10609 * ARGF.to_a(limit, chomp: false) -> array
10610 * ARGF.to_a(sep, limit, chomp: false) -> array
10611 *
10612 * Reads each file in ARGF in its entirety, returning an Array containing
10613 * lines from the files. Lines are assumed to be separated by _sep_.
10614 *
10615 * lines = ARGF.readlines
10616 * lines[0] #=> "This is line one\n"
10617 *
10618 * See +IO.readlines+ for a full description of all options.
10619 */
10620static VALUE
10621argf_readlines(int argc, VALUE *argv, VALUE argf)
10622{
10623 long lineno = ARGF.lineno;
10624 VALUE lines, ary;
10625
10626 ary = rb_ary_new();
10627 while (next_argv()) {
10628 if (ARGF_GENERIC_INPUT_P()) {
10629 lines = forward_current(rb_intern("readlines"), argc, argv);
10630 }
10631 else {
10632 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10633 argf_close(argf);
10634 }
10635 ARGF.next_p = 1;
10636 rb_ary_concat(ary, lines);
10637 ARGF.lineno = lineno + RARRAY_LEN(ary);
10638 ARGF.last_lineno = ARGF.lineno;
10639 }
10640 ARGF.init_p = 0;
10641 return ary;
10642}
10643
10644/*
10645 * call-seq:
10646 * `command` -> string
10647 *
10648 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10649 * sets global variable <tt>$?</tt> to the process status.
10650 *
10651 * This method has potential security vulnerabilities if called with untrusted input;
10652 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
10653 *
10654 * Examples:
10655 *
10656 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10657 * $ `echo oops && exit 99` # => "oops\n"
10658 * $ $? # => #<Process::Status: pid 17088 exit 99>
10659 * $ $?.exitstatus # => 99
10660 *
10661 * The built-in syntax <tt>%x{...}</tt> uses this method.
10662 *
10663 */
10664
10665static VALUE
10666rb_f_backquote(VALUE obj, VALUE str)
10667{
10668 VALUE port;
10669 VALUE result;
10670 rb_io_t *fptr;
10671
10672 StringValue(str);
10673 rb_last_status_clear();
10674 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10675 if (NIL_P(port)) return rb_str_new(0,0);
10676
10677 GetOpenFile(port, fptr);
10678 result = read_all(fptr, remain_size(fptr), Qnil);
10679 rb_io_close(port);
10680 rb_io_fptr_cleanup_all(fptr);
10681 RB_GC_GUARD(port);
10682
10683 return result;
10684}
10685
10686#ifdef HAVE_SYS_SELECT_H
10687#include <sys/select.h>
10688#endif
10689
10690static VALUE
10691select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10692{
10693 VALUE res, list;
10694 rb_fdset_t *rp, *wp, *ep;
10695 rb_io_t *fptr;
10696 long i;
10697 int max = 0, n;
10698 int pending = 0;
10699 struct timeval timerec;
10700
10701 if (!NIL_P(read)) {
10702 Check_Type(read, T_ARRAY);
10703 for (i=0; i<RARRAY_LEN(read); i++) {
10704 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10705 rb_fd_set(fptr->fd, &fds[0]);
10706 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10707 pending++;
10708 rb_fd_set(fptr->fd, &fds[3]);
10709 }
10710 if (max < fptr->fd) max = fptr->fd;
10711 }
10712 if (pending) { /* no blocking if there's buffered data */
10713 timerec.tv_sec = timerec.tv_usec = 0;
10714 tp = &timerec;
10715 }
10716 rp = &fds[0];
10717 }
10718 else
10719 rp = 0;
10720
10721 if (!NIL_P(write)) {
10722 Check_Type(write, T_ARRAY);
10723 for (i=0; i<RARRAY_LEN(write); i++) {
10724 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10725 GetOpenFile(write_io, fptr);
10726 rb_fd_set(fptr->fd, &fds[1]);
10727 if (max < fptr->fd) max = fptr->fd;
10728 }
10729 wp = &fds[1];
10730 }
10731 else
10732 wp = 0;
10733
10734 if (!NIL_P(except)) {
10735 Check_Type(except, T_ARRAY);
10736 for (i=0; i<RARRAY_LEN(except); i++) {
10737 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10738 VALUE write_io = GetWriteIO(io);
10739 GetOpenFile(io, fptr);
10740 rb_fd_set(fptr->fd, &fds[2]);
10741 if (max < fptr->fd) max = fptr->fd;
10742 if (io != write_io) {
10743 GetOpenFile(write_io, fptr);
10744 rb_fd_set(fptr->fd, &fds[2]);
10745 if (max < fptr->fd) max = fptr->fd;
10746 }
10747 }
10748 ep = &fds[2];
10749 }
10750 else {
10751 ep = 0;
10752 }
10753
10754 max++;
10755
10756 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10757 if (n < 0) {
10758 rb_sys_fail(0);
10759 }
10760 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10761
10762 res = rb_ary_new2(3);
10763 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10764 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10765 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10766
10767 if (rp) {
10768 list = RARRAY_AREF(res, 0);
10769 for (i=0; i< RARRAY_LEN(read); i++) {
10770 VALUE obj = rb_ary_entry(read, i);
10771 VALUE io = rb_io_get_io(obj);
10772 GetOpenFile(io, fptr);
10773 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10774 rb_fd_isset(fptr->fd, &fds[3])) {
10775 rb_ary_push(list, obj);
10776 }
10777 }
10778 }
10779
10780 if (wp) {
10781 list = RARRAY_AREF(res, 1);
10782 for (i=0; i< RARRAY_LEN(write); i++) {
10783 VALUE obj = rb_ary_entry(write, i);
10784 VALUE io = rb_io_get_io(obj);
10785 VALUE write_io = GetWriteIO(io);
10786 GetOpenFile(write_io, fptr);
10787 if (rb_fd_isset(fptr->fd, &fds[1])) {
10788 rb_ary_push(list, obj);
10789 }
10790 }
10791 }
10792
10793 if (ep) {
10794 list = RARRAY_AREF(res, 2);
10795 for (i=0; i< RARRAY_LEN(except); i++) {
10796 VALUE obj = rb_ary_entry(except, i);
10797 VALUE io = rb_io_get_io(obj);
10798 VALUE write_io = GetWriteIO(io);
10799 GetOpenFile(io, fptr);
10800 if (rb_fd_isset(fptr->fd, &fds[2])) {
10801 rb_ary_push(list, obj);
10802 }
10803 else if (io != write_io) {
10804 GetOpenFile(write_io, fptr);
10805 if (rb_fd_isset(fptr->fd, &fds[2])) {
10806 rb_ary_push(list, obj);
10807 }
10808 }
10809 }
10810 }
10811
10812 return res; /* returns an empty array on interrupt */
10813}
10814
10816 VALUE read, write, except;
10817 struct timeval *timeout;
10818 rb_fdset_t fdsets[4];
10819};
10820
10821static VALUE
10822select_call(VALUE arg)
10823{
10824 struct select_args *p = (struct select_args *)arg;
10825
10826 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10827}
10828
10829static VALUE
10830select_end(VALUE arg)
10831{
10832 struct select_args *p = (struct select_args *)arg;
10833 int i;
10834
10835 for (i = 0; i < numberof(p->fdsets); ++i)
10836 rb_fd_term(&p->fdsets[i]);
10837 return Qnil;
10838}
10839
10840static VALUE sym_normal, sym_sequential, sym_random,
10841 sym_willneed, sym_dontneed, sym_noreuse;
10842
10843#ifdef HAVE_POSIX_FADVISE
10844struct io_advise_struct {
10845 int fd;
10846 int advice;
10847 rb_off_t offset;
10848 rb_off_t len;
10849};
10850
10851static VALUE
10852io_advise_internal(void *arg)
10853{
10854 struct io_advise_struct *ptr = arg;
10855 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10856}
10857
10858static VALUE
10859io_advise_sym_to_const(VALUE sym)
10860{
10861#ifdef POSIX_FADV_NORMAL
10862 if (sym == sym_normal)
10863 return INT2NUM(POSIX_FADV_NORMAL);
10864#endif
10865
10866#ifdef POSIX_FADV_RANDOM
10867 if (sym == sym_random)
10868 return INT2NUM(POSIX_FADV_RANDOM);
10869#endif
10870
10871#ifdef POSIX_FADV_SEQUENTIAL
10872 if (sym == sym_sequential)
10873 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10874#endif
10875
10876#ifdef POSIX_FADV_WILLNEED
10877 if (sym == sym_willneed)
10878 return INT2NUM(POSIX_FADV_WILLNEED);
10879#endif
10880
10881#ifdef POSIX_FADV_DONTNEED
10882 if (sym == sym_dontneed)
10883 return INT2NUM(POSIX_FADV_DONTNEED);
10884#endif
10885
10886#ifdef POSIX_FADV_NOREUSE
10887 if (sym == sym_noreuse)
10888 return INT2NUM(POSIX_FADV_NOREUSE);
10889#endif
10890
10891 return Qnil;
10892}
10893
10894static VALUE
10895do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10896{
10897 int rv;
10898 struct io_advise_struct ias;
10899 VALUE num_adv;
10900
10901 num_adv = io_advise_sym_to_const(advice);
10902
10903 /*
10904 * The platform doesn't support this hint. We don't raise exception, instead
10905 * silently ignore it. Because IO::advise is only hint.
10906 */
10907 if (NIL_P(num_adv))
10908 return Qnil;
10909
10910 ias.fd = fptr->fd;
10911 ias.advice = NUM2INT(num_adv);
10912 ias.offset = offset;
10913 ias.len = len;
10914
10915 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10916 if (rv && rv != ENOSYS) {
10917 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10918 it returns the error code. */
10919 VALUE message = rb_sprintf("%"PRIsVALUE" "
10920 "(%"PRI_OFFT_PREFIX"d, "
10921 "%"PRI_OFFT_PREFIX"d, "
10922 "%"PRIsVALUE")",
10923 fptr->pathv, offset, len, advice);
10924 rb_syserr_fail_str(rv, message);
10925 }
10926
10927 return Qnil;
10928}
10929
10930#endif /* HAVE_POSIX_FADVISE */
10931
10932static void
10933advice_arg_check(VALUE advice)
10934{
10935 if (!SYMBOL_P(advice))
10936 rb_raise(rb_eTypeError, "advice must be a Symbol");
10937
10938 if (advice != sym_normal &&
10939 advice != sym_sequential &&
10940 advice != sym_random &&
10941 advice != sym_willneed &&
10942 advice != sym_dontneed &&
10943 advice != sym_noreuse) {
10944 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10945 }
10946}
10947
10948/*
10949 * call-seq:
10950 * advise(advice, offset = 0, len = 0) -> nil
10951 *
10952 * Invokes Posix system call
10953 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10954 * which announces an intention to access data from the current file
10955 * in a particular manner.
10956 *
10957 * The arguments and results are platform-dependent.
10958 *
10959 * The relevant data is specified by:
10960 *
10961 * - +offset+: The offset of the first byte of data.
10962 * - +len+: The number of bytes to be accessed;
10963 * if +len+ is zero, or is larger than the number of bytes remaining,
10964 * all remaining bytes will be accessed.
10965 *
10966 * Argument +advice+ is one of the following symbols:
10967 *
10968 * - +:normal+: The application has no advice to give
10969 * about its access pattern for the specified data.
10970 * If no advice is given for an open file, this is the default assumption.
10971 * - +:sequential+: The application expects to access the specified data sequentially
10972 * (with lower offsets read before higher ones).
10973 * - +:random+: The specified data will be accessed in random order.
10974 * - +:noreuse+: The specified data will be accessed only once.
10975 * - +:willneed+: The specified data will be accessed in the near future.
10976 * - +:dontneed+: The specified data will not be accessed in the near future.
10977 *
10978 * Not implemented on all platforms.
10979 *
10980 */
10981static VALUE
10982rb_io_advise(int argc, VALUE *argv, VALUE io)
10983{
10984 VALUE advice, offset, len;
10985 rb_off_t off, l;
10986 rb_io_t *fptr;
10987
10988 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10989 advice_arg_check(advice);
10990
10991 io = GetWriteIO(io);
10992 GetOpenFile(io, fptr);
10993
10994 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10995 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10996
10997#ifdef HAVE_POSIX_FADVISE
10998 return do_io_advise(fptr, advice, off, l);
10999#else
11000 ((void)off, (void)l); /* Ignore all hint */
11001 return Qnil;
11002#endif
11003}
11004
11005static int
11006is_pos_inf(VALUE x)
11007{
11008 double f;
11009 if (!RB_FLOAT_TYPE_P(x))
11010 return 0;
11011 f = RFLOAT_VALUE(x);
11012 return isinf(f) && 0 < f;
11013}
11014
11015/*
11016 * call-seq:
11017 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11018 *
11019 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
11020 * which monitors multiple file descriptors,
11021 * waiting until one or more of the file descriptors
11022 * becomes ready for some class of I/O operation.
11023 *
11024 * Not implemented on all platforms.
11025 *
11026 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11027 * is an array of IO objects.
11028 *
11029 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11030 * interval in seconds.
11031 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11032 * +nil+ and +Float::INFINITY+ means no timeout.
11033 *
11034 * The method monitors the \IO objects given in all three arrays,
11035 * waiting for some to be ready;
11036 * returns a 3-element array whose elements are:
11037 *
11038 * - An array of the objects in +read_ios+ that are ready for reading.
11039 * - An array of the objects in +write_ios+ that are ready for writing.
11040 * - An array of the objects in +error_ios+ have pending exceptions.
11041 *
11042 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11043 *
11044 * \IO.select peeks the buffer of \IO objects for testing readability.
11045 * If the \IO buffer is not empty, \IO.select immediately notifies
11046 * readability. This "peek" only happens for \IO objects. It does not
11047 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11048 *
11049 * The best way to use \IO.select is invoking it after non-blocking
11050 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11051 * raise an exception which is extended by IO::WaitReadable or
11052 * IO::WaitWritable. The modules notify how the caller should wait
11053 * with \IO.select. If IO::WaitReadable is raised, the caller should
11054 * wait for reading. If IO::WaitWritable is raised, the caller should
11055 * wait for writing.
11056 *
11057 * So, blocking read (#readpartial) can be emulated using
11058 * #read_nonblock and \IO.select as follows:
11059 *
11060 * begin
11061 * result = io_like.read_nonblock(maxlen)
11062 * rescue IO::WaitReadable
11063 * IO.select([io_like])
11064 * retry
11065 * rescue IO::WaitWritable
11066 * IO.select(nil, [io_like])
11067 * retry
11068 * end
11069 *
11070 * Especially, the combination of non-blocking methods and \IO.select is
11071 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11072 * has #to_io method to return underlying IO object. IO.select calls
11073 * #to_io to obtain the file descriptor to wait.
11074 *
11075 * This means that readability notified by \IO.select doesn't mean
11076 * readability from OpenSSL::SSL::SSLSocket object.
11077 *
11078 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11079 * some data. \IO.select doesn't see the buffer. So \IO.select can
11080 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11081 *
11082 * However, several more complicated situations exist.
11083 *
11084 * SSL is a protocol which is sequence of records.
11085 * The record consists of multiple bytes.
11086 * So, the remote side of SSL sends a partial record, IO.select
11087 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11088 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11089 *
11090 * Also, the remote side can request SSL renegotiation which forces
11091 * the local SSL engine to write some data.
11092 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11093 * system call and it can block.
11094 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11095 * IO::WaitWritable instead of blocking.
11096 * So, the caller should wait for ready for writability as above
11097 * example.
11098 *
11099 * The combination of non-blocking methods and \IO.select is also useful
11100 * for streams such as tty, pipe socket socket when multiple processes
11101 * read from a stream.
11102 *
11103 * Finally, Linux kernel developers don't guarantee that
11104 * readability of select(2) means readability of following read(2) even
11105 * for a single process;
11106 * see {select(2)}[https://linux.die.net/man/2/select]
11107 *
11108 * Invoking \IO.select before IO#readpartial works well as usual.
11109 * However it is not the best way to use \IO.select.
11110 *
11111 * The writability notified by select(2) doesn't show
11112 * how many bytes are writable.
11113 * IO#write method blocks until given whole string is written.
11114 * So, <tt>IO#write(two or more bytes)</tt> can block after
11115 * writability is notified by \IO.select. IO#write_nonblock is required
11116 * to avoid the blocking.
11117 *
11118 * Blocking write (#write) can be emulated using #write_nonblock and
11119 * IO.select as follows: IO::WaitReadable should also be rescued for
11120 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11121 *
11122 * while 0 < string.bytesize
11123 * begin
11124 * written = io_like.write_nonblock(string)
11125 * rescue IO::WaitReadable
11126 * IO.select([io_like])
11127 * retry
11128 * rescue IO::WaitWritable
11129 * IO.select(nil, [io_like])
11130 * retry
11131 * end
11132 * string = string.byteslice(written..-1)
11133 * end
11134 *
11135 * Example:
11136 *
11137 * rp, wp = IO.pipe
11138 * mesg = "ping "
11139 * 100.times {
11140 * # IO.select follows IO#read. Not the best way to use IO.select.
11141 * rs, ws, = IO.select([rp], [wp])
11142 * if r = rs[0]
11143 * ret = r.read(5)
11144 * print ret
11145 * case ret
11146 * when /ping/
11147 * mesg = "pong\n"
11148 * when /pong/
11149 * mesg = "ping "
11150 * end
11151 * end
11152 * if w = ws[0]
11153 * w.write(mesg)
11154 * end
11155 * }
11156 *
11157 * Output:
11158 *
11159 * ping pong
11160 * ping pong
11161 * ping pong
11162 * (snipped)
11163 * ping
11164 *
11165 */
11166
11167static VALUE
11168rb_f_select(int argc, VALUE *argv, VALUE obj)
11169{
11170 VALUE scheduler = rb_fiber_scheduler_current();
11171 if (scheduler != Qnil) {
11172 // It's optionally supported.
11173 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11174 if (!UNDEF_P(result)) return result;
11175 }
11176
11177 VALUE timeout;
11178 struct select_args args;
11179 struct timeval timerec;
11180 int i;
11181
11182 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11183 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11184 args.timeout = 0;
11185 }
11186 else {
11187 timerec = rb_time_interval(timeout);
11188 args.timeout = &timerec;
11189 }
11190
11191 for (i = 0; i < numberof(args.fdsets); ++i)
11192 rb_fd_init(&args.fdsets[i]);
11193
11194 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11195}
11196
11197#ifdef IOCTL_REQ_TYPE
11198 typedef IOCTL_REQ_TYPE ioctl_req_t;
11199#else
11200 typedef int ioctl_req_t;
11201# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11202#endif
11203
11204#ifdef HAVE_IOCTL
11205struct ioctl_arg {
11206 int fd;
11207 ioctl_req_t cmd;
11208 long narg;
11209};
11210
11211static VALUE
11212nogvl_ioctl(void *ptr)
11213{
11214 struct ioctl_arg *arg = ptr;
11215
11216 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11217}
11218
11219static int
11220do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11221{
11222 int retval;
11223 struct ioctl_arg arg;
11224
11225 arg.fd = io->fd;
11226 arg.cmd = cmd;
11227 arg.narg = narg;
11228
11229 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11230
11231 return retval;
11232}
11233#endif
11234
11235#define DEFAULT_IOCTL_NARG_LEN (256)
11236
11237#if defined(__linux__) && defined(_IOC_SIZE)
11238static long
11239linux_iocparm_len(ioctl_req_t cmd)
11240{
11241 long len;
11242
11243 if ((cmd & 0xFFFF0000) == 0) {
11244 /* legacy and unstructured ioctl number. */
11245 return DEFAULT_IOCTL_NARG_LEN;
11246 }
11247
11248 len = _IOC_SIZE(cmd);
11249
11250 /* paranoia check for silly drivers which don't keep ioctl convention */
11251 if (len < DEFAULT_IOCTL_NARG_LEN)
11252 len = DEFAULT_IOCTL_NARG_LEN;
11253
11254 return len;
11255}
11256#endif
11257
11258#ifdef HAVE_IOCTL
11259static long
11260ioctl_narg_len(ioctl_req_t cmd)
11261{
11262 long len;
11263
11264#ifdef IOCPARM_MASK
11265#ifndef IOCPARM_LEN
11266#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11267#endif
11268#endif
11269#ifdef IOCPARM_LEN
11270 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11271#elif defined(__linux__) && defined(_IOC_SIZE)
11272 len = linux_iocparm_len(cmd);
11273#else
11274 /* otherwise guess at what's safe */
11275 len = DEFAULT_IOCTL_NARG_LEN;
11276#endif
11277
11278 return len;
11279}
11280#endif
11281
11282#ifdef HAVE_FCNTL
11283#ifdef __linux__
11284typedef long fcntl_arg_t;
11285#else
11286/* posix */
11287typedef int fcntl_arg_t;
11288#endif
11289
11290static long
11291fcntl_narg_len(ioctl_req_t cmd)
11292{
11293 long len;
11294
11295 switch (cmd) {
11296#ifdef F_DUPFD
11297 case F_DUPFD:
11298 len = sizeof(fcntl_arg_t);
11299 break;
11300#endif
11301#ifdef F_DUP2FD /* bsd specific */
11302 case F_DUP2FD:
11303 len = sizeof(int);
11304 break;
11305#endif
11306#ifdef F_DUPFD_CLOEXEC /* linux specific */
11307 case F_DUPFD_CLOEXEC:
11308 len = sizeof(fcntl_arg_t);
11309 break;
11310#endif
11311#ifdef F_GETFD
11312 case F_GETFD:
11313 len = 1;
11314 break;
11315#endif
11316#ifdef F_SETFD
11317 case F_SETFD:
11318 len = sizeof(fcntl_arg_t);
11319 break;
11320#endif
11321#ifdef F_GETFL
11322 case F_GETFL:
11323 len = 1;
11324 break;
11325#endif
11326#ifdef F_SETFL
11327 case F_SETFL:
11328 len = sizeof(fcntl_arg_t);
11329 break;
11330#endif
11331#ifdef F_GETOWN
11332 case F_GETOWN:
11333 len = 1;
11334 break;
11335#endif
11336#ifdef F_SETOWN
11337 case F_SETOWN:
11338 len = sizeof(fcntl_arg_t);
11339 break;
11340#endif
11341#ifdef F_GETOWN_EX /* linux specific */
11342 case F_GETOWN_EX:
11343 len = sizeof(struct f_owner_ex);
11344 break;
11345#endif
11346#ifdef F_SETOWN_EX /* linux specific */
11347 case F_SETOWN_EX:
11348 len = sizeof(struct f_owner_ex);
11349 break;
11350#endif
11351#ifdef F_GETLK
11352 case F_GETLK:
11353 len = sizeof(struct flock);
11354 break;
11355#endif
11356#ifdef F_SETLK
11357 case F_SETLK:
11358 len = sizeof(struct flock);
11359 break;
11360#endif
11361#ifdef F_SETLKW
11362 case F_SETLKW:
11363 len = sizeof(struct flock);
11364 break;
11365#endif
11366#ifdef F_READAHEAD /* bsd specific */
11367 case F_READAHEAD:
11368 len = sizeof(int);
11369 break;
11370#endif
11371#ifdef F_RDAHEAD /* Darwin specific */
11372 case F_RDAHEAD:
11373 len = sizeof(int);
11374 break;
11375#endif
11376#ifdef F_GETSIG /* linux specific */
11377 case F_GETSIG:
11378 len = 1;
11379 break;
11380#endif
11381#ifdef F_SETSIG /* linux specific */
11382 case F_SETSIG:
11383 len = sizeof(fcntl_arg_t);
11384 break;
11385#endif
11386#ifdef F_GETLEASE /* linux specific */
11387 case F_GETLEASE:
11388 len = 1;
11389 break;
11390#endif
11391#ifdef F_SETLEASE /* linux specific */
11392 case F_SETLEASE:
11393 len = sizeof(fcntl_arg_t);
11394 break;
11395#endif
11396#ifdef F_NOTIFY /* linux specific */
11397 case F_NOTIFY:
11398 len = sizeof(fcntl_arg_t);
11399 break;
11400#endif
11401
11402 default:
11403 len = 256;
11404 break;
11405 }
11406
11407 return len;
11408}
11409#else /* HAVE_FCNTL */
11410static long
11411fcntl_narg_len(ioctl_req_t cmd)
11412{
11413 return 0;
11414}
11415#endif /* HAVE_FCNTL */
11416
11417#define NARG_SENTINEL 17
11418
11419static long
11420setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11421{
11422 long narg = 0;
11423 VALUE arg = *argp;
11424
11425 if (!RTEST(arg)) {
11426 narg = 0;
11427 }
11428 else if (FIXNUM_P(arg)) {
11429 narg = FIX2LONG(arg);
11430 }
11431 else if (arg == Qtrue) {
11432 narg = 1;
11433 }
11434 else {
11435 VALUE tmp = rb_check_string_type(arg);
11436
11437 if (NIL_P(tmp)) {
11438 narg = NUM2LONG(arg);
11439 }
11440 else {
11441 char *ptr;
11442 long len, slen;
11443
11444 *argp = arg = tmp;
11445 len = narg_len(cmd);
11446 rb_str_modify(arg);
11447
11448 slen = RSTRING_LEN(arg);
11449 /* expand for data + sentinel. */
11450 if (slen < len+1) {
11451 rb_str_resize(arg, len+1);
11452 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11453 slen = len+1;
11454 }
11455 /* a little sanity check here */
11456 ptr = RSTRING_PTR(arg);
11457 ptr[slen - 1] = NARG_SENTINEL;
11458 narg = (long)(SIGNED_VALUE)ptr;
11459 }
11460 }
11461
11462 return narg;
11463}
11464
11465static VALUE
11466finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11467{
11468 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11469 if (RB_TYPE_P(arg, T_STRING)) {
11470 char *ptr;
11471 long slen;
11472 RSTRING_GETMEM(arg, ptr, slen);
11473 if (ptr[slen-1] != NARG_SENTINEL)
11474 rb_raise(rb_eArgError, "return value overflowed string");
11475 ptr[slen-1] = '\0';
11476 }
11477
11478 return INT2NUM(retval);
11479}
11480
11481#ifdef HAVE_IOCTL
11482static VALUE
11483rb_ioctl(VALUE io, VALUE req, VALUE arg)
11484{
11485 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11486 rb_io_t *fptr;
11487 long narg;
11488 int retval;
11489
11490 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11491 GetOpenFile(io, fptr);
11492 retval = do_ioctl(fptr, cmd, narg);
11493 return finish_narg(retval, arg, fptr);
11494}
11495
11496/*
11497 * call-seq:
11498 * ioctl(integer_cmd, argument) -> integer
11499 *
11500 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11501 * which issues a low-level command to an I/O device.
11502 *
11503 * Issues a low-level command to an I/O device.
11504 * The arguments and returned value are platform-dependent.
11505 * The effect of the call is platform-dependent.
11506 *
11507 * If argument +argument+ is an integer, it is passed directly;
11508 * if it is a string, it is interpreted as a binary sequence of bytes.
11509 *
11510 * Not implemented on all platforms.
11511 *
11512 */
11513
11514static VALUE
11515rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11516{
11517 VALUE req, arg;
11518
11519 rb_scan_args(argc, argv, "11", &req, &arg);
11520 return rb_ioctl(io, req, arg);
11521}
11522#else
11523#define rb_io_ioctl rb_f_notimplement
11524#endif
11525
11526#ifdef HAVE_FCNTL
11527struct fcntl_arg {
11528 int fd;
11529 int cmd;
11530 long narg;
11531};
11532
11533static VALUE
11534nogvl_fcntl(void *ptr)
11535{
11536 struct fcntl_arg *arg = ptr;
11537
11538#if defined(F_DUPFD)
11539 if (arg->cmd == F_DUPFD)
11540 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11541#endif
11542 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11543}
11544
11545static int
11546do_fcntl(struct rb_io *io, int cmd, long narg)
11547{
11548 int retval;
11549 struct fcntl_arg arg;
11550
11551 arg.fd = io->fd;
11552 arg.cmd = cmd;
11553 arg.narg = narg;
11554
11555 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11556 if (retval != -1) {
11557 switch (cmd) {
11558#if defined(F_DUPFD)
11559 case F_DUPFD:
11560#endif
11561#if defined(F_DUPFD_CLOEXEC)
11562 case F_DUPFD_CLOEXEC:
11563#endif
11564 rb_update_max_fd(retval);
11565 }
11566 }
11567
11568 return retval;
11569}
11570
11571static VALUE
11572rb_fcntl(VALUE io, VALUE req, VALUE arg)
11573{
11574 int cmd = NUM2INT(req);
11575 rb_io_t *fptr;
11576 long narg;
11577 int retval;
11578
11579 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11580 GetOpenFile(io, fptr);
11581 retval = do_fcntl(fptr, cmd, narg);
11582 return finish_narg(retval, arg, fptr);
11583}
11584
11585/*
11586 * call-seq:
11587 * fcntl(integer_cmd, argument) -> integer
11588 *
11589 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11590 * which provides a mechanism for issuing low-level commands to control or query
11591 * a file-oriented I/O stream. Arguments and results are platform
11592 * dependent.
11593 *
11594 * If +argument+ is a number, its value is passed directly;
11595 * if it is a string, it is interpreted as a binary sequence of bytes.
11596 * (Array#pack might be a useful way to build this string.)
11597 *
11598 * Not implemented on all platforms.
11599 *
11600 */
11601
11602static VALUE
11603rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11604{
11605 VALUE req, arg;
11606
11607 rb_scan_args(argc, argv, "11", &req, &arg);
11608 return rb_fcntl(io, req, arg);
11609}
11610#else
11611#define rb_io_fcntl rb_f_notimplement
11612#endif
11613
11614#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11615/*
11616 * call-seq:
11617 * syscall(integer_callno, *arguments) -> integer
11618 *
11619 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11620 * which calls a specified function.
11621 *
11622 * Calls the operating system function identified by +integer_callno+;
11623 * returns the result of the function or raises SystemCallError if it failed.
11624 * The effect of the call is platform-dependent.
11625 * The arguments and returned value are platform-dependent.
11626 *
11627 * For each of +arguments+: if it is an integer, it is passed directly;
11628 * if it is a string, it is interpreted as a binary sequence of bytes.
11629 * There may be as many as nine such arguments.
11630 *
11631 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11632 * are platform-dependent.
11633 *
11634 * Note: Method +syscall+ is essentially unsafe and unportable.
11635 * The DL (Fiddle) library is preferred for safer and a bit
11636 * more portable programming.
11637 *
11638 * Not implemented on all platforms.
11639 *
11640 */
11641
11642static VALUE
11643rb_f_syscall(int argc, VALUE *argv, VALUE _)
11644{
11645 VALUE arg[8];
11646#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11647# define SYSCALL __syscall
11648# define NUM2SYSCALLID(x) NUM2LONG(x)
11649# define RETVAL2NUM(x) LONG2NUM(x)
11650# if SIZEOF_LONG == 8
11651 long num, retval = -1;
11652# elif SIZEOF_LONG_LONG == 8
11653 long long num, retval = -1;
11654# else
11655# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11656# endif
11657#elif defined(__linux__)
11658# define SYSCALL syscall
11659# define NUM2SYSCALLID(x) NUM2LONG(x)
11660# define RETVAL2NUM(x) LONG2NUM(x)
11661 /*
11662 * Linux man page says, syscall(2) function prototype is below.
11663 *
11664 * int syscall(int number, ...);
11665 *
11666 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11667 */
11668 long num, retval = -1;
11669#else
11670# define SYSCALL syscall
11671# define NUM2SYSCALLID(x) NUM2INT(x)
11672# define RETVAL2NUM(x) INT2NUM(x)
11673 int num, retval = -1;
11674#endif
11675 int i;
11676
11677 if (RTEST(ruby_verbose)) {
11679 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11680 }
11681
11682 if (argc == 0)
11683 rb_raise(rb_eArgError, "too few arguments for syscall");
11684 if (argc > numberof(arg))
11685 rb_raise(rb_eArgError, "too many arguments for syscall");
11686 num = NUM2SYSCALLID(argv[0]); ++argv;
11687 for (i = argc - 1; i--; ) {
11688 VALUE v = rb_check_string_type(argv[i]);
11689
11690 if (!NIL_P(v)) {
11691 StringValue(v);
11692 rb_str_modify(v);
11693 arg[i] = (VALUE)StringValueCStr(v);
11694 }
11695 else {
11696 arg[i] = (VALUE)NUM2LONG(argv[i]);
11697 }
11698 }
11699
11700 switch (argc) {
11701 case 1:
11702 retval = SYSCALL(num);
11703 break;
11704 case 2:
11705 retval = SYSCALL(num, arg[0]);
11706 break;
11707 case 3:
11708 retval = SYSCALL(num, arg[0],arg[1]);
11709 break;
11710 case 4:
11711 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11712 break;
11713 case 5:
11714 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11715 break;
11716 case 6:
11717 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11718 break;
11719 case 7:
11720 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11721 break;
11722 case 8:
11723 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11724 break;
11725 }
11726
11727 if (retval == -1)
11728 rb_sys_fail(0);
11729 return RETVAL2NUM(retval);
11730#undef SYSCALL
11731#undef NUM2SYSCALLID
11732#undef RETVAL2NUM
11733}
11734#else
11735#define rb_f_syscall rb_f_notimplement
11736#endif
11737
11738static VALUE
11739io_new_instance(VALUE args)
11740{
11741 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11742}
11743
11744static rb_encoding *
11745find_encoding(VALUE v)
11746{
11747 rb_encoding *enc = rb_find_encoding(v);
11748 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11749 return enc;
11750}
11751
11752static void
11753io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11754{
11755 rb_encoding *enc, *enc2;
11756 int ecflags = fptr->encs.ecflags;
11757 VALUE ecopts, tmp;
11758
11759 if (!NIL_P(v2)) {
11760 enc2 = find_encoding(v1);
11761 tmp = rb_check_string_type(v2);
11762 if (!NIL_P(tmp)) {
11763 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11764 /* Special case - "-" => no transcoding */
11765 enc = enc2;
11766 enc2 = NULL;
11767 }
11768 else
11769 enc = find_encoding(v2);
11770 if (enc == enc2) {
11771 /* Special case - "-" => no transcoding */
11772 enc2 = NULL;
11773 }
11774 }
11775 else {
11776 enc = find_encoding(v2);
11777 if (enc == enc2) {
11778 /* Special case - "-" => no transcoding */
11779 enc2 = NULL;
11780 }
11781 }
11782 if (enc2 == rb_ascii8bit_encoding()) {
11783 /* If external is ASCII-8BIT, no transcoding */
11784 enc = enc2;
11785 enc2 = NULL;
11786 }
11787 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11788 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11789 }
11790 else {
11791 if (NIL_P(v1)) {
11792 /* Set to default encodings */
11793 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11794 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11795 ecopts = Qnil;
11796 }
11797 else {
11798 tmp = rb_check_string_type(v1);
11799 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11800 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11801 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11802 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11803 }
11804 else {
11805 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11806 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11807 ecopts = Qnil;
11808 }
11809 }
11810 }
11811 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11812 fptr->encs.enc = enc;
11813 fptr->encs.enc2 = enc2;
11814 fptr->encs.ecflags = ecflags;
11815 fptr->encs.ecopts = ecopts;
11816 clear_codeconv(fptr);
11817
11818}
11819
11821 rb_io_t *fptr;
11822 VALUE v1;
11823 VALUE v2;
11824 VALUE opt;
11825};
11826
11827static VALUE
11828io_encoding_set_v(VALUE v)
11829{
11830 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11831 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11832 return Qnil;
11833}
11834
11835static VALUE
11836pipe_pair_close(VALUE rw)
11837{
11838 VALUE *rwp = (VALUE *)rw;
11839 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11840}
11841
11842/*
11843 * call-seq:
11844 * IO.pipe(**opts) -> [read_io, write_io]
11845 * IO.pipe(enc, **opts) -> [read_io, write_io]
11846 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11847 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11848 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11849 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11850 *
11851 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11852 * connected to each other.
11853 *
11854 * If argument +enc_string+ is given, it must be a string containing one of:
11855 *
11856 * - The name of the encoding to be used as the external encoding.
11857 * - The colon-separated names of two encodings to be used as the external
11858 * and internal encodings.
11859 *
11860 * If argument +int_enc+ is given, it must be an Encoding object
11861 * or encoding name string that specifies the internal encoding to be used;
11862 * if argument +ext_enc+ is also given, it must be an Encoding object
11863 * or encoding name string that specifies the external encoding to be used.
11864 *
11865 * The string read from +read_io+ is tagged with the external encoding;
11866 * if an internal encoding is also specified, the string is converted
11867 * to, and tagged with, that encoding.
11868 *
11869 * If any encoding is specified,
11870 * optional hash arguments specify the conversion option.
11871 *
11872 * Optional keyword arguments +opts+ specify:
11873 *
11874 * - {Open Options}[rdoc-ref:IO@Open+Options].
11875 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11876 *
11877 * With no block given, returns the two endpoints in an array:
11878 *
11879 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11880 *
11881 * With a block given, calls the block with the two endpoints;
11882 * closes both endpoints and returns the value of the block:
11883 *
11884 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11885 *
11886 * Output:
11887 *
11888 * #<IO:fd 6>
11889 * #<IO:fd 7>
11890 *
11891 * Not available on all platforms.
11892 *
11893 * In the example below, the two processes close the ends of the pipe
11894 * that they are not using. This is not just a cosmetic nicety. The
11895 * read end of a pipe will not generate an end of file condition if
11896 * there are any writers with the pipe still open. In the case of the
11897 * parent process, the <tt>rd.read</tt> will never return if it
11898 * does not first issue a <tt>wr.close</tt>:
11899 *
11900 * rd, wr = IO.pipe
11901 *
11902 * if fork
11903 * wr.close
11904 * puts "Parent got: <#{rd.read}>"
11905 * rd.close
11906 * Process.wait
11907 * else
11908 * rd.close
11909 * puts 'Sending message to parent'
11910 * wr.write "Hi Dad"
11911 * wr.close
11912 * end
11913 *
11914 * <em>produces:</em>
11915 *
11916 * Sending message to parent
11917 * Parent got: <Hi Dad>
11918 *
11919 */
11920
11921static VALUE
11922rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11923{
11924 int pipes[2], state;
11925 VALUE r, w, args[3], v1, v2;
11926 VALUE opt;
11927 rb_io_t *fptr, *fptr2;
11928 struct io_encoding_set_args ies_args;
11929 enum rb_io_mode fmode = 0;
11930 VALUE ret;
11931
11932 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11933 if (rb_pipe(pipes) < 0)
11934 rb_sys_fail(0);
11935
11936 args[0] = klass;
11937 args[1] = INT2NUM(pipes[0]);
11938 args[2] = INT2FIX(O_RDONLY);
11939 r = rb_protect(io_new_instance, (VALUE)args, &state);
11940 if (state) {
11941 close(pipes[0]);
11942 close(pipes[1]);
11943 rb_jump_tag(state);
11944 }
11945 GetOpenFile(r, fptr);
11946
11947 ies_args.fptr = fptr;
11948 ies_args.v1 = v1;
11949 ies_args.v2 = v2;
11950 ies_args.opt = opt;
11951 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11952 if (state) {
11953 close(pipes[1]);
11954 io_close(r);
11955 rb_jump_tag(state);
11956 }
11957
11958 args[1] = INT2NUM(pipes[1]);
11959 args[2] = INT2FIX(O_WRONLY);
11960 w = rb_protect(io_new_instance, (VALUE)args, &state);
11961 if (state) {
11962 close(pipes[1]);
11963 if (!NIL_P(r)) rb_io_close(r);
11964 rb_jump_tag(state);
11965 }
11966 GetOpenFile(w, fptr2);
11967 rb_io_synchronized(fptr2);
11968
11969 extract_binmode(opt, &fmode);
11970
11971 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11974 }
11975
11976#if DEFAULT_TEXTMODE
11977 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11978 fptr->mode &= ~FMODE_TEXTMODE;
11979 setmode(fptr->fd, O_BINARY);
11980 }
11981#if RUBY_CRLF_ENVIRONMENT
11984 }
11985#endif
11986#endif
11987 fptr->mode |= fmode;
11988#if DEFAULT_TEXTMODE
11989 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11990 fptr2->mode &= ~FMODE_TEXTMODE;
11991 setmode(fptr2->fd, O_BINARY);
11992 }
11993#endif
11994 fptr2->mode |= fmode;
11995
11996 ret = rb_assoc_new(r, w);
11997 if (rb_block_given_p()) {
11998 VALUE rw[2];
11999 rw[0] = r;
12000 rw[1] = w;
12001 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12002 }
12003 return ret;
12004}
12005
12007 int argc;
12008 VALUE *argv;
12009 VALUE io;
12010};
12011
12012static void
12013open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12014{
12015 VALUE path, v;
12016 VALUE vmode = Qnil, vperm = Qnil;
12017
12018 path = *argv++;
12019 argc--;
12020 FilePathValue(path);
12021 arg->io = 0;
12022 arg->argc = argc;
12023 arg->argv = argv;
12024 if (NIL_P(opt)) {
12025 vmode = INT2NUM(O_RDONLY);
12026 vperm = INT2FIX(0666);
12027 }
12028 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12029 int n;
12030
12031 v = rb_to_array_type(v);
12032 n = RARRAY_LENINT(v);
12033 rb_check_arity(n, 0, 3); /* rb_io_open */
12034 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12035 }
12036 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12037}
12038
12039static VALUE
12040io_s_foreach(VALUE v)
12041{
12042 struct getline_arg *arg = (void *)v;
12043 VALUE str;
12044
12045 if (arg->limit == 0)
12046 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12047 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12048 rb_lastline_set(str);
12049 rb_yield(str);
12050 }
12052 return Qnil;
12053}
12054
12055/*
12056 * call-seq:
12057 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12058 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12059 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12060 * IO.foreach(...) -> an_enumerator
12061 *
12062 * Calls the block with each successive line read from the stream.
12063 *
12064 * When called from class \IO (but not subclasses of \IO),
12065 * this method has potential security vulnerabilities if called with untrusted input;
12066 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12067 *
12068 * The first argument must be a string that is the path to a file.
12069 *
12070 * With only argument +path+ given, parses lines from the file at the given +path+,
12071 * as determined by the default line separator,
12072 * and calls the block with each successive line:
12073 *
12074 * File.foreach('t.txt') {|line| p line }
12075 *
12076 * Output: the same as above.
12077 *
12078 * For both forms, command and path, the remaining arguments are the same.
12079 *
12080 * With argument +sep+ given, parses lines as determined by that line separator
12081 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12082 *
12083 * File.foreach('t.txt', 'li') {|line| p line }
12084 *
12085 * Output:
12086 *
12087 * "First li"
12088 * "ne\nSecond li"
12089 * "ne\n\nThird li"
12090 * "ne\nFourth li"
12091 * "ne\n"
12092 *
12093 * Each paragraph:
12094 *
12095 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12096 *
12097 * Output:
12098 *
12099 * "First line\nSecond line\n\n"
12100 * "Third line\nFourth line\n"
12101 *
12102 * With argument +limit+ given, parses lines as determined by the default
12103 * line separator and the given line-length limit
12104 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12105 *
12106 * File.foreach('t.txt', 7) {|line| p line }
12107 *
12108 * Output:
12109 *
12110 * "First l"
12111 * "ine\n"
12112 * "Second "
12113 * "line\n"
12114 * "\n"
12115 * "Third l"
12116 * "ine\n"
12117 * "Fourth l"
12118 * "line\n"
12119 *
12120 * With arguments +sep+ and +limit+ given,
12121 * combines the two behaviors
12122 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12123 *
12124 * Optional keyword arguments +opts+ specify:
12125 *
12126 * - {Open Options}[rdoc-ref:IO@Open+Options].
12127 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12128 * - {Line Options}[rdoc-ref:IO@Line+IO].
12129 *
12130 * Returns an Enumerator if no block is given.
12131 *
12132 */
12133
12134static VALUE
12135rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12136{
12137 VALUE opt;
12138 int orig_argc = argc;
12139 struct foreach_arg arg;
12140 struct getline_arg garg;
12141
12142 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12143 RETURN_ENUMERATOR(self, orig_argc, argv);
12144 extract_getline_args(argc-1, argv+1, &garg);
12145 open_key_args(self, argc, argv, opt, &arg);
12146 if (NIL_P(arg.io)) return Qnil;
12147 extract_getline_opts(opt, &garg);
12148 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12149 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12150}
12151
12152static VALUE
12153io_s_readlines(VALUE v)
12154{
12155 struct getline_arg *arg = (void *)v;
12156 return io_readlines(arg, arg->io);
12157}
12158
12159/*
12160 * call-seq:
12161 * IO.readlines(path, sep = $/, **opts) -> array
12162 * IO.readlines(path, limit, **opts) -> array
12163 * IO.readlines(path, sep, limit, **opts) -> array
12164 *
12165 * Returns an array of all lines read from the stream.
12166 *
12167 * When called from class \IO (but not subclasses of \IO),
12168 * this method has potential security vulnerabilities if called with untrusted input;
12169 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12170 *
12171 * The first argument must be a string that is the path to a file.
12172 *
12173 * With only argument +path+ given, parses lines from the file at the given +path+,
12174 * as determined by the default line separator,
12175 * and returns those lines in an array:
12176 *
12177 * IO.readlines('t.txt')
12178 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12179 *
12180 * With argument +sep+ given, parses lines as determined by that line separator
12181 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12182 *
12183 * # Ordinary separator.
12184 * IO.readlines('t.txt', 'li')
12185 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12186 * # Get-paragraphs separator.
12187 * IO.readlines('t.txt', '')
12188 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12189 * # Get-all separator.
12190 * IO.readlines('t.txt', nil)
12191 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12192 *
12193 * With argument +limit+ given, parses lines as determined by the default
12194 * line separator and the given line-length limit
12195 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12196 *
12197 * IO.readlines('t.txt', 7)
12198 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12199 *
12200 * With arguments +sep+ and +limit+ given,
12201 * combines the two behaviors
12202 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12203 *
12204 * Optional keyword arguments +opts+ specify:
12205 *
12206 * - {Open Options}[rdoc-ref:IO@Open+Options].
12207 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12208 * - {Line Options}[rdoc-ref:IO@Line+IO].
12209 *
12210 */
12211
12212static VALUE
12213rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12214{
12215 VALUE opt;
12216 struct foreach_arg arg;
12217 struct getline_arg garg;
12218
12219 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12220 extract_getline_args(argc-1, argv+1, &garg);
12221 open_key_args(io, argc, argv, opt, &arg);
12222 if (NIL_P(arg.io)) return Qnil;
12223 extract_getline_opts(opt, &garg);
12224 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12225 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12226}
12227
12228static VALUE
12229io_s_read(VALUE v)
12230{
12231 struct foreach_arg *arg = (void *)v;
12232 return io_read(arg->argc, arg->argv, arg->io);
12233}
12234
12235struct seek_arg {
12236 VALUE io;
12237 VALUE offset;
12238 int mode;
12239};
12240
12241static VALUE
12242seek_before_access(VALUE argp)
12243{
12244 struct seek_arg *arg = (struct seek_arg *)argp;
12245 rb_io_binmode(arg->io);
12246 return rb_io_seek(arg->io, arg->offset, arg->mode);
12247}
12248
12249/*
12250 * call-seq:
12251 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12252 *
12253 * Opens the stream, reads and returns some or all of its content,
12254 * and closes the stream; returns +nil+ if no bytes were read.
12255 *
12256 * When called from class \IO (but not subclasses of \IO),
12257 * this method has potential security vulnerabilities if called with untrusted input;
12258 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12259 *
12260 * The first argument must be a string that is the path to a file.
12261 *
12262 * With only argument +path+ given, reads in text mode and returns the entire content
12263 * of the file at the given path:
12264 *
12265 * IO.read('t.txt')
12266 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12267 *
12268 * On Windows, text mode can terminate reading and leave bytes in the file
12269 * unread when encountering certain special bytes. Consider using
12270 * IO.binread if all bytes in the file should be read.
12271 *
12272 * With argument +length+, returns +length+ bytes if available:
12273 *
12274 * IO.read('t.txt', 7) # => "First l"
12275 * IO.read('t.txt', 700)
12276 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12277 *
12278 * With arguments +length+ and +offset+, returns +length+ bytes
12279 * if available, beginning at the given +offset+:
12280 *
12281 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12282 * IO.read('t.txt', 10, 200) # => nil
12283 *
12284 * Optional keyword arguments +opts+ specify:
12285 *
12286 * - {Open Options}[rdoc-ref:IO@Open+Options].
12287 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12288 *
12289 */
12290
12291static VALUE
12292rb_io_s_read(int argc, VALUE *argv, VALUE io)
12293{
12294 VALUE opt, offset;
12295 long off;
12296 struct foreach_arg arg;
12297
12298 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12299 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12300 rb_raise(rb_eArgError, "negative offset %ld given", off);
12301 }
12302 open_key_args(io, argc, argv, opt, &arg);
12303 if (NIL_P(arg.io)) return Qnil;
12304 if (!NIL_P(offset)) {
12305 struct seek_arg sarg;
12306 int state = 0;
12307 sarg.io = arg.io;
12308 sarg.offset = offset;
12309 sarg.mode = SEEK_SET;
12310 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12311 if (state) {
12312 rb_io_close(arg.io);
12313 rb_jump_tag(state);
12314 }
12315 if (arg.argc == 2) arg.argc = 1;
12316 }
12317 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12318}
12319
12320/*
12321 * call-seq:
12322 * IO.binread(path, length = nil, offset = 0) -> string or nil
12323 *
12324 * Behaves like IO.read, except that the stream is opened in binary mode
12325 * with ASCII-8BIT encoding.
12326 *
12327 * When called from class \IO (but not subclasses of \IO),
12328 * this method has potential security vulnerabilities if called with untrusted input;
12329 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12330 *
12331 */
12332
12333static VALUE
12334rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12335{
12336 VALUE offset;
12337 struct foreach_arg arg;
12338 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12339 enum {
12340 oflags = O_RDONLY
12341#ifdef O_BINARY
12342 |O_BINARY
12343#endif
12344 };
12345 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12346
12347 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12348 FilePathValue(argv[0]);
12349 convconfig.enc = rb_ascii8bit_encoding();
12350 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12351 if (NIL_P(arg.io)) return Qnil;
12352 arg.argv = argv+1;
12353 arg.argc = (argc > 1) ? 1 : 0;
12354 if (!NIL_P(offset)) {
12355 struct seek_arg sarg;
12356 int state = 0;
12357 sarg.io = arg.io;
12358 sarg.offset = offset;
12359 sarg.mode = SEEK_SET;
12360 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12361 if (state) {
12362 rb_io_close(arg.io);
12363 rb_jump_tag(state);
12364 }
12365 }
12366 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12367}
12368
12369static VALUE
12370io_s_write0(VALUE v)
12371{
12372 struct write_arg *arg = (void *)v;
12373 return io_write(arg->io,arg->str,arg->nosync);
12374}
12375
12376static VALUE
12377io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12378{
12379 VALUE string, offset, opt;
12380 struct foreach_arg arg;
12381 struct write_arg warg;
12382
12383 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12384
12385 if (NIL_P(opt)) opt = rb_hash_new();
12386 else opt = rb_hash_dup(opt);
12387
12388
12389 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12390 int mode = O_WRONLY|O_CREAT;
12391#ifdef O_BINARY
12392 if (binary) mode |= O_BINARY;
12393#endif
12394 if (NIL_P(offset)) mode |= O_TRUNC;
12395 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12396 }
12397 open_key_args(klass, argc, argv, opt, &arg);
12398
12399#ifndef O_BINARY
12400 if (binary) rb_io_binmode_m(arg.io);
12401#endif
12402
12403 if (NIL_P(arg.io)) return Qnil;
12404 if (!NIL_P(offset)) {
12405 struct seek_arg sarg;
12406 int state = 0;
12407 sarg.io = arg.io;
12408 sarg.offset = offset;
12409 sarg.mode = SEEK_SET;
12410 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12411 if (state) {
12412 rb_io_close(arg.io);
12413 rb_jump_tag(state);
12414 }
12415 }
12416
12417 warg.io = arg.io;
12418 warg.str = string;
12419 warg.nosync = 0;
12420
12421 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12422}
12423
12424/*
12425 * call-seq:
12426 * IO.write(path, data, offset = 0, **opts) -> integer
12427 *
12428 * Opens the stream, writes the given +data+ to it,
12429 * and closes the stream; returns the number of bytes written.
12430 *
12431 * When called from class \IO (but not subclasses of \IO),
12432 * this method has potential security vulnerabilities if called with untrusted input;
12433 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12434 *
12435 * The first argument must be a string that is the path to a file.
12436 *
12437 * With only argument +path+ given, writes the given +data+ to the file at that path:
12438 *
12439 * IO.write('t.tmp', 'abc') # => 3
12440 * File.read('t.tmp') # => "abc"
12441 *
12442 * If +offset+ is zero (the default), the file is overwritten:
12443 *
12444 * IO.write('t.tmp', 'A') # => 1
12445 * File.read('t.tmp') # => "A"
12446 *
12447 * If +offset+ in within the file content, the file is partly overwritten:
12448 *
12449 * IO.write('t.tmp', 'abcdef') # => 3
12450 * File.read('t.tmp') # => "abcdef"
12451 * # Offset within content.
12452 * IO.write('t.tmp', '012', 2) # => 3
12453 * File.read('t.tmp') # => "ab012f"
12454 *
12455 * If +offset+ is outside the file content,
12456 * the file is padded with null characters <tt>"\u0000"</tt>:
12457 *
12458 * IO.write('t.tmp', 'xyz', 10) # => 3
12459 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12460 *
12461 * Optional keyword arguments +opts+ specify:
12462 *
12463 * - {Open Options}[rdoc-ref:IO@Open+Options].
12464 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12465 *
12466 */
12467
12468static VALUE
12469rb_io_s_write(int argc, VALUE *argv, VALUE io)
12470{
12471 return io_s_write(argc, argv, io, 0);
12472}
12473
12474/*
12475 * call-seq:
12476 * IO.binwrite(path, string, offset = 0) -> integer
12477 *
12478 * Behaves like IO.write, except that the stream is opened in binary mode
12479 * with ASCII-8BIT encoding.
12480 *
12481 * When called from class \IO (but not subclasses of \IO),
12482 * this method has potential security vulnerabilities if called with untrusted input;
12483 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12484 *
12485 */
12486
12487static VALUE
12488rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12489{
12490 return io_s_write(argc, argv, io, 1);
12491}
12492
12494 VALUE src;
12495 VALUE dst;
12496 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12497 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12498
12499 rb_io_t *src_fptr;
12500 rb_io_t *dst_fptr;
12501 unsigned close_src : 1;
12502 unsigned close_dst : 1;
12503 int error_no;
12504 rb_off_t total;
12505 const char *syserr;
12506 const char *notimp;
12507 VALUE th;
12508 struct stat src_stat;
12509 struct stat dst_stat;
12510#ifdef HAVE_FCOPYFILE
12511 copyfile_state_t copyfile_state;
12512#endif
12513};
12514
12515static void *
12516exec_interrupts(void *arg)
12517{
12518 VALUE th = (VALUE)arg;
12519 rb_thread_execute_interrupts(th);
12520 return NULL;
12521}
12522
12523/*
12524 * returns TRUE if the preceding system call was interrupted
12525 * so we can continue. If the thread was interrupted, we
12526 * reacquire the GVL to execute interrupts before continuing.
12527 */
12528static int
12529maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12530{
12531 switch (errno) {
12532 case EINTR:
12533#if defined(ERESTART)
12534 case ERESTART:
12535#endif
12536 if (rb_thread_interrupted(stp->th)) {
12537 if (has_gvl)
12538 rb_thread_execute_interrupts(stp->th);
12539 else
12540 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12541 }
12542 return TRUE;
12543 }
12544 return FALSE;
12545}
12546
12548 VALUE scheduler;
12549
12550 rb_io_t *fptr;
12551 short events;
12552
12553 VALUE result;
12554};
12555
12556static void *
12557fiber_scheduler_wait_for(void * _arguments)
12558{
12559 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12560
12561 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12562
12563 return NULL;
12564}
12565
12566#if USE_POLL
12567# define IOWAIT_SYSCALL "poll"
12568STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12569STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12570static int
12571nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12572{
12574 if (scheduler != Qnil) {
12575 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12576 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12577 return RTEST(args.result);
12578 }
12579
12580 int fd = fptr->fd;
12581 if (fd == -1) return 0;
12582
12583 struct pollfd fds;
12584
12585 fds.fd = fd;
12586 fds.events = events;
12587
12588 int timeout_milliseconds = -1;
12589
12590 if (timeout) {
12591 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12592 }
12593
12594 return poll(&fds, 1, timeout_milliseconds);
12595}
12596#else /* !USE_POLL */
12597# define IOWAIT_SYSCALL "select"
12598static int
12599nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12600{
12602 if (scheduler != Qnil) {
12603 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12604 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12605 return RTEST(args.result);
12606 }
12607
12608 int fd = fptr->fd;
12609
12610 if (fd == -1) {
12611 errno = EBADF;
12612 return -1;
12613 }
12614
12615 rb_fdset_t fds;
12616 int ret;
12617
12618 rb_fd_init(&fds);
12619 rb_fd_set(fd, &fds);
12620
12621 switch (events) {
12622 case RB_WAITFD_IN:
12623 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12624 break;
12625 case RB_WAITFD_OUT:
12626 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12627 break;
12628 default:
12629 VM_UNREACHABLE(nogvl_wait_for);
12630 }
12631
12632 rb_fd_term(&fds);
12633
12634 // On timeout, this returns 0.
12635 return ret;
12636}
12637#endif /* !USE_POLL */
12638
12639static int
12640maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12641{
12642 int ret;
12643
12644 do {
12645 if (has_gvl) {
12647 }
12648 else {
12649 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12650 }
12651 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12652
12653 if (ret < 0) {
12654 stp->syserr = IOWAIT_SYSCALL;
12655 stp->error_no = errno;
12656 return ret;
12657 }
12658 return 0;
12659}
12660
12661static int
12662nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12663{
12664 int ret;
12665
12666 do {
12667 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12668 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12669
12670 if (ret < 0) {
12671 stp->syserr = IOWAIT_SYSCALL;
12672 stp->error_no = errno;
12673 return ret;
12674 }
12675 return 0;
12676}
12677
12678#ifdef USE_COPY_FILE_RANGE
12679
12680static ssize_t
12681simple_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)
12682{
12683#ifdef HAVE_COPY_FILE_RANGE
12684 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12685#else
12686 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12687#endif
12688}
12689
12690static int
12691nogvl_copy_file_range(struct copy_stream_struct *stp)
12692{
12693 ssize_t ss;
12694 rb_off_t src_size;
12695 rb_off_t copy_length, src_offset, *src_offset_ptr;
12696
12697 if (!S_ISREG(stp->src_stat.st_mode))
12698 return 0;
12699
12700 src_size = stp->src_stat.st_size;
12701 src_offset = stp->src_offset;
12702 if (src_offset >= (rb_off_t)0) {
12703 src_offset_ptr = &src_offset;
12704 }
12705 else {
12706 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12707 }
12708
12709 copy_length = stp->copy_length;
12710 if (copy_length < (rb_off_t)0) {
12711 if (src_offset < (rb_off_t)0) {
12712 rb_off_t current_offset;
12713 errno = 0;
12714 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12715 if (current_offset < (rb_off_t)0 && errno) {
12716 stp->syserr = "lseek";
12717 stp->error_no = errno;
12718 return (int)current_offset;
12719 }
12720 copy_length = src_size - current_offset;
12721 }
12722 else {
12723 copy_length = src_size - src_offset;
12724 }
12725 }
12726
12727 retry_copy_file_range:
12728# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12729 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12730 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12731# else
12732 ss = (ssize_t)copy_length;
12733# endif
12734 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12735 if (0 < ss) {
12736 stp->total += ss;
12737 copy_length -= ss;
12738 if (0 < copy_length) {
12739 goto retry_copy_file_range;
12740 }
12741 }
12742 if (ss < 0) {
12743 if (maygvl_copy_stream_continue_p(0, stp)) {
12744 goto retry_copy_file_range;
12745 }
12746 switch (errno) {
12747 case EINVAL:
12748 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12749 docker container) */
12750#ifdef ENOSYS
12751 case ENOSYS:
12752#endif
12753#ifdef EXDEV
12754 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12755#endif
12756 return 0;
12757 case EAGAIN:
12758#if EWOULDBLOCK != EAGAIN
12759 case EWOULDBLOCK:
12760#endif
12761 {
12762 int ret = nogvl_copy_stream_wait_write(stp);
12763 if (ret < 0) return ret;
12764 }
12765 goto retry_copy_file_range;
12766 case EBADF:
12767 {
12768 int e = errno;
12769 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12770
12771 if (flags != -1 && flags & O_APPEND) {
12772 return 0;
12773 }
12774 errno = e;
12775 }
12776 }
12777 stp->syserr = "copy_file_range";
12778 stp->error_no = errno;
12779 return (int)ss;
12780 }
12781 return 1;
12782}
12783#endif
12784
12785#ifdef HAVE_FCOPYFILE
12786static int
12787nogvl_fcopyfile(struct copy_stream_struct *stp)
12788{
12789 rb_off_t cur, ss = 0;
12790 const rb_off_t src_offset = stp->src_offset;
12791 int ret;
12792
12793 if (stp->copy_length >= (rb_off_t)0) {
12794 /* copy_length can't be specified in fcopyfile(3) */
12795 return 0;
12796 }
12797
12798 if (!S_ISREG(stp->src_stat.st_mode))
12799 return 0;
12800
12801 if (!S_ISREG(stp->dst_stat.st_mode))
12802 return 0;
12803 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12804 return 0;
12805 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12806 /* fcopyfile(3) appends src IO to dst IO and then truncates
12807 * dst IO to src IO's original size. */
12808 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12809 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12810 if (end > (rb_off_t)0) return 0;
12811 }
12812
12813 if (src_offset > (rb_off_t)0) {
12814 rb_off_t r;
12815
12816 /* get current offset */
12817 errno = 0;
12818 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12819 if (cur < (rb_off_t)0 && errno) {
12820 stp->error_no = errno;
12821 return 1;
12822 }
12823
12824 errno = 0;
12825 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12826 if (r < (rb_off_t)0 && errno) {
12827 stp->error_no = errno;
12828 return 1;
12829 }
12830 }
12831
12832 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12833 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12834 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12835
12836 if (ret == 0) { /* success */
12837 stp->total = ss;
12838 if (src_offset > (rb_off_t)0) {
12839 rb_off_t r;
12840 errno = 0;
12841 /* reset offset */
12842 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12843 if (r < (rb_off_t)0 && errno) {
12844 stp->error_no = errno;
12845 return 1;
12846 }
12847 }
12848 }
12849 else {
12850 switch (errno) {
12851 case ENOTSUP:
12852 case EPERM:
12853 case EINVAL:
12854 return 0;
12855 }
12856 stp->syserr = "fcopyfile";
12857 stp->error_no = errno;
12858 return (int)ret;
12859 }
12860 return 1;
12861}
12862#endif
12863
12864#ifdef HAVE_SENDFILE
12865
12866# ifdef __linux__
12867# define USE_SENDFILE
12868
12869# ifdef HAVE_SYS_SENDFILE_H
12870# include <sys/sendfile.h>
12871# endif
12872
12873static ssize_t
12874simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12875{
12876 return sendfile(out_fd, in_fd, offset, (size_t)count);
12877}
12878
12879# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12880/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12881 * without cpuset -l 0.
12882 */
12883# define USE_SENDFILE
12884
12885static ssize_t
12886simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12887{
12888 int r;
12889 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12890 rb_off_t sbytes;
12891# ifdef __APPLE__
12892 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12893 sbytes = count;
12894# else
12895 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12896# endif
12897 if (r != 0 && sbytes == 0) return r;
12898 if (offset) {
12899 *offset += sbytes;
12900 }
12901 else {
12902 lseek(in_fd, sbytes, SEEK_CUR);
12903 }
12904 return (ssize_t)sbytes;
12905}
12906
12907# endif
12908
12909#endif
12910
12911#ifdef USE_SENDFILE
12912static int
12913nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12914{
12915 ssize_t ss;
12916 rb_off_t src_size;
12917 rb_off_t copy_length;
12918 rb_off_t src_offset;
12919 int use_pread;
12920
12921 if (!S_ISREG(stp->src_stat.st_mode))
12922 return 0;
12923
12924 src_size = stp->src_stat.st_size;
12925#ifndef __linux__
12926 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12927 return 0;
12928#endif
12929
12930 src_offset = stp->src_offset;
12931 use_pread = src_offset >= (rb_off_t)0;
12932
12933 copy_length = stp->copy_length;
12934 if (copy_length < (rb_off_t)0) {
12935 if (use_pread)
12936 copy_length = src_size - src_offset;
12937 else {
12938 rb_off_t cur;
12939 errno = 0;
12940 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12941 if (cur < (rb_off_t)0 && errno) {
12942 stp->syserr = "lseek";
12943 stp->error_no = errno;
12944 return (int)cur;
12945 }
12946 copy_length = src_size - cur;
12947 }
12948 }
12949
12950 retry_sendfile:
12951# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12952 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12953 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12954# else
12955 ss = (ssize_t)copy_length;
12956# endif
12957 if (use_pread) {
12958 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12959 }
12960 else {
12961 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12962 }
12963 if (0 < ss) {
12964 stp->total += ss;
12965 copy_length -= ss;
12966 if (0 < copy_length) {
12967 goto retry_sendfile;
12968 }
12969 }
12970 if (ss < 0) {
12971 if (maygvl_copy_stream_continue_p(0, stp))
12972 goto retry_sendfile;
12973 switch (errno) {
12974 case EINVAL:
12975#ifdef ENOSYS
12976 case ENOSYS:
12977#endif
12978#ifdef EOPNOTSUP
12979 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12980 see also: [Feature #16965] */
12981 case EOPNOTSUP:
12982#endif
12983 return 0;
12984 case EAGAIN:
12985#if EWOULDBLOCK != EAGAIN
12986 case EWOULDBLOCK:
12987#endif
12988 {
12989 int ret;
12990#ifndef __linux__
12991 /*
12992 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12993 * select() reports regular files to always be "ready", so
12994 * there is no need to select() on it.
12995 * Other OSes may have the same limitation for sendfile() which
12996 * allow us to bypass maygvl_copy_stream_wait_read()...
12997 */
12998 ret = maygvl_copy_stream_wait_read(0, stp);
12999 if (ret < 0) return ret;
13000#endif
13001 ret = nogvl_copy_stream_wait_write(stp);
13002 if (ret < 0) return ret;
13003 }
13004 goto retry_sendfile;
13005 }
13006 stp->syserr = "sendfile";
13007 stp->error_no = errno;
13008 return (int)ss;
13009 }
13010 return 1;
13011}
13012#endif
13013
13014static ssize_t
13015maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13016{
13017 if (has_gvl)
13018 return rb_io_read_memory(fptr, buf, count);
13019 else
13020 return read(fptr->fd, buf, count);
13021}
13022
13023static ssize_t
13024maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13025{
13026 ssize_t ss;
13027 retry_read:
13028 if (offset < (rb_off_t)0) {
13029 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13030 }
13031 else {
13032 ss = pread(stp->src_fptr->fd, buf, len, offset);
13033 }
13034 if (ss == 0) {
13035 return 0;
13036 }
13037 if (ss < 0) {
13038 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13039 goto retry_read;
13040 switch (errno) {
13041 case EAGAIN:
13042#if EWOULDBLOCK != EAGAIN
13043 case EWOULDBLOCK:
13044#endif
13045 {
13046 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13047 if (ret < 0) return ret;
13048 }
13049 goto retry_read;
13050#ifdef ENOSYS
13051 case ENOSYS:
13052 stp->notimp = "pread";
13053 return ss;
13054#endif
13055 }
13056 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13057 stp->error_no = errno;
13058 }
13059 return ss;
13060}
13061
13062static int
13063nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13064{
13065 ssize_t ss;
13066 int off = 0;
13067 while (len) {
13068 ss = write(stp->dst_fptr->fd, buf+off, len);
13069 if (ss < 0) {
13070 if (maygvl_copy_stream_continue_p(0, stp))
13071 continue;
13072 if (io_again_p(errno)) {
13073 int ret = nogvl_copy_stream_wait_write(stp);
13074 if (ret < 0) return ret;
13075 continue;
13076 }
13077 stp->syserr = "write";
13078 stp->error_no = errno;
13079 return (int)ss;
13080 }
13081 off += (int)ss;
13082 len -= (int)ss;
13083 stp->total += ss;
13084 }
13085 return 0;
13086}
13087
13088static void
13089nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13090{
13091 char buf[1024*16];
13092 size_t len;
13093 ssize_t ss;
13094 int ret;
13095 rb_off_t copy_length;
13096 rb_off_t src_offset;
13097 int use_eof;
13098 int use_pread;
13099
13100 copy_length = stp->copy_length;
13101 use_eof = copy_length < (rb_off_t)0;
13102 src_offset = stp->src_offset;
13103 use_pread = src_offset >= (rb_off_t)0;
13104
13105 if (use_pread && stp->close_src) {
13106 rb_off_t r;
13107 errno = 0;
13108 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13109 if (r < (rb_off_t)0 && errno) {
13110 stp->syserr = "lseek";
13111 stp->error_no = errno;
13112 return;
13113 }
13114 src_offset = (rb_off_t)-1;
13115 use_pread = 0;
13116 }
13117
13118 while (use_eof || 0 < copy_length) {
13119 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13120 len = (size_t)copy_length;
13121 }
13122 else {
13123 len = sizeof(buf);
13124 }
13125 if (use_pread) {
13126 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13127 if (0 < ss)
13128 src_offset += ss;
13129 }
13130 else {
13131 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13132 }
13133 if (ss <= 0) /* EOF or error */
13134 return;
13135
13136 ret = nogvl_copy_stream_write(stp, buf, ss);
13137 if (ret < 0)
13138 return;
13139
13140 if (!use_eof)
13141 copy_length -= ss;
13142 }
13143}
13144
13145static void *
13146nogvl_copy_stream_func(void *arg)
13147{
13148 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13149#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13150 int ret;
13151#endif
13152
13153#ifdef USE_COPY_FILE_RANGE
13154 ret = nogvl_copy_file_range(stp);
13155 if (ret != 0)
13156 goto finish; /* error or success */
13157#endif
13158
13159#ifdef HAVE_FCOPYFILE
13160 ret = nogvl_fcopyfile(stp);
13161 if (ret != 0)
13162 goto finish; /* error or success */
13163#endif
13164
13165#ifdef USE_SENDFILE
13166 ret = nogvl_copy_stream_sendfile(stp);
13167 if (ret != 0)
13168 goto finish; /* error or success */
13169#endif
13170
13171 nogvl_copy_stream_read_write(stp);
13172
13173#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13174 finish:
13175#endif
13176 return 0;
13177}
13178
13179static VALUE
13180copy_stream_fallback_body(VALUE arg)
13181{
13182 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13183 const int buflen = 16*1024;
13184 VALUE n;
13185 VALUE buf = rb_str_buf_new(buflen);
13186 rb_off_t rest = stp->copy_length;
13187 rb_off_t off = stp->src_offset;
13188 ID read_method = id_readpartial;
13189
13190 if (!stp->src_fptr) {
13191 if (!rb_respond_to(stp->src, read_method)) {
13192 read_method = id_read;
13193 }
13194 }
13195
13196 while (1) {
13197 long numwrote;
13198 long l;
13199 rb_str_make_independent(buf);
13200 if (stp->copy_length < (rb_off_t)0) {
13201 l = buflen;
13202 }
13203 else {
13204 if (rest == 0) {
13205 rb_str_resize(buf, 0);
13206 break;
13207 }
13208 l = buflen < rest ? buflen : (long)rest;
13209 }
13210 if (!stp->src_fptr) {
13211 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13212
13213 if (read_method == id_read && NIL_P(rc))
13214 break;
13215 }
13216 else {
13217 ssize_t ss;
13218 rb_str_resize(buf, buflen);
13219 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13220 rb_str_resize(buf, ss > 0 ? ss : 0);
13221 if (ss < 0)
13222 return Qnil;
13223 if (ss == 0)
13224 rb_eof_error();
13225 if (off >= (rb_off_t)0)
13226 off += ss;
13227 }
13228 n = rb_io_write(stp->dst, buf);
13229 numwrote = NUM2LONG(n);
13230 stp->total += numwrote;
13231 rest -= numwrote;
13232 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13233 break;
13234 }
13235 }
13236
13237 return Qnil;
13238}
13239
13240static VALUE
13241copy_stream_fallback(struct copy_stream_struct *stp)
13242{
13243 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13244 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13245 }
13246 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13247 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13248 rb_eEOFError, (VALUE)0);
13249 return Qnil;
13250}
13251
13252static VALUE
13253copy_stream_body(VALUE arg)
13254{
13255 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13256 VALUE src_io = stp->src, dst_io = stp->dst;
13257 const int common_oflags = 0
13258#ifdef O_NOCTTY
13259 | O_NOCTTY
13260#endif
13261 ;
13262
13263 stp->th = rb_thread_current();
13264
13265 stp->total = 0;
13266
13267 if (src_io == argf ||
13268 !(RB_TYPE_P(src_io, T_FILE) ||
13269 RB_TYPE_P(src_io, T_STRING) ||
13270 rb_respond_to(src_io, rb_intern("to_path")))) {
13271 stp->src_fptr = NULL;
13272 }
13273 else {
13274 int stat_ret;
13275 VALUE tmp_io = rb_io_check_io(src_io);
13276 if (!NIL_P(tmp_io)) {
13277 src_io = tmp_io;
13278 }
13279 else if (!RB_TYPE_P(src_io, T_FILE)) {
13280 VALUE args[2];
13281 FilePathValue(src_io);
13282 args[0] = src_io;
13283 args[1] = INT2NUM(O_RDONLY|common_oflags);
13284 src_io = rb_class_new_instance(2, args, rb_cFile);
13285 stp->src = src_io;
13286 stp->close_src = 1;
13287 }
13288 RB_IO_POINTER(src_io, stp->src_fptr);
13289 rb_io_check_byte_readable(stp->src_fptr);
13290
13291 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13292 if (stat_ret < 0) {
13293 stp->syserr = "fstat";
13294 stp->error_no = errno;
13295 return Qnil;
13296 }
13297 }
13298
13299 if (dst_io == argf ||
13300 !(RB_TYPE_P(dst_io, T_FILE) ||
13301 RB_TYPE_P(dst_io, T_STRING) ||
13302 rb_respond_to(dst_io, rb_intern("to_path")))) {
13303 stp->dst_fptr = NULL;
13304 }
13305 else {
13306 int stat_ret;
13307 VALUE tmp_io = rb_io_check_io(dst_io);
13308 if (!NIL_P(tmp_io)) {
13309 dst_io = GetWriteIO(tmp_io);
13310 }
13311 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13312 VALUE args[3];
13313 FilePathValue(dst_io);
13314 args[0] = dst_io;
13315 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13316 args[2] = INT2FIX(0666);
13317 dst_io = rb_class_new_instance(3, args, rb_cFile);
13318 stp->dst = dst_io;
13319 stp->close_dst = 1;
13320 }
13321 else {
13322 dst_io = GetWriteIO(dst_io);
13323 stp->dst = dst_io;
13324 }
13325 RB_IO_POINTER(dst_io, stp->dst_fptr);
13326 rb_io_check_writable(stp->dst_fptr);
13327
13328 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13329 if (stat_ret < 0) {
13330 stp->syserr = "fstat";
13331 stp->error_no = errno;
13332 return Qnil;
13333 }
13334 }
13335
13336#ifdef O_BINARY
13337 if (stp->src_fptr)
13338 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13339#endif
13340 if (stp->dst_fptr)
13341 io_ascii8bit_binmode(stp->dst_fptr);
13342
13343 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13344 size_t len = stp->src_fptr->rbuf.len;
13345 VALUE str;
13346 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13347 len = (size_t)stp->copy_length;
13348 }
13349 str = rb_str_buf_new(len);
13350 rb_str_resize(str,len);
13351 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13352 if (stp->dst_fptr) { /* IO or filename */
13353 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13354 rb_sys_fail_on_write(stp->dst_fptr);
13355 }
13356 else /* others such as StringIO */
13357 rb_io_write(dst_io, str);
13358 rb_str_resize(str, 0);
13359 stp->total += len;
13360 if (stp->copy_length >= (rb_off_t)0)
13361 stp->copy_length -= len;
13362 }
13363
13364 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13365 rb_raise(rb_eIOError, "flush failed");
13366 }
13367
13368 if (stp->copy_length == 0)
13369 return Qnil;
13370
13371 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13372 return copy_stream_fallback(stp);
13373 }
13374
13375 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13376 return Qnil;
13377}
13378
13379static VALUE
13380copy_stream_finalize(VALUE arg)
13381{
13382 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13383
13384#ifdef HAVE_FCOPYFILE
13385 if (stp->copyfile_state) {
13386 copyfile_state_free(stp->copyfile_state);
13387 }
13388#endif
13389
13390 if (stp->close_src) {
13391 rb_io_close_m(stp->src);
13392 }
13393 if (stp->close_dst) {
13394 rb_io_close_m(stp->dst);
13395 }
13396 if (stp->syserr) {
13397 rb_syserr_fail(stp->error_no, stp->syserr);
13398 }
13399 if (stp->notimp) {
13400 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13401 }
13402 return Qnil;
13403}
13404
13405/*
13406 * call-seq:
13407 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13408 *
13409 * Copies from the given +src+ to the given +dst+,
13410 * returning the number of bytes copied.
13411 *
13412 * - The given +src+ must be one of the following:
13413 *
13414 * - The path to a readable file, from which source data is to be read.
13415 * - An \IO-like object, opened for reading and capable of responding
13416 * to method +:readpartial+ or method +:read+.
13417 *
13418 * - The given +dst+ must be one of the following:
13419 *
13420 * - The path to a writable file, to which data is to be written.
13421 * - An \IO-like object, opened for writing and capable of responding
13422 * to method +:write+.
13423 *
13424 * The examples here use file <tt>t.txt</tt> as source:
13425 *
13426 * File.read('t.txt')
13427 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13428 * File.read('t.txt').size # => 47
13429 *
13430 * If only arguments +src+ and +dst+ are given,
13431 * the entire source stream is copied:
13432 *
13433 * # Paths.
13434 * IO.copy_stream('t.txt', 't.tmp') # => 47
13435 *
13436 * # IOs (recall that a File is also an IO).
13437 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13438 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13439 * IO.copy_stream(src_io, dst_io) # => 47
13440 * src_io.close
13441 * dst_io.close
13442 *
13443 * With argument +src_length+ a non-negative integer,
13444 * no more than that many bytes are copied:
13445 *
13446 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13447 * File.read('t.tmp') # => "First line"
13448 *
13449 * With argument +src_offset+ also given,
13450 * the source stream is read beginning at that offset:
13451 *
13452 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13453 * IO.read('t.tmp') # => "Second line"
13454 *
13455 */
13456static VALUE
13457rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13458{
13459 VALUE src, dst, length, src_offset;
13460 struct copy_stream_struct st;
13461
13462 MEMZERO(&st, struct copy_stream_struct, 1);
13463
13464 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13465
13466 st.src = src;
13467 st.dst = dst;
13468
13469 st.src_fptr = NULL;
13470 st.dst_fptr = NULL;
13471
13472 if (NIL_P(length))
13473 st.copy_length = (rb_off_t)-1;
13474 else
13475 st.copy_length = NUM2OFFT(length);
13476
13477 if (NIL_P(src_offset))
13478 st.src_offset = (rb_off_t)-1;
13479 else
13480 st.src_offset = NUM2OFFT(src_offset);
13481
13482 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13483
13484 return OFFT2NUM(st.total);
13485}
13486
13487/*
13488 * call-seq:
13489 * external_encoding -> encoding or nil
13490 *
13491 * Returns the Encoding object that represents the encoding of the stream,
13492 * or +nil+ if the stream is in write mode and no encoding is specified.
13493 *
13494 * See {Encodings}[rdoc-ref:File@Encodings].
13495 *
13496 */
13497
13498static VALUE
13499rb_io_external_encoding(VALUE io)
13500{
13501 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13502
13503 if (fptr->encs.enc2) {
13504 return rb_enc_from_encoding(fptr->encs.enc2);
13505 }
13506 if (fptr->mode & FMODE_WRITABLE) {
13507 if (fptr->encs.enc)
13508 return rb_enc_from_encoding(fptr->encs.enc);
13509 return Qnil;
13510 }
13511 return rb_enc_from_encoding(io_read_encoding(fptr));
13512}
13513
13514/*
13515 * call-seq:
13516 * internal_encoding -> encoding or nil
13517 *
13518 * Returns the Encoding object that represents the encoding of the internal string,
13519 * if conversion is specified,
13520 * or +nil+ otherwise.
13521 *
13522 * See {Encodings}[rdoc-ref:File@Encodings].
13523 *
13524 */
13525
13526static VALUE
13527rb_io_internal_encoding(VALUE io)
13528{
13529 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13530
13531 if (!fptr->encs.enc2) return Qnil;
13532 return rb_enc_from_encoding(io_read_encoding(fptr));
13533}
13534
13535/*
13536 * call-seq:
13537 * set_encoding(ext_enc) -> self
13538 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13539 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13540 *
13541 * See {Encodings}[rdoc-ref:File@Encodings].
13542 *
13543 * Argument +ext_enc+, if given, must be an Encoding object
13544 * or a String with the encoding name;
13545 * it is assigned as the encoding for the stream.
13546 *
13547 * Argument +int_enc+, if given, must be an Encoding object
13548 * or a String with the encoding name;
13549 * it is assigned as the encoding for the internal string.
13550 *
13551 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13552 * containing two colon-separated encoding names;
13553 * corresponding Encoding objects are assigned as the external
13554 * and internal encodings for the stream.
13555 *
13556 * If the external encoding of a string is binary/ASCII-8BIT,
13557 * the internal encoding of the string is set to nil, since no
13558 * transcoding is needed.
13559 *
13560 * Optional keyword arguments +enc_opts+ specify
13561 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13562 *
13563 */
13564
13565static VALUE
13566rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13567{
13568 rb_io_t *fptr;
13569 VALUE v1, v2, opt;
13570
13571 if (!RB_TYPE_P(io, T_FILE)) {
13572 return forward(io, id_set_encoding, argc, argv);
13573 }
13574
13575 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13576 GetOpenFile(io, fptr);
13577 io_encoding_set(fptr, v1, v2, opt);
13578 return io;
13579}
13580
13581void
13582rb_stdio_set_default_encoding(void)
13583{
13584 VALUE val = Qnil;
13585
13586#ifdef _WIN32
13587 if (isatty(fileno(stdin))) {
13588 rb_encoding *external = rb_locale_encoding();
13589 rb_encoding *internal = rb_default_internal_encoding();
13590 if (!internal) internal = rb_default_external_encoding();
13591 io_encoding_set(RFILE(rb_stdin)->fptr,
13592 rb_enc_from_encoding(external),
13593 rb_enc_from_encoding(internal),
13594 Qnil);
13595 }
13596 else
13597#endif
13598 rb_io_set_encoding(1, &val, rb_stdin);
13599 rb_io_set_encoding(1, &val, rb_stdout);
13600 rb_io_set_encoding(1, &val, rb_stderr);
13601}
13602
13603static inline int
13604global_argf_p(VALUE arg)
13605{
13606 return arg == argf;
13607}
13608
13609typedef VALUE (*argf_encoding_func)(VALUE io);
13610
13611static VALUE
13612argf_encoding(VALUE argf, argf_encoding_func func)
13613{
13614 if (!RTEST(ARGF.current_file)) {
13615 return rb_enc_default_external();
13616 }
13617 return func(rb_io_check_io(ARGF.current_file));
13618}
13619
13620/*
13621 * call-seq:
13622 * ARGF.external_encoding -> encoding
13623 *
13624 * Returns the external encoding for files read from ARGF as an Encoding
13625 * object. The external encoding is the encoding of the text as stored in a
13626 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13627 * represent this text within Ruby.
13628 *
13629 * To set the external encoding use ARGF.set_encoding.
13630 *
13631 * For example:
13632 *
13633 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13634 *
13635 */
13636static VALUE
13637argf_external_encoding(VALUE argf)
13638{
13639 return argf_encoding(argf, rb_io_external_encoding);
13640}
13641
13642/*
13643 * call-seq:
13644 * ARGF.internal_encoding -> encoding
13645 *
13646 * Returns the internal encoding for strings read from ARGF as an
13647 * Encoding object.
13648 *
13649 * If ARGF.set_encoding has been called with two encoding names, the second
13650 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13651 * value is returned. Failing that, if a default external encoding was
13652 * specified on the command-line, that value is used. If the encoding is
13653 * unknown, +nil+ is returned.
13654 */
13655static VALUE
13656argf_internal_encoding(VALUE argf)
13657{
13658 return argf_encoding(argf, rb_io_internal_encoding);
13659}
13660
13661/*
13662 * call-seq:
13663 * ARGF.set_encoding(ext_enc) -> ARGF
13664 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13665 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13666 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13667 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13668 *
13669 * If single argument is specified, strings read from ARGF are tagged with
13670 * the encoding specified.
13671 *
13672 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13673 * the read string is converted from the first encoding (external encoding)
13674 * to the second encoding (internal encoding), then tagged with the second
13675 * encoding.
13676 *
13677 * If two arguments are specified, they must be encoding objects or encoding
13678 * names. Again, the first specifies the external encoding; the second
13679 * specifies the internal encoding.
13680 *
13681 * If the external encoding and the internal encoding are specified, the
13682 * optional Hash argument can be used to adjust the conversion process. The
13683 * structure of this hash is explained in the String#encode documentation.
13684 *
13685 * For example:
13686 *
13687 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13688 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13689 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13690 * # to UTF-8.
13691 */
13692static VALUE
13693argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13694{
13695 rb_io_t *fptr;
13696
13697 if (!next_argv()) {
13698 rb_raise(rb_eArgError, "no stream to set encoding");
13699 }
13700 rb_io_set_encoding(argc, argv, ARGF.current_file);
13701 GetOpenFile(ARGF.current_file, fptr);
13702 ARGF.encs = fptr->encs;
13703 return argf;
13704}
13705
13706/*
13707 * call-seq:
13708 * ARGF.tell -> Integer
13709 * ARGF.pos -> Integer
13710 *
13711 * Returns the current offset (in bytes) of the current file in ARGF.
13712 *
13713 * ARGF.pos #=> 0
13714 * ARGF.gets #=> "This is line one\n"
13715 * ARGF.pos #=> 17
13716 *
13717 */
13718static VALUE
13719argf_tell(VALUE argf)
13720{
13721 if (!next_argv()) {
13722 rb_raise(rb_eArgError, "no stream to tell");
13723 }
13724 ARGF_FORWARD(0, 0);
13725 return rb_io_tell(ARGF.current_file);
13726}
13727
13728/*
13729 * call-seq:
13730 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13731 *
13732 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13733 * the value of _whence_. See IO#seek for further details.
13734 */
13735static VALUE
13736argf_seek_m(int argc, VALUE *argv, VALUE argf)
13737{
13738 if (!next_argv()) {
13739 rb_raise(rb_eArgError, "no stream to seek");
13740 }
13741 ARGF_FORWARD(argc, argv);
13742 return rb_io_seek_m(argc, argv, ARGF.current_file);
13743}
13744
13745/*
13746 * call-seq:
13747 * ARGF.pos = position -> Integer
13748 *
13749 * Seeks to the position given by _position_ (in bytes) in ARGF.
13750 *
13751 * For example:
13752 *
13753 * ARGF.pos = 17
13754 * ARGF.gets #=> "This is line two\n"
13755 */
13756static VALUE
13757argf_set_pos(VALUE argf, VALUE offset)
13758{
13759 if (!next_argv()) {
13760 rb_raise(rb_eArgError, "no stream to set position");
13761 }
13762 ARGF_FORWARD(1, &offset);
13763 return rb_io_set_pos(ARGF.current_file, offset);
13764}
13765
13766/*
13767 * call-seq:
13768 * ARGF.rewind -> 0
13769 *
13770 * Positions the current file to the beginning of input, resetting
13771 * ARGF.lineno to zero.
13772 *
13773 * ARGF.readline #=> "This is line one\n"
13774 * ARGF.rewind #=> 0
13775 * ARGF.lineno #=> 0
13776 * ARGF.readline #=> "This is line one\n"
13777 */
13778static VALUE
13779argf_rewind(VALUE argf)
13780{
13781 VALUE ret;
13782 int old_lineno;
13783
13784 if (!next_argv()) {
13785 rb_raise(rb_eArgError, "no stream to rewind");
13786 }
13787 ARGF_FORWARD(0, 0);
13788 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13789 ret = rb_io_rewind(ARGF.current_file);
13790 if (!global_argf_p(argf)) {
13791 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13792 }
13793 return ret;
13794}
13795
13796/*
13797 * call-seq:
13798 * ARGF.fileno -> integer
13799 * ARGF.to_i -> integer
13800 *
13801 * Returns an integer representing the numeric file descriptor for
13802 * the current file. Raises an ArgumentError if there isn't a current file.
13803 *
13804 * ARGF.fileno #=> 3
13805 */
13806static VALUE
13807argf_fileno(VALUE argf)
13808{
13809 if (!next_argv()) {
13810 rb_raise(rb_eArgError, "no stream");
13811 }
13812 ARGF_FORWARD(0, 0);
13813 return rb_io_fileno(ARGF.current_file);
13814}
13815
13816/*
13817 * call-seq:
13818 * ARGF.to_io -> IO
13819 *
13820 * Returns an IO object representing the current file. This will be a
13821 * File object unless the current file is a stream such as STDIN.
13822 *
13823 * For example:
13824 *
13825 * ARGF.to_io #=> #<File:glark.txt>
13826 * ARGF.to_io #=> #<IO:<STDIN>>
13827 */
13828static VALUE
13829argf_to_io(VALUE argf)
13830{
13831 next_argv();
13832 ARGF_FORWARD(0, 0);
13833 return ARGF.current_file;
13834}
13835
13836/*
13837 * call-seq:
13838 * ARGF.eof? -> true or false
13839 * ARGF.eof -> true or false
13840 *
13841 * Returns true if the current file in ARGF is at end of file, i.e. it has
13842 * no data to read. The stream must be opened for reading or an IOError
13843 * will be raised.
13844 *
13845 * $ echo "eof" | ruby argf.rb
13846 *
13847 * ARGF.eof? #=> false
13848 * 3.times { ARGF.readchar }
13849 * ARGF.eof? #=> false
13850 * ARGF.readchar #=> "\n"
13851 * ARGF.eof? #=> true
13852 */
13853
13854static VALUE
13855argf_eof(VALUE argf)
13856{
13857 next_argv();
13858 if (RTEST(ARGF.current_file)) {
13859 if (ARGF.init_p == 0) return Qtrue;
13860 next_argv();
13861 ARGF_FORWARD(0, 0);
13862 if (rb_io_eof(ARGF.current_file)) {
13863 return Qtrue;
13864 }
13865 }
13866 return Qfalse;
13867}
13868
13869/*
13870 * call-seq:
13871 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13872 *
13873 * Reads _length_ bytes from ARGF. The files named on the command line
13874 * are concatenated and treated as a single file by this method, so when
13875 * called without arguments the contents of this pseudo file are returned in
13876 * their entirety.
13877 *
13878 * _length_ must be a non-negative integer or +nil+.
13879 *
13880 * If _length_ is a positive integer, +read+ tries to read
13881 * _length_ bytes without any conversion (binary mode).
13882 * It returns +nil+ if an EOF is encountered before anything can be read.
13883 * Fewer than _length_ bytes are returned if an EOF is encountered during
13884 * the read.
13885 * In the case of an integer _length_, the resulting string is always
13886 * in ASCII-8BIT encoding.
13887 *
13888 * If _length_ is omitted or is +nil+, it reads until EOF
13889 * and the encoding conversion is applied, if applicable.
13890 * A string is returned even if EOF is encountered before any data is read.
13891 *
13892 * If _length_ is zero, it returns an empty string (<code>""</code>).
13893 *
13894 * If the optional _outbuf_ argument is present,
13895 * it must reference a String, which will receive the data.
13896 * The _outbuf_ will contain only the received data after the method call
13897 * even if it is not empty at the beginning.
13898 *
13899 * For example:
13900 *
13901 * $ echo "small" > small.txt
13902 * $ echo "large" > large.txt
13903 * $ ./glark.rb small.txt large.txt
13904 *
13905 * ARGF.read #=> "small\nlarge"
13906 * ARGF.read(200) #=> "small\nlarge"
13907 * ARGF.read(2) #=> "sm"
13908 * ARGF.read(0) #=> ""
13909 *
13910 * Note that this method behaves like the fread() function in C.
13911 * This means it retries to invoke read(2) system calls to read data
13912 * with the specified length.
13913 * If you need the behavior like a single read(2) system call,
13914 * consider ARGF#readpartial or ARGF#read_nonblock.
13915 */
13916
13917static VALUE
13918argf_read(int argc, VALUE *argv, VALUE argf)
13919{
13920 VALUE tmp, str, length;
13921 long len = 0;
13922
13923 rb_scan_args(argc, argv, "02", &length, &str);
13924 if (!NIL_P(length)) {
13925 len = NUM2LONG(argv[0]);
13926 }
13927 if (!NIL_P(str)) {
13928 StringValue(str);
13929 rb_str_resize(str,0);
13930 argv[1] = Qnil;
13931 }
13932
13933 retry:
13934 if (!next_argv()) {
13935 return str;
13936 }
13937 if (ARGF_GENERIC_INPUT_P()) {
13938 tmp = argf_forward(argc, argv, argf);
13939 }
13940 else {
13941 tmp = io_read(argc, argv, ARGF.current_file);
13942 }
13943 if (NIL_P(str)) str = tmp;
13944 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13945 if (NIL_P(tmp) || NIL_P(length)) {
13946 if (ARGF.next_p != -1) {
13947 argf_close(argf);
13948 ARGF.next_p = 1;
13949 goto retry;
13950 }
13951 }
13952 else if (argc >= 1) {
13953 long slen = RSTRING_LEN(str);
13954 if (slen < len) {
13955 argv[0] = LONG2NUM(len - slen);
13956 goto retry;
13957 }
13958 }
13959 return str;
13960}
13961
13963 int argc;
13964 VALUE *argv;
13965 VALUE argf;
13966};
13967
13968static VALUE
13969argf_forward_call(VALUE arg)
13970{
13971 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13972 argf_forward(p->argc, p->argv, p->argf);
13973 return Qnil;
13974}
13975
13976static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13977 int nonblock);
13978
13979/*
13980 * call-seq:
13981 * ARGF.readpartial(maxlen) -> string
13982 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13983 *
13984 * Reads at most _maxlen_ bytes from the ARGF stream.
13985 *
13986 * If the optional _outbuf_ argument is present,
13987 * it must reference a String, which will receive the data.
13988 * The _outbuf_ will contain only the received data after the method call
13989 * even if it is not empty at the beginning.
13990 *
13991 * It raises EOFError on end of ARGF stream.
13992 * Since ARGF stream is a concatenation of multiple files,
13993 * internally EOF is occur for each file.
13994 * ARGF.readpartial returns empty strings for EOFs except the last one and
13995 * raises EOFError for the last one.
13996 *
13997 */
13998
13999static VALUE
14000argf_readpartial(int argc, VALUE *argv, VALUE argf)
14001{
14002 return argf_getpartial(argc, argv, argf, Qnil, 0);
14003}
14004
14005/*
14006 * call-seq:
14007 * ARGF.read_nonblock(maxlen[, options]) -> string
14008 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14009 *
14010 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14011 */
14012
14013static VALUE
14014argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14015{
14016 VALUE opts;
14017
14018 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14019
14020 if (!NIL_P(opts))
14021 argc--;
14022
14023 return argf_getpartial(argc, argv, argf, opts, 1);
14024}
14025
14026static VALUE
14027argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14028{
14029 VALUE tmp, str, length;
14030 int no_exception;
14031
14032 rb_scan_args(argc, argv, "11", &length, &str);
14033 if (!NIL_P(str)) {
14034 StringValue(str);
14035 argv[1] = str;
14036 }
14037 no_exception = no_exception_p(opts);
14038
14039 if (!next_argv()) {
14040 if (!NIL_P(str)) {
14041 rb_str_resize(str, 0);
14042 }
14043 rb_eof_error();
14044 }
14045 if (ARGF_GENERIC_INPUT_P()) {
14046 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14047 struct argf_call_arg arg;
14048 arg.argc = argc;
14049 arg.argv = argv;
14050 arg.argf = argf;
14051 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14052 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14053 }
14054 else {
14055 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14056 }
14057 if (NIL_P(tmp)) {
14058 if (ARGF.next_p == -1) {
14059 return io_nonblock_eof(no_exception);
14060 }
14061 argf_close(argf);
14062 ARGF.next_p = 1;
14063 if (RARRAY_LEN(ARGF.argv) == 0) {
14064 return io_nonblock_eof(no_exception);
14065 }
14066 if (NIL_P(str))
14067 str = rb_str_new(NULL, 0);
14068 return str;
14069 }
14070 return tmp;
14071}
14072
14073/*
14074 * call-seq:
14075 * ARGF.getc -> String or nil
14076 *
14077 * Reads the next character from ARGF and returns it as a String. Returns
14078 * +nil+ at the end of the stream.
14079 *
14080 * ARGF treats the files named on the command line as a single file created
14081 * by concatenating their contents. After returning the last character of the
14082 * first file, it returns the first character of the second file, and so on.
14083 *
14084 * For example:
14085 *
14086 * $ echo "foo" > file
14087 * $ ruby argf.rb file
14088 *
14089 * ARGF.getc #=> "f"
14090 * ARGF.getc #=> "o"
14091 * ARGF.getc #=> "o"
14092 * ARGF.getc #=> "\n"
14093 * ARGF.getc #=> nil
14094 * ARGF.getc #=> nil
14095 */
14096static VALUE
14097argf_getc(VALUE argf)
14098{
14099 VALUE ch;
14100
14101 retry:
14102 if (!next_argv()) return Qnil;
14103 if (ARGF_GENERIC_INPUT_P()) {
14104 ch = forward_current(rb_intern("getc"), 0, 0);
14105 }
14106 else {
14107 ch = rb_io_getc(ARGF.current_file);
14108 }
14109 if (NIL_P(ch) && ARGF.next_p != -1) {
14110 argf_close(argf);
14111 ARGF.next_p = 1;
14112 goto retry;
14113 }
14114
14115 return ch;
14116}
14117
14118/*
14119 * call-seq:
14120 * ARGF.getbyte -> Integer or nil
14121 *
14122 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14123 * the end of the stream.
14124 *
14125 * For example:
14126 *
14127 * $ echo "foo" > file
14128 * $ ruby argf.rb file
14129 *
14130 * ARGF.getbyte #=> 102
14131 * ARGF.getbyte #=> 111
14132 * ARGF.getbyte #=> 111
14133 * ARGF.getbyte #=> 10
14134 * ARGF.getbyte #=> nil
14135 */
14136static VALUE
14137argf_getbyte(VALUE argf)
14138{
14139 VALUE ch;
14140
14141 retry:
14142 if (!next_argv()) return Qnil;
14143 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14144 ch = forward_current(rb_intern("getbyte"), 0, 0);
14145 }
14146 else {
14147 ch = rb_io_getbyte(ARGF.current_file);
14148 }
14149 if (NIL_P(ch) && ARGF.next_p != -1) {
14150 argf_close(argf);
14151 ARGF.next_p = 1;
14152 goto retry;
14153 }
14154
14155 return ch;
14156}
14157
14158/*
14159 * call-seq:
14160 * ARGF.readchar -> String or nil
14161 *
14162 * Reads the next character from ARGF and returns it as a String. Raises
14163 * an EOFError after the last character of the last file has been read.
14164 *
14165 * For example:
14166 *
14167 * $ echo "foo" > file
14168 * $ ruby argf.rb file
14169 *
14170 * ARGF.readchar #=> "f"
14171 * ARGF.readchar #=> "o"
14172 * ARGF.readchar #=> "o"
14173 * ARGF.readchar #=> "\n"
14174 * ARGF.readchar #=> end of file reached (EOFError)
14175 */
14176static VALUE
14177argf_readchar(VALUE argf)
14178{
14179 VALUE ch;
14180
14181 retry:
14182 if (!next_argv()) rb_eof_error();
14183 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14184 ch = forward_current(rb_intern("getc"), 0, 0);
14185 }
14186 else {
14187 ch = rb_io_getc(ARGF.current_file);
14188 }
14189 if (NIL_P(ch) && ARGF.next_p != -1) {
14190 argf_close(argf);
14191 ARGF.next_p = 1;
14192 goto retry;
14193 }
14194
14195 return ch;
14196}
14197
14198/*
14199 * call-seq:
14200 * ARGF.readbyte -> Integer
14201 *
14202 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14203 * an EOFError after the last byte of the last file has been read.
14204 *
14205 * For example:
14206 *
14207 * $ echo "foo" > file
14208 * $ ruby argf.rb file
14209 *
14210 * ARGF.readbyte #=> 102
14211 * ARGF.readbyte #=> 111
14212 * ARGF.readbyte #=> 111
14213 * ARGF.readbyte #=> 10
14214 * ARGF.readbyte #=> end of file reached (EOFError)
14215 */
14216static VALUE
14217argf_readbyte(VALUE argf)
14218{
14219 VALUE c;
14220
14221 NEXT_ARGF_FORWARD(0, 0);
14222 c = argf_getbyte(argf);
14223 if (NIL_P(c)) {
14224 rb_eof_error();
14225 }
14226 return c;
14227}
14228
14229#define FOREACH_ARGF() while (next_argv())
14230
14231static VALUE
14232argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14233{
14234 const VALUE current = ARGF.current_file;
14235 rb_yield_values2(argc, argv);
14236 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14238 }
14239 return Qnil;
14240}
14241
14242#define ARGF_block_call(mid, argc, argv, func, argf) \
14243 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14244 func, argf, rb_keyword_given_p())
14245
14246static void
14247argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14248{
14249 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14250 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14251}
14252
14253static VALUE
14254argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14255{
14256 if (!global_argf_p(argf)) {
14257 ARGF.last_lineno = ++ARGF.lineno;
14258 }
14259 return argf_block_call_i(i, argf, argc, argv, blockarg);
14260}
14261
14262static void
14263argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14264{
14265 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14266 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14267}
14268
14269/*
14270 * call-seq:
14271 * ARGF.each(sep=$/) {|line| block } -> ARGF
14272 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14273 * ARGF.each(...) -> an_enumerator
14274 *
14275 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14276 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14277 * ARGF.each_line(...) -> an_enumerator
14278 *
14279 * Returns an enumerator which iterates over each line (separated by _sep_,
14280 * which defaults to your platform's newline character) of each file in
14281 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14282 * block, otherwise an enumerator is returned.
14283 * The optional _limit_ argument is an Integer specifying the maximum
14284 * length of each line; longer lines will be split according to this limit.
14285 *
14286 * This method allows you to treat the files supplied on the command line as
14287 * a single file consisting of the concatenation of each named file. After
14288 * the last line of the first file has been returned, the first line of the
14289 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14290 * used to determine the filename of the current line and line number of the
14291 * whole input, respectively.
14292 *
14293 * For example, the following code prints out each line of each named file
14294 * prefixed with its line number, displaying the filename once per file:
14295 *
14296 * ARGF.each_line do |line|
14297 * puts ARGF.filename if ARGF.file.lineno == 1
14298 * puts "#{ARGF.file.lineno}: #{line}"
14299 * end
14300 *
14301 * While the following code prints only the first file's name at first, and
14302 * the contents with line number counted through all named files.
14303 *
14304 * ARGF.each_line do |line|
14305 * puts ARGF.filename if ARGF.lineno == 1
14306 * puts "#{ARGF.lineno}: #{line}"
14307 * end
14308 */
14309static VALUE
14310argf_each_line(int argc, VALUE *argv, VALUE argf)
14311{
14312 RETURN_ENUMERATOR(argf, argc, argv);
14313 FOREACH_ARGF() {
14314 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14315 }
14316 return argf;
14317}
14318
14319/*
14320 * call-seq:
14321 * ARGF.each_byte {|byte| block } -> ARGF
14322 * ARGF.each_byte -> an_enumerator
14323 *
14324 * Iterates over each byte of each file in +ARGV+.
14325 * A byte is returned as an Integer in the range 0..255.
14326 *
14327 * This method allows you to treat the files supplied on the command line as
14328 * a single file consisting of the concatenation of each named file. After
14329 * the last byte of the first file has been returned, the first byte of the
14330 * second file is returned. The ARGF.filename method can be used to
14331 * determine the filename of the current byte.
14332 *
14333 * If no block is given, an enumerator is returned instead.
14334 *
14335 * For example:
14336 *
14337 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14338 *
14339 */
14340static VALUE
14341argf_each_byte(VALUE argf)
14342{
14343 RETURN_ENUMERATOR(argf, 0, 0);
14344 FOREACH_ARGF() {
14345 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14346 }
14347 return argf;
14348}
14349
14350/*
14351 * call-seq:
14352 * ARGF.each_char {|char| block } -> ARGF
14353 * ARGF.each_char -> an_enumerator
14354 *
14355 * Iterates over each character of each file in ARGF.
14356 *
14357 * This method allows you to treat the files supplied on the command line as
14358 * a single file consisting of the concatenation of each named file. After
14359 * the last character of the first file has been returned, the first
14360 * character of the second file is returned. The ARGF.filename method can
14361 * be used to determine the name of the file in which the current character
14362 * appears.
14363 *
14364 * If no block is given, an enumerator is returned instead.
14365 */
14366static VALUE
14367argf_each_char(VALUE argf)
14368{
14369 RETURN_ENUMERATOR(argf, 0, 0);
14370 FOREACH_ARGF() {
14371 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14372 }
14373 return argf;
14374}
14375
14376/*
14377 * call-seq:
14378 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14379 * ARGF.each_codepoint -> an_enumerator
14380 *
14381 * Iterates over each codepoint of each file in ARGF.
14382 *
14383 * This method allows you to treat the files supplied on the command line as
14384 * a single file consisting of the concatenation of each named file. After
14385 * the last codepoint of the first file has been returned, the first
14386 * codepoint of the second file is returned. The ARGF.filename method can
14387 * be used to determine the name of the file in which the current codepoint
14388 * appears.
14389 *
14390 * If no block is given, an enumerator is returned instead.
14391 */
14392static VALUE
14393argf_each_codepoint(VALUE argf)
14394{
14395 RETURN_ENUMERATOR(argf, 0, 0);
14396 FOREACH_ARGF() {
14397 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14398 }
14399 return argf;
14400}
14401
14402/*
14403 * call-seq:
14404 * ARGF.filename -> String
14405 * ARGF.path -> String
14406 *
14407 * Returns the current filename. "-" is returned when the current file is
14408 * STDIN.
14409 *
14410 * For example:
14411 *
14412 * $ echo "foo" > foo
14413 * $ echo "bar" > bar
14414 * $ echo "glark" > glark
14415 *
14416 * $ ruby argf.rb foo bar glark
14417 *
14418 * ARGF.filename #=> "foo"
14419 * ARGF.read(5) #=> "foo\nb"
14420 * ARGF.filename #=> "bar"
14421 * ARGF.skip
14422 * ARGF.filename #=> "glark"
14423 */
14424static VALUE
14425argf_filename(VALUE argf)
14426{
14427 next_argv();
14428 return ARGF.filename;
14429}
14430
14431static VALUE
14432argf_filename_getter(ID id, VALUE *var)
14433{
14434 return argf_filename(*var);
14435}
14436
14437/*
14438 * call-seq:
14439 * ARGF.file -> IO or File object
14440 *
14441 * Returns the current file as an IO or File object.
14442 * <code>$stdin</code> is returned when the current file is STDIN.
14443 *
14444 * For example:
14445 *
14446 * $ echo "foo" > foo
14447 * $ echo "bar" > bar
14448 *
14449 * $ ruby argf.rb foo bar
14450 *
14451 * ARGF.file #=> #<File:foo>
14452 * ARGF.read(5) #=> "foo\nb"
14453 * ARGF.file #=> #<File:bar>
14454 */
14455static VALUE
14456argf_file(VALUE argf)
14457{
14458 next_argv();
14459 return ARGF.current_file;
14460}
14461
14462/*
14463 * call-seq:
14464 * ARGF.binmode -> ARGF
14465 *
14466 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14467 * be reset to non-binary mode. This option has the following effects:
14468 *
14469 * * Newline conversion is disabled.
14470 * * Encoding conversion is disabled.
14471 * * Content is treated as ASCII-8BIT.
14472 */
14473static VALUE
14474argf_binmode_m(VALUE argf)
14475{
14476 ARGF.binmode = 1;
14477 next_argv();
14478 ARGF_FORWARD(0, 0);
14479 rb_io_ascii8bit_binmode(ARGF.current_file);
14480 return argf;
14481}
14482
14483/*
14484 * call-seq:
14485 * ARGF.binmode? -> true or false
14486 *
14487 * Returns true if ARGF is being read in binary mode; false otherwise.
14488 * To enable binary mode use ARGF.binmode.
14489 *
14490 * For example:
14491 *
14492 * ARGF.binmode? #=> false
14493 * ARGF.binmode
14494 * ARGF.binmode? #=> true
14495 */
14496static VALUE
14497argf_binmode_p(VALUE argf)
14498{
14499 return RBOOL(ARGF.binmode);
14500}
14501
14502/*
14503 * call-seq:
14504 * ARGF.skip -> ARGF
14505 *
14506 * Sets the current file to the next file in ARGV. If there aren't any more
14507 * files it has no effect.
14508 *
14509 * For example:
14510 *
14511 * $ ruby argf.rb foo bar
14512 * ARGF.filename #=> "foo"
14513 * ARGF.skip
14514 * ARGF.filename #=> "bar"
14515 */
14516static VALUE
14517argf_skip(VALUE argf)
14518{
14519 if (ARGF.init_p && ARGF.next_p == 0) {
14520 argf_close(argf);
14521 ARGF.next_p = 1;
14522 }
14523 return argf;
14524}
14525
14526/*
14527 * call-seq:
14528 * ARGF.close -> ARGF
14529 *
14530 * Closes the current file and skips to the next file in ARGV. If there are
14531 * no more files to open, just closes the current file. STDIN will not be
14532 * closed.
14533 *
14534 * For example:
14535 *
14536 * $ ruby argf.rb foo bar
14537 *
14538 * ARGF.filename #=> "foo"
14539 * ARGF.close
14540 * ARGF.filename #=> "bar"
14541 * ARGF.close
14542 */
14543static VALUE
14544argf_close_m(VALUE argf)
14545{
14546 next_argv();
14547 argf_close(argf);
14548 if (ARGF.next_p != -1) {
14549 ARGF.next_p = 1;
14550 }
14551 ARGF.lineno = 0;
14552 return argf;
14553}
14554
14555/*
14556 * call-seq:
14557 * ARGF.closed? -> true or false
14558 *
14559 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14560 * ARGF.close to actually close the current file.
14561 */
14562static VALUE
14563argf_closed(VALUE argf)
14564{
14565 next_argv();
14566 ARGF_FORWARD(0, 0);
14567 return rb_io_closed_p(ARGF.current_file);
14568}
14569
14570/*
14571 * call-seq:
14572 * ARGF.to_s -> String
14573 *
14574 * Returns "ARGF".
14575 */
14576static VALUE
14577argf_to_s(VALUE argf)
14578{
14579 return rb_str_new2("ARGF");
14580}
14581
14582/*
14583 * call-seq:
14584 * ARGF.inplace_mode -> String
14585 *
14586 * Returns the file extension appended to the names of backup copies of
14587 * modified files under in-place edit mode. This value can be set using
14588 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14589 */
14590static VALUE
14591argf_inplace_mode_get(VALUE argf)
14592{
14593 if (!ARGF.inplace) return Qnil;
14594 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14595 return rb_str_dup(ARGF.inplace);
14596}
14597
14598static VALUE
14599opt_i_get(ID id, VALUE *var)
14600{
14601 return argf_inplace_mode_get(*var);
14602}
14603
14604/*
14605 * call-seq:
14606 * ARGF.inplace_mode = ext -> ARGF
14607 *
14608 * Sets the filename extension for in-place editing mode to the given String.
14609 * The backup copy of each file being edited has this value appended to its
14610 * filename.
14611 *
14612 * For example:
14613 *
14614 * $ ruby argf.rb file.txt
14615 *
14616 * ARGF.inplace_mode = '.bak'
14617 * ARGF.each_line do |line|
14618 * print line.sub("foo","bar")
14619 * end
14620 *
14621 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14622 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14623 * "bar".
14624 */
14625static VALUE
14626argf_inplace_mode_set(VALUE argf, VALUE val)
14627{
14628 if (!RTEST(val)) {
14629 ARGF.inplace = Qfalse;
14630 }
14631 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14632 ARGF.inplace = Qnil;
14633 }
14634 else {
14635 ARGF.inplace = rb_str_new_frozen(val);
14636 }
14637 return argf;
14638}
14639
14640static void
14641opt_i_set(VALUE val, ID id, VALUE *var)
14642{
14643 argf_inplace_mode_set(*var, val);
14644}
14645
14646void
14647ruby_set_inplace_mode(const char *suffix)
14648{
14649 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14650}
14651
14652/*
14653 * call-seq:
14654 * ARGF.argv -> ARGV
14655 *
14656 * Returns the +ARGV+ array, which contains the arguments passed to your
14657 * script, one per element.
14658 *
14659 * For example:
14660 *
14661 * $ ruby argf.rb -v glark.txt
14662 *
14663 * ARGF.argv #=> ["-v", "glark.txt"]
14664 *
14665 */
14666static VALUE
14667argf_argv(VALUE argf)
14668{
14669 return ARGF.argv;
14670}
14671
14672static VALUE
14673argf_argv_getter(ID id, VALUE *var)
14674{
14675 return argf_argv(*var);
14676}
14677
14678VALUE
14680{
14681 return ARGF.argv;
14682}
14683
14684/*
14685 * call-seq:
14686 * ARGF.to_write_io -> io
14687 *
14688 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14689 * enabled.
14690 */
14691static VALUE
14692argf_write_io(VALUE argf)
14693{
14694 if (!RTEST(ARGF.current_file)) {
14695 rb_raise(rb_eIOError, "not opened for writing");
14696 }
14697 return GetWriteIO(ARGF.current_file);
14698}
14699
14700/*
14701 * call-seq:
14702 * ARGF.write(*objects) -> integer
14703 *
14704 * Writes each of the given +objects+ if inplace mode.
14705 */
14706static VALUE
14707argf_write(int argc, VALUE *argv, VALUE argf)
14708{
14709 return rb_io_writev(argf_write_io(argf), argc, argv);
14710}
14711
14712void
14713rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14714{
14715 rb_readwrite_syserr_fail(waiting, errno, mesg);
14716}
14717
14718void
14719rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14720{
14721 VALUE arg, c = Qnil;
14722 arg = mesg ? rb_str_new2(mesg) : Qnil;
14723 switch (waiting) {
14724 case RB_IO_WAIT_WRITABLE:
14725 switch (n) {
14726 case EAGAIN:
14727 c = rb_eEAGAINWaitWritable;
14728 break;
14729#if EAGAIN != EWOULDBLOCK
14730 case EWOULDBLOCK:
14731 c = rb_eEWOULDBLOCKWaitWritable;
14732 break;
14733#endif
14734 case EINPROGRESS:
14735 c = rb_eEINPROGRESSWaitWritable;
14736 break;
14737 default:
14739 }
14740 break;
14741 case RB_IO_WAIT_READABLE:
14742 switch (n) {
14743 case EAGAIN:
14744 c = rb_eEAGAINWaitReadable;
14745 break;
14746#if EAGAIN != EWOULDBLOCK
14747 case EWOULDBLOCK:
14748 c = rb_eEWOULDBLOCKWaitReadable;
14749 break;
14750#endif
14751 case EINPROGRESS:
14752 c = rb_eEINPROGRESSWaitReadable;
14753 break;
14754 default:
14756 }
14757 break;
14758 default:
14759 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14760 }
14762}
14763
14764static VALUE
14765get_LAST_READ_LINE(ID _x, VALUE *_y)
14766{
14767 return rb_lastline_get();
14768}
14769
14770static void
14771set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14772{
14773 rb_lastline_set(val);
14774}
14775
14776/*
14777 * Document-class: IOError
14778 *
14779 * Raised when an IO operation fails.
14780 *
14781 * File.open("/etc/hosts") {|f| f << "example"}
14782 * #=> IOError: not opened for writing
14783 *
14784 * File.open("/etc/hosts") {|f| f.close; f.read }
14785 * #=> IOError: closed stream
14786 *
14787 * Note that some IO failures raise <code>SystemCallError</code>s
14788 * and these are not subclasses of IOError:
14789 *
14790 * File.open("does/not/exist")
14791 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14792 */
14793
14794/*
14795 * Document-class: EOFError
14796 *
14797 * Raised by some IO operations when reaching the end of file. Many IO
14798 * methods exist in two forms,
14799 *
14800 * one that returns +nil+ when the end of file is reached, the other
14801 * raises EOFError.
14802 *
14803 * EOFError is a subclass of IOError.
14804 *
14805 * file = File.open("/etc/hosts")
14806 * file.read
14807 * file.gets #=> nil
14808 * file.readline #=> EOFError: end of file reached
14809 * file.close
14810 */
14811
14812/*
14813 * Document-class: ARGF
14814 *
14815 * == \ARGF and +ARGV+
14816 *
14817 * The \ARGF object works with the array at global variable +ARGV+
14818 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14819 *
14820 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14821 *
14822 * Initially, it contains the command-line arguments and options
14823 * that are passed to the Ruby program;
14824 * the program can modify that array as it likes.
14825 *
14826 * - **ARGF** may be thought of as the <b>argument files</b> object.
14827 *
14828 * It can access file streams and/or the <tt>$stdin</tt> stream,
14829 * based on what it finds in +ARGV+.
14830 * This provides a convenient way for the command line
14831 * to specify streams for a Ruby program to read.
14832 *
14833 * == Reading
14834 *
14835 * \ARGF may read from _source_ streams,
14836 * which at any particular time are determined by the content of +ARGV+.
14837 *
14838 * === Simplest Case
14839 *
14840 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14841 * the source is <tt>$stdin</tt>:
14842 *
14843 * - \File +t.rb+:
14844 *
14845 * p ['ARGV', ARGV]
14846 * p ['ARGF.read', ARGF.read]
14847 *
14848 * - Commands and outputs
14849 * (see below for the content of files +foo.txt+ and +bar.txt+):
14850 *
14851 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14852 * ["ARGV", []]
14853 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14854 *
14855 * $ cat foo.txt bar.txt | ruby t.rb
14856 * ["ARGV", []]
14857 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14858 *
14859 * === About the Examples
14860 *
14861 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14862 *
14863 * $ cat foo.txt
14864 * Foo 0
14865 * Foo 1
14866 * $ cat bar.txt
14867 * Bar 0
14868 * Bar 1
14869 * Bar 2
14870 * Bar 3
14871 *
14872 * === Sources in +ARGV+
14873 *
14874 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14875 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14876 * the sources are found in +ARGV+.
14877 *
14878 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14879 * and is one of:
14880 *
14881 * - The string path to a file that may be opened as a stream.
14882 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14883 *
14884 * Each element that is _not_ one of these
14885 * should be removed from +ARGV+ before \ARGF accesses that source.
14886 *
14887 * In the following example:
14888 *
14889 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14890 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14891 *
14892 * Example:
14893 *
14894 * - \File +t.rb+:
14895 *
14896 * # Print arguments (and options, if any) found on command line.
14897 * p ['ARGV', ARGV]
14898 *
14899 * - Command and output:
14900 *
14901 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14902 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14903 *
14904 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14905 *
14906 * - \File +t.rb+:
14907 *
14908 * p "ARGV: #{ARGV}"
14909 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
14910 *
14911 * - Command and output:
14912 *
14913 * $ ruby t.rb foo.txt bar.txt
14914 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14915 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14916 *
14917 * Because the value at +ARGV+ is an ordinary array,
14918 * you can manipulate it to control which sources \ARGF considers:
14919 *
14920 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14921 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14922 *
14923 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14924 * when all sources have been accessed, the array is empty:
14925 *
14926 * - \File +t.rb+:
14927 *
14928 * until ARGV.empty? && ARGF.eof?
14929 * p "ARGV: #{ARGV}"
14930 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14931 * end
14932 *
14933 * - Command and output:
14934 *
14935 * $ ruby t.rb foo.txt bar.txt
14936 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14937 * "Line: Foo 0\n"
14938 * "ARGV: [\"bar.txt\"]"
14939 * "Line: Foo 1\n"
14940 * "ARGV: [\"bar.txt\"]"
14941 * "Line: Bar 0\n"
14942 * "ARGV: []"
14943 * "Line: Bar 1\n"
14944 * "ARGV: []"
14945 * "Line: Bar 2\n"
14946 * "ARGV: []"
14947 * "Line: Bar 3\n"
14948 *
14949 * ==== Filepaths in +ARGV+
14950 *
14951 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14952 *
14953 * This program prints what it reads from files at the paths specified
14954 * on the command line:
14955 *
14956 * - \File +t.rb+:
14957 *
14958 * p ['ARGV', ARGV]
14959 * # Read and print all content from the specified sources.
14960 * p ['ARGF.read', ARGF.read]
14961 *
14962 * - Command and output:
14963 *
14964 * $ ruby t.rb foo.txt bar.txt
14965 * ["ARGV", [foo.txt, bar.txt]
14966 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14967 *
14968 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14969 *
14970 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14971 *
14972 * - \File +t.rb+:
14973 *
14974 * p ['ARGV', ARGV]
14975 * p ['ARGF.read', ARGF.read]
14976 *
14977 * - Command and output:
14978 *
14979 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14980 * ["ARGV", ["-"]]
14981 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14982 *
14983 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
14984 * (exception:
14985 * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
14986 *
14987 * - Command and output:
14988 *
14989 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
14990 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14991 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14992 *
14993 * ==== Mixtures and Repetitions in +ARGV+
14994 *
14995 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
14996 * and character <tt>'-'</tt>, including repetitions.
14997 *
14998 * ==== Modifications to +ARGV+
14999 *
15000 * The running Ruby program may make any modifications to the +ARGV+ array;
15001 * the current value of +ARGV+ affects \ARGF reading.
15002 *
15003 * ==== Empty +ARGV+
15004 *
15005 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15006 * or raises an exception, depending on the specific method.
15007 *
15008 * === More Read Methods
15009 *
15010 * As seen above, method ARGF#read reads the content of all sources
15011 * into a single string.
15012 * Other \ARGF methods provide other ways to access that content;
15013 * these include:
15014 *
15015 * - Byte access: #each_byte, #getbyte, #readbyte.
15016 * - Character access: #each_char, #getc, #readchar.
15017 * - Codepoint access: #each_codepoint.
15018 * - Line access: #each_line, #gets, #readline, #readlines.
15019 * - Source access: #read, #read_nonblock, #readpartial.
15020 *
15021 * === About \Enumerable
15022 *
15023 * \ARGF includes module Enumerable.
15024 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15025 *
15026 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15027 * _not_ from +ARGV+;
15028 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15029 * not an array of the strings from +ARGV+:
15030 *
15031 * - \File +t.rb+:
15032 *
15033 * p ['ARGV', ARGV]
15034 * p ['ARGF.entries', ARGF.entries]
15035 *
15036 * - Command and output:
15037 *
15038 * $ ruby t.rb foo.txt bar.txt
15039 * ["ARGV", ["foo.txt", "bar.txt"]]
15040 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15041 *
15042 * == Writing
15043 *
15044 * If <i>inplace mode</i> is in effect,
15045 * \ARGF may write to target streams,
15046 * which at any particular time are determined by the content of ARGV.
15047 *
15048 * Methods about inplace mode:
15049 *
15050 * - #inplace_mode
15051 * - #inplace_mode=
15052 * - #to_write_io
15053 *
15054 * Methods for writing:
15055 *
15056 * - #print
15057 * - #printf
15058 * - #putc
15059 * - #puts
15060 * - #write
15061 *
15062 */
15063
15064/*
15065 * An instance of class \IO (commonly called a _stream_)
15066 * represents an input/output stream in the underlying operating system.
15067 * Class \IO is the basis for input and output in Ruby.
15068 *
15069 * Class File is the only class in the Ruby core that is a subclass of \IO.
15070 * Some classes in the Ruby standard library are also subclasses of \IO;
15071 * these include TCPSocket and UDPSocket.
15072 *
15073 * The global constant ARGF (also accessible as <tt>$<</tt>)
15074 * provides an IO-like stream that allows access to all file paths
15075 * found in ARGV (or found in STDIN if ARGV is empty).
15076 * ARGF is not itself a subclass of \IO.
15077 *
15078 * Class StringIO provides an IO-like stream that handles a String.
15079 * StringIO is not itself a subclass of \IO.
15080 *
15081 * Important objects based on \IO include:
15082 *
15083 * - $stdin.
15084 * - $stdout.
15085 * - $stderr.
15086 * - Instances of class File.
15087 *
15088 * An instance of \IO may be created using:
15089 *
15090 * - IO.new: returns a new \IO object for the given integer file descriptor.
15091 * - IO.open: passes a new \IO object to the given block.
15092 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15093 * of a newly-launched subprocess.
15094 * - Kernel#open: Returns a new \IO object connected to a given source:
15095 * stream, file, or subprocess.
15096 *
15097 * Like a File stream, an \IO stream has:
15098 *
15099 * - A read/write mode, which may be read-only, write-only, or read/write;
15100 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
15101 * - A data mode, which may be text-only or binary;
15102 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15103 * - Internal and external encodings;
15104 * see {Encodings}[rdoc-ref:File@Encodings].
15105 *
15106 * And like other \IO streams, it has:
15107 *
15108 * - A position, which determines where in the stream the next
15109 * read or write is to occur;
15110 * see {Position}[rdoc-ref:IO@Position].
15111 * - A line number, which is a special, line-oriented, "position"
15112 * (different from the position mentioned above);
15113 * see {Line Number}[rdoc-ref:IO@Line+Number].
15114 *
15115 * == Extension <tt>io/console</tt>
15116 *
15117 * Extension <tt>io/console</tt> provides numerous methods
15118 * for interacting with the console;
15119 * requiring it adds numerous methods to class \IO.
15120 *
15121 * == Example Files
15122 *
15123 * Many examples here use these variables:
15124 *
15125 * :include: doc/examples/files.rdoc
15126 *
15127 * == Open Options
15128 *
15129 * A number of \IO methods accept optional keyword arguments
15130 * that determine how a new stream is to be opened:
15131 *
15132 * - +:mode+: Stream mode.
15133 * - +:flags+: Integer file open flags;
15134 * If +mode+ is also given, the two are bitwise-ORed.
15135 * - +:external_encoding+: External encoding for the stream.
15136 * - +:internal_encoding+: Internal encoding for the stream.
15137 * <tt>'-'</tt> is a synonym for the default internal encoding.
15138 * If the value is +nil+ no conversion occurs.
15139 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15140 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15141 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15142 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15143 * when the stream closes; otherwise it remains open.
15144 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15145 * #path method.
15146 *
15147 * Also available are the options offered in String#encode,
15148 * which may control conversion between external and internal encoding.
15149 *
15150 * == Basic \IO
15151 *
15152 * You can perform basic stream \IO with these methods,
15153 * which typically operate on multi-byte strings:
15154 *
15155 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15156 * - IO#write: Writes zero or more strings to the stream;
15157 * each given object that is not already a string is converted via +to_s+.
15158 *
15159 * === Position
15160 *
15161 * An \IO stream has a nonnegative integer _position_,
15162 * which is the byte offset at which the next read or write is to occur.
15163 * A new stream has position zero (and line number zero);
15164 * method +rewind+ resets the position (and line number) to zero.
15165 *
15166 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15167 * Encoding::Converter instances used for that \IO.
15168 *
15169 * The relevant methods:
15170 *
15171 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15172 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15173 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15174 * relative to a given position +whence+
15175 * (indicating the beginning, end, or current position).
15176 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15177 *
15178 * === Open and Closed Streams
15179 *
15180 * A new \IO stream may be open for reading, open for writing, or both.
15181 *
15182 * A stream is automatically closed when claimed by the garbage collector.
15183 *
15184 * Attempted reading or writing on a closed stream raises an exception.
15185 *
15186 * The relevant methods:
15187 *
15188 * - IO#close: Closes the stream for both reading and writing.
15189 * - IO#close_read: Closes the stream for reading.
15190 * - IO#close_write: Closes the stream for writing.
15191 * - IO#closed?: Returns whether the stream is closed.
15192 *
15193 * === End-of-Stream
15194 *
15195 * You can query whether a stream is positioned at its end:
15196 *
15197 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15198 *
15199 * You can reposition to end-of-stream by using method IO#seek:
15200 *
15201 * f = File.new('t.txt')
15202 * f.eof? # => false
15203 * f.seek(0, :END)
15204 * f.eof? # => true
15205 * f.close
15206 *
15207 * Or by reading all stream content (which is slower than using IO#seek):
15208 *
15209 * f.rewind
15210 * f.eof? # => false
15211 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15212 * f.eof? # => true
15213 *
15214 * == Line \IO
15215 *
15216 * Class \IO supports line-oriented
15217 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15218 *
15219 * === Line Input
15220 *
15221 * Class \IO supports line-oriented input for
15222 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15223 *
15224 * ==== \File Line Input
15225 *
15226 * You can read lines from a file using these methods:
15227 *
15228 * - IO.foreach: Reads each line and passes it to the given block.
15229 * - IO.readlines: Reads and returns all lines in an array.
15230 *
15231 * For each of these methods:
15232 *
15233 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15234 * - Line parsing depends on the effective <i>line separator</i>;
15235 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15236 * - The length of each returned line depends on the effective <i>line limit</i>;
15237 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15238 *
15239 * ==== Stream Line Input
15240 *
15241 * You can read lines from an \IO stream using these methods:
15242 *
15243 * - IO#each_line: Reads each remaining line, passing it to the given block.
15244 * - IO#gets: Returns the next line.
15245 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15246 * - IO#readlines: Returns all remaining lines in an array.
15247 *
15248 * For each of these methods:
15249 *
15250 * - Reading may begin mid-line,
15251 * depending on the stream's _position_;
15252 * see {Position}[rdoc-ref:IO@Position].
15253 * - Line parsing depends on the effective <i>line separator</i>;
15254 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15255 * - The length of each returned line depends on the effective <i>line limit</i>;
15256 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15257 *
15258 * ===== Line Separator
15259 *
15260 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15261 * the string that determines what is considered a line;
15262 * it is sometimes called the <i>input record separator</i>.
15263 *
15264 * The default line separator is taken from global variable <tt>$/</tt>,
15265 * whose initial value is <tt>"\n"</tt>.
15266 *
15267 * Generally, the line to be read next is all data
15268 * from the current {position}[rdoc-ref:IO@Position]
15269 * to the next line separator
15270 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15271 *
15272 * f = File.new('t.txt')
15273 * # Method gets with no sep argument returns the next line, according to $/.
15274 * f.gets # => "First line\n"
15275 * f.gets # => "Second line\n"
15276 * f.gets # => "\n"
15277 * f.gets # => "Fourth line\n"
15278 * f.gets # => "Fifth line\n"
15279 * f.close
15280 *
15281 * You can use a different line separator by passing argument +sep+:
15282 *
15283 * f = File.new('t.txt')
15284 * f.gets('l') # => "First l"
15285 * f.gets('li') # => "ine\nSecond li"
15286 * f.gets('lin') # => "ne\n\nFourth lin"
15287 * f.gets # => "e\n"
15288 * f.close
15289 *
15290 * Or by setting global variable <tt>$/</tt>:
15291 *
15292 * f = File.new('t.txt')
15293 * $/ = 'l'
15294 * f.gets # => "First l"
15295 * f.gets # => "ine\nSecond l"
15296 * f.gets # => "ine\n\nFourth l"
15297 * f.close
15298 *
15299 * ===== Special Line Separator Values
15300 *
15301 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15302 * accepts two special values for parameter +sep+:
15303 *
15304 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15305 *
15306 * f = File.new('t.txt')
15307 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15308 * f.close
15309 *
15310 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15311 * (paragraphs being separated by two consecutive line separators):
15312 *
15313 * f = File.new('t.txt')
15314 * f.gets('') # => "First line\nSecond line\n\n"
15315 * f.gets('') # => "Fourth line\nFifth line\n"
15316 * f.close
15317 *
15318 * ===== Line Limit
15319 *
15320 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15321 * uses an integer <i>line limit</i>,
15322 * which restricts the number of bytes that may be returned.
15323 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15324 * than the limit).
15325 *
15326 * The default limit value is <tt>-1</tt>;
15327 * any negative limit value means that there is no limit.
15328 *
15329 * If there is no limit, the line is determined only by +sep+.
15330 *
15331 * # Text with 1-byte characters.
15332 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15333 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15334 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15335 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15336 * # No more than one line.
15337 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15338 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15339 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15340 *
15341 * # Text with 2-byte characters, which will not be split.
15342 * File.open('t.rus') {|f| f.gets(1).size } # => 1
15343 * File.open('t.rus') {|f| f.gets(2).size } # => 1
15344 * File.open('t.rus') {|f| f.gets(3).size } # => 2
15345 * File.open('t.rus') {|f| f.gets(4).size } # => 2
15346 *
15347 * ===== Line Separator and Line Limit
15348 *
15349 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15350 *
15351 * - Returns the next line as determined by line separator +sep+.
15352 * - But returns no more bytes than are allowed by the limit +limit+.
15353 *
15354 * Example:
15355 *
15356 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15357 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15358 *
15359 * ===== Line Number
15360 *
15361 * A readable \IO stream has a non-negative integer <i>line number</i>:
15362 *
15363 * - IO#lineno: Returns the line number.
15364 * - IO#lineno=: Resets and returns the line number.
15365 *
15366 * Unless modified by a call to method IO#lineno=,
15367 * the line number is the number of lines read
15368 * by certain line-oriented methods,
15369 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15370 *
15371 * - IO.foreach: Increments the line number on each call to the block.
15372 * - IO#each_line: Increments the line number on each call to the block.
15373 * - IO#gets: Increments the line number.
15374 * - IO#readline: Increments the line number.
15375 * - IO#readlines: Increments the line number for each line read.
15376 *
15377 * A new stream is initially has line number zero (and position zero);
15378 * method +rewind+ resets the line number (and position) to zero:
15379 *
15380 * f = File.new('t.txt')
15381 * f.lineno # => 0
15382 * f.gets # => "First line\n"
15383 * f.lineno # => 1
15384 * f.rewind
15385 * f.lineno # => 0
15386 * f.close
15387 *
15388 * Reading lines from a stream usually changes its line number:
15389 *
15390 * f = File.new('t.txt', 'r')
15391 * f.lineno # => 0
15392 * f.readline # => "This is line one.\n"
15393 * f.lineno # => 1
15394 * f.readline # => "This is the second line.\n"
15395 * f.lineno # => 2
15396 * f.readline # => "Here's the third line.\n"
15397 * f.lineno # => 3
15398 * f.eof? # => true
15399 * f.close
15400 *
15401 * Iterating over lines in a stream usually changes its line number:
15402 *
15403 * File.open('t.txt') do |f|
15404 * f.each_line do |line|
15405 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15406 * end
15407 * end
15408 *
15409 * Output:
15410 *
15411 * "position=11 eof?=false lineno=1"
15412 * "position=23 eof?=false lineno=2"
15413 * "position=24 eof?=false lineno=3"
15414 * "position=36 eof?=false lineno=4"
15415 * "position=47 eof?=true lineno=5"
15416 *
15417 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15418 * the line number does not affect where the next read or write will occur:
15419 *
15420 * f = File.new('t.txt')
15421 * f.lineno = 1000
15422 * f.lineno # => 1000
15423 * f.gets # => "First line\n"
15424 * f.lineno # => 1001
15425 * f.close
15426 *
15427 * Associated with the line number is the global variable <tt>$.</tt>:
15428 *
15429 * - When a stream is opened, <tt>$.</tt> is not set;
15430 * its value is left over from previous activity in the process:
15431 *
15432 * $. = 41
15433 * f = File.new('t.txt')
15434 * $. = 41
15435 * # => 41
15436 * f.close
15437 *
15438 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15439 *
15440 * f0 = File.new('t.txt')
15441 * f1 = File.new('t.dat')
15442 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15443 * $. # => 5
15444 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15445 * $. # => 1
15446 * f0.close
15447 * f1.close
15448 *
15449 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15450 *
15451 * f = File.new('t.txt')
15452 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15453 * $. # => 5
15454 * f.rewind
15455 * f.seek(0, :SET)
15456 * $. # => 5
15457 * f.close
15458 *
15459 * === Line Output
15460 *
15461 * You can write to an \IO stream line-by-line using this method:
15462 *
15463 * - IO#puts: Writes objects to the stream.
15464 *
15465 * == Character \IO
15466 *
15467 * You can process an \IO stream character-by-character using these methods:
15468 *
15469 * - IO#getc: Reads and returns the next character from the stream.
15470 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15471 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15472 * - IO#putc: Writes a character to the stream.
15473 * - IO#each_char: Reads each remaining character in the stream,
15474 * passing the character to the given block.
15475 *
15476 * == Byte \IO
15477 *
15478 * You can process an \IO stream byte-by-byte using these methods:
15479 *
15480 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15481 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15482 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15483 * - IO#each_byte: Reads each remaining byte in the stream,
15484 * passing the byte to the given block.
15485 *
15486 * == Codepoint \IO
15487 *
15488 * You can process an \IO stream codepoint-by-codepoint:
15489 *
15490 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15491 *
15492 * == What's Here
15493 *
15494 * First, what's elsewhere. Class \IO:
15495 *
15496 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15497 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15498 * which provides dozens of additional methods.
15499 *
15500 * Here, class \IO provides methods that are useful for:
15501 *
15502 * - {Creating}[rdoc-ref:IO@Creating]
15503 * - {Reading}[rdoc-ref:IO@Reading]
15504 * - {Writing}[rdoc-ref:IO@Writing]
15505 * - {Positioning}[rdoc-ref:IO@Positioning]
15506 * - {Iterating}[rdoc-ref:IO@Iterating]
15507 * - {Settings}[rdoc-ref:IO@Settings]
15508 * - {Querying}[rdoc-ref:IO@Querying]
15509 * - {Buffering}[rdoc-ref:IO@Buffering]
15510 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15511 * - {Other}[rdoc-ref:IO@Other]
15512 *
15513 * === Creating
15514 *
15515 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15516 * integer file descriptor.
15517 * - ::open: Creates a new \IO object.
15518 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15519 * - ::popen: Creates an \IO object to interact with a subprocess.
15520 * - ::select: Selects which given \IO instances are ready for reading,
15521 * writing, or have pending exceptions.
15522 *
15523 * === Reading
15524 *
15525 * - ::binread: Returns a binary string with all or a subset of bytes
15526 * from the given file.
15527 * - ::read: Returns a string with all or a subset of bytes from the given file.
15528 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15529 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15530 * - #getc: Returns the next character read from +self+ as a string.
15531 * - #gets: Returns the line read from +self+.
15532 * - #pread: Returns all or the next _n_ bytes read from +self+,
15533 * not updating the receiver's offset.
15534 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15535 * for a given _n_.
15536 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15537 * in non-block mode.
15538 * - #readbyte: Returns the next byte read from +self+;
15539 * same as #getbyte, but raises an exception on end-of-stream.
15540 * - #readchar: Returns the next character read from +self+;
15541 * same as #getc, but raises an exception on end-of-stream.
15542 * - #readline: Returns the next line read from +self+;
15543 * same as #getline, but raises an exception of end-of-stream.
15544 * - #readlines: Returns an array of all lines read read from +self+.
15545 * - #readpartial: Returns up to the given number of bytes from +self+.
15546 *
15547 * === Writing
15548 *
15549 * - ::binwrite: Writes the given string to the file at the given filepath,
15550 * in binary mode.
15551 * - ::write: Writes the given string to +self+.
15552 * - #<<: Appends the given string to +self+.
15553 * - #print: Prints last read line or given objects to +self+.
15554 * - #printf: Writes to +self+ based on the given format string and objects.
15555 * - #putc: Writes a character to +self+.
15556 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15557 * - #pwrite: Writes the given string at the given offset,
15558 * not updating the receiver's offset.
15559 * - #write: Writes one or more given strings to +self+.
15560 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15561 *
15562 * === Positioning
15563 *
15564 * - #lineno: Returns the current line number in +self+.
15565 * - #lineno=: Sets the line number is +self+.
15566 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15567 * - #pos=: Sets the byte offset in +self+.
15568 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15569 * - #rewind: Positions +self+ to the beginning of input.
15570 * - #seek: Sets the offset for +self+ relative to given position.
15571 *
15572 * === Iterating
15573 *
15574 * - ::foreach: Yields each line of given file to the block.
15575 * - #each (aliased as #each_line): Calls the given block
15576 * with each successive line in +self+.
15577 * - #each_byte: Calls the given block with each successive byte in +self+
15578 * as an integer.
15579 * - #each_char: Calls the given block with each successive character in +self+
15580 * as a string.
15581 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15582 * as an integer.
15583 *
15584 * === Settings
15585 *
15586 * - #autoclose=: Sets whether +self+ auto-closes.
15587 * - #binmode: Sets +self+ to binary mode.
15588 * - #close: Closes +self+.
15589 * - #close_on_exec=: Sets the close-on-exec flag.
15590 * - #close_read: Closes +self+ for reading.
15591 * - #close_write: Closes +self+ for writing.
15592 * - #set_encoding: Sets the encoding for +self+.
15593 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15594 * Unicode byte-order-mark.
15595 * - #sync=: Sets the sync-mode to the given value.
15596 *
15597 * === Querying
15598 *
15599 * - #autoclose?: Returns whether +self+ auto-closes.
15600 * - #binmode?: Returns whether +self+ is in binary mode.
15601 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15602 * - #closed?: Returns whether +self+ is closed.
15603 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15604 * - #external_encoding: Returns the external encoding object for +self+.
15605 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15606 * - #internal_encoding: Returns the internal encoding object for +self+.
15607 * - #pid: Returns the process ID of a child process associated with +self+,
15608 * if +self+ was created by ::popen.
15609 * - #stat: Returns the File::Stat object containing status information for +self+.
15610 * - #sync: Returns whether +self+ is in sync-mode.
15611 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15612 *
15613 * === Buffering
15614 *
15615 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15616 * - #flush: Flushes any buffered data within +self+ to the underlying
15617 * operating system.
15618 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15619 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15620 * - #ungetc: Prepends buffer for +self+ with given string.
15621 *
15622 * === Low-Level Access
15623 *
15624 * - ::sysopen: Opens the file given by its path,
15625 * returning the integer file descriptor.
15626 * - #advise: Announces the intention to access data from +self+ in a specific way.
15627 * - #fcntl: Passes a low-level command to the file specified
15628 * by the given file descriptor.
15629 * - #ioctl: Passes a low-level command to the device specified
15630 * by the given file descriptor.
15631 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15632 * - #sysseek: Sets the offset for +self+.
15633 * - #syswrite: Writes the given string to +self+ using a low-level write.
15634 *
15635 * === Other
15636 *
15637 * - ::copy_stream: Copies data from a source to a destination,
15638 * each of which is a filepath or an \IO-like object.
15639 * - ::try_convert: Returns a new \IO object resulting from converting
15640 * the given object.
15641 * - #inspect: Returns the string representation of +self+.
15642 *
15643 */
15644
15645void
15646Init_IO(void)
15647{
15648 VALUE rb_cARGF;
15649#ifdef __CYGWIN__
15650#include <sys/cygwin.h>
15651 static struct __cygwin_perfile pf[] =
15652 {
15653 {"", O_RDONLY | O_BINARY},
15654 {"", O_WRONLY | O_BINARY},
15655 {"", O_RDWR | O_BINARY},
15656 {"", O_APPEND | O_BINARY},
15657 {NULL, 0}
15658 };
15659 cygwin_internal(CW_PERFILE, pf);
15660#endif
15661
15664
15665 id_write = rb_intern_const("write");
15666 id_read = rb_intern_const("read");
15667 id_getc = rb_intern_const("getc");
15668 id_flush = rb_intern_const("flush");
15669 id_readpartial = rb_intern_const("readpartial");
15670 id_set_encoding = rb_intern_const("set_encoding");
15671 id_fileno = rb_intern_const("fileno");
15672
15673 rb_define_global_function("syscall", rb_f_syscall, -1);
15674
15675 rb_define_global_function("open", rb_f_open, -1);
15676 rb_define_global_function("printf", rb_f_printf, -1);
15677 rb_define_global_function("print", rb_f_print, -1);
15678 rb_define_global_function("putc", rb_f_putc, 1);
15679 rb_define_global_function("puts", rb_f_puts, -1);
15680 rb_define_global_function("gets", rb_f_gets, -1);
15681 rb_define_global_function("readline", rb_f_readline, -1);
15682 rb_define_global_function("select", rb_f_select, -1);
15683
15684 rb_define_global_function("readlines", rb_f_readlines, -1);
15685
15686 rb_define_global_function("`", rb_f_backquote, 1);
15687
15688 rb_define_global_function("p", rb_f_p, -1);
15689 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15690
15691 rb_cIO = rb_define_class("IO", rb_cObject);
15693
15694 /* Can be raised by IO operations when IO#timeout= is set. */
15696
15697 /* Readable event mask for IO#wait. */
15698 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15699 /* Writable event mask for IO#wait. */
15700 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15701 /* Priority event mask for IO#wait. */
15702 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15703
15704 /* exception to wait for reading. see IO.select. */
15706 /* exception to wait for writing. see IO.select. */
15708 /* exception to wait for reading by EAGAIN. see IO.select. */
15709 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15710 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15711 /* exception to wait for writing by EAGAIN. see IO.select. */
15712 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15713 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15714#if EAGAIN == EWOULDBLOCK
15715 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15716 /* same as IO::EAGAINWaitReadable */
15717 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15718 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15719 /* same as IO::EAGAINWaitWritable */
15720 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15721#else
15722 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15723 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15724 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15725 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15726 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15727 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15728#endif
15729 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15730 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15731 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15732 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15733 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15734 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15735
15736#if 0
15737 /* This is necessary only for forcing rdoc handle File::open */
15738 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15739#endif
15740
15741 rb_define_alloc_func(rb_cIO, io_alloc);
15742 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15743 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15744 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15745 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15746 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15747 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15748 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15749 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15750 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15751 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15752 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15753 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15754 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15755 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15756 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15757
15758 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15759
15761 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
15762
15763 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15764 rb_vm_register_global_object(rb_default_rs);
15765 rb_rs = rb_default_rs;
15767 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15768 rb_gvar_ractor_local("$/"); // not local but ractor safe
15769 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15770 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15771 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
15772
15773 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15774 rb_gvar_ractor_local("$_");
15775
15776 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15777 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15778
15779 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15780 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15781 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15782 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15783
15784 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15785 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15786 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15787 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15788 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15789
15790 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15791 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15792
15793 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15794 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15795
15796 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15797 rb_define_alias(rb_cIO, "to_i", "fileno");
15798 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15799
15800 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15801 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15802
15803 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15804 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15805 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15806 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15807
15808 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15809 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15810
15811 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15812
15813 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15814 rb_define_method(rb_cIO, "read", io_read, -1);
15815 rb_define_method(rb_cIO, "write", io_write_m, -1);
15816 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15817 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15818 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15819 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15820 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15821 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15822 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15824 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15825 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15826 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15827 /* Set I/O position from the beginning */
15828 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15829 /* Set I/O position from the current position */
15830 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15831 /* Set I/O position from the end */
15832 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15833#ifdef SEEK_DATA
15834 /* Set I/O position to the next location containing data */
15835 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15836#endif
15837#ifdef SEEK_HOLE
15838 /* Set I/O position to the next hole */
15839 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15840#endif
15841 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15842 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15843 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15844 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15845 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15846
15847 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15848 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15849
15850 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15851 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15852 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15853 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15854
15855 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15856 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15857 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15858 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15859 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15860 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15861
15862 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15863 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15864 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15865
15866 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15867 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15868
15869 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15870
15871 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15872 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15873 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15874 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15875
15876 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15877 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15878
15879 rb_define_method(rb_cIO, "wait", io_wait, -1);
15880
15881 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15882 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15883 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15884
15885 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15886 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15887 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15888 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15889
15890 rb_gvar_ractor_local("$stdin");
15891 rb_gvar_ractor_local("$stdout");
15892 rb_gvar_ractor_local("$>");
15893 rb_gvar_ractor_local("$stderr");
15894
15896 rb_stdin = rb_io_prep_stdin();
15898 rb_stdout = rb_io_prep_stdout();
15900 rb_stderr = rb_io_prep_stderr();
15901
15902 orig_stdout = rb_stdout;
15903 orig_stderr = rb_stderr;
15904
15905 /* Holds the original stdin */
15907 /* Holds the original stdout */
15909 /* Holds the original stderr */
15911
15912#if 0
15913 /* Hack to get rdoc to regard ARGF as a class: */
15914 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15915#endif
15916
15917 rb_cARGF = rb_class_new(rb_cObject);
15918 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15919 rb_define_alloc_func(rb_cARGF, argf_alloc);
15920
15922
15923 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15924 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15925 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15926 rb_define_alias(rb_cARGF, "inspect", "to_s");
15927 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15928
15929 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15930 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15931 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15932 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15933 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15934 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15935 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15936 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15937 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15938
15939 rb_define_method(rb_cARGF, "read", argf_read, -1);
15940 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15941 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15942 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15943 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15944 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15945 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15946 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15947 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15948 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15949 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15950 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15951 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15952 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15953 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15954 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15955 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15956 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15957 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15958 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15959
15960 rb_define_method(rb_cARGF, "write", argf_write, -1);
15961 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15962 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15963 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15964 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15965
15966 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15967 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15968 rb_define_method(rb_cARGF, "file", argf_file, 0);
15969 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15970 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15971 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15972
15973 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15974 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15975
15976 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15977 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15978
15979 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15980 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15981 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15982
15983 argf = rb_class_new_instance(0, 0, rb_cARGF);
15984
15986 /*
15987 * ARGF is a stream designed for use in scripts that process files given
15988 * as command-line arguments or passed in via STDIN.
15989 *
15990 * See ARGF (the class) for more details.
15991 */
15993
15994 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15995 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15996 ARGF.filename = rb_str_new2("-");
15997
15998 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15999 rb_gvar_ractor_local("$-i");
16000
16001 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16002
16003#if defined (_WIN32) || defined(__CYGWIN__)
16004 atexit(pipe_atexit);
16005#endif
16006
16007 Init_File();
16008
16009 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16010
16011 sym_mode = ID2SYM(rb_intern_const("mode"));
16012 sym_perm = ID2SYM(rb_intern_const("perm"));
16013 sym_flags = ID2SYM(rb_intern_const("flags"));
16014 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16015 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16016 sym_encoding = ID2SYM(rb_id_encoding());
16017 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16018 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16019 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16020 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16021 sym_normal = ID2SYM(rb_intern_const("normal"));
16022 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16023 sym_random = ID2SYM(rb_intern_const("random"));
16024 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16025 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16026 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16027 sym_SET = ID2SYM(rb_intern_const("SET"));
16028 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16029 sym_END = ID2SYM(rb_intern_const("END"));
16030#ifdef SEEK_DATA
16031 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16032#endif
16033#ifdef SEEK_HOLE
16034 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16035#endif
16036 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16037 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16038}
16039
16040#include "io.rbinc"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:117
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1796
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1589
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:969
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1620
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1725
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2956
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:3259
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:3246
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1007
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:3035
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1674
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:400
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1682
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:134
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:111
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:520
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:109
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition ctype.h:103
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:518
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition transcode.h:538
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:519
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1676
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
void rb_notimplement(void)
Definition error.c:3840
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:476
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:508
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1441
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:653
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3909
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
Definition io.c:14719
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:14713
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:3296
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:2192
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2233
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:2221
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:3277
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:3290
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
Definition encoding.h:571
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c: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:3922
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c: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
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h: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
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8625
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4333
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:8758
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:9187
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:5198
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5104
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:9368
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:248
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:328
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:206
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2727
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:9167
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:6413
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6367
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5262
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7415
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10446
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:7298
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:7305
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5780
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:3115
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:3797
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1497
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1680
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1531
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c: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:3565
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:4267
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3387
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:3739
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2950
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3250
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3369
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:2744
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:1513
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c: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.
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:3179
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:2017
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:3402
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:4035
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
Definition variable.c:846
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:162
enum rb_io_mode rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
Definition io.c:6499
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:6632
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
Definition io.h:260
rb_io_event
Type of events that an IO can wait.
Definition io.h:96
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:97
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition io.h:99
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition io.h:98
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:168
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
Definition io.h:252
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:442
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
Definition io.c:1015
#define FMODE_TTY
The IO is a TTY.
Definition io.h:192
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:215
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition io.c:1024
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
Definition io.c: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:7115
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:6781
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2930
#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:9414
#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
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:2
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:186
int off
Offset inside of ptr.
Definition io.h:5
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
Definition io.c:3004
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:6906
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:5700
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:5888
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
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:3454
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:9280
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
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:7402
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_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
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
#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:14679
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9066
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:90
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
Definition scan_args.h:59
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition scan_args.h:78
Scheduler APIs.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
Definition scheduler.c:466
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
Definition scheduler.c:1001
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
Definition scheduler.c:517
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
Definition scheduler.c:751
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
Definition scheduler.c:977
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:737
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
Definition scheduler.h:72
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:781
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
Definition scheduler.c:1013
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread value inst...
Definition scheduler.c:474
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
Definition scheduler.c:989
VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread)
Identical to rb_fiber_scheduler_current_for_thread(), except it expects a threadptr instead of a thre...
Definition scheduler.c:479
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
Definition scheduler.c:757
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
Definition scheduler.c:1025
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
Definition thread.c:4532
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
@ RUBY_Qfalse
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
C99 shim for <stdbool.h>
Ruby's File and IO.
Definition rfile.h:35
Definition io.c:236
Definition win32.h:230
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:208
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
Decomposed encoding flags (e.g.
Definition io.h:134
int ecflags
Flags.
Definition io.h:144
VALUE ecopts
Flags as Ruby hash.
Definition io.h:152
rb_encoding * enc2
External encoding.
Definition io.h:138
rb_encoding * enc
Internal encoding.
Definition io.h:136
IO buffers.
Definition io.h:109
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:112
int off
Offset inside of ptr.
Definition io.h:115
int len
Length of the buffer.
Definition io.h:118
int capa
Designed capacity of the buffer.
Definition io.h:121
Ruby's IO, metadata and buffers.
Definition io.h:295
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:330
enum rb_io_mode mode
mode flags: FMODE_XXXs
Definition io.h:310
void(* finalize)(struct rb_io *, int)
finalize proc
Definition io.h:326
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:352
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:363
struct rb_io_encoding encs
Decomposed encoding flags.
Definition io.h:348
VALUE self
The IO's Ruby level counterpart.
Definition io.h:298
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:400
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:406
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:302
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
Definition io.h:390
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:345
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:376
int fd
file descriptor.
Definition io.h:306
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:337
int lineno
number of lines read
Definition io.h:318
struct ccan_list_head blocking_operations
Threads that are performing a blocking operation without the GVL using this IO.
Definition io.h:131
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:372
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:359
rb_pid_t pid
child's pid (for pipes)
Definition io.h:314
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
Definition io.h:383
VALUE pathv
pathname for file
Definition io.h:322
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
Definition value_type.h:307
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:433
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376