Ruby 4.1.0dev (2026-10-29 revision 952e77c511a0d183f43464cba30c55834eac643e)
io.c (952e77c511a0d183f43464cba30c55834eac643e)
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#ifdef __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(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
53#endif
54
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun)
56# define USE_SETVBUF
57#endif
58
59#include <sys/types.h>
60#ifdef HAVE_SYS_IOCTL_H
61#include <sys/ioctl.h>
62#endif
63#if defined(HAVE_FCNTL_H)
64#include <fcntl.h>
65#elif defined(HAVE_SYS_FCNTL_H)
66#include <sys/fcntl.h>
67#endif
68
69#ifdef HAVE_SYS_TIME_H
70# include <sys/time.h>
71#endif
72
73#include <sys/stat.h>
74
75#if defined(HAVE_SYS_PARAM_H)
76# include <sys/param.h>
77#endif
78
79#if !defined NOFILE
80# define NOFILE 64
81#endif
82
83#ifdef HAVE_UNISTD_H
84#include <unistd.h>
85#endif
86
87#ifdef HAVE_SYSCALL_H
88#include <syscall.h>
89#elif defined HAVE_SYS_SYSCALL_H
90#include <sys/syscall.h>
91#endif
92
93#ifdef HAVE_SYS_UIO_H
94#include <sys/uio.h>
95#endif
96
97#ifdef HAVE_SYS_WAIT_H
98# include <sys/wait.h> /* for WNOHANG on BSD */
99#endif
100
101#ifdef HAVE_COPYFILE_H
102# include <copyfile.h>
103#endif
104
105#if defined __APPLE__
106# include <AvailabilityMacros.h>
107#endif
108
110#include "ccan/list/list.h"
111#include "dln.h"
112#include "encindex.h"
113#include "id.h"
114#include "internal.h"
115#include "internal/class.h"
116#include "internal/encoding.h"
117#include "internal/error.h"
118#include "internal/inits.h"
119#include "internal/io.h"
120#include "internal/numeric.h"
121#include "internal/object.h"
122#include "internal/process.h"
123#include "internal/string.h"
124#include "internal/thread.h"
125#include "internal/transcode.h"
126#include "internal/variable.h"
127#include "ruby/io.h"
128#include "ruby/io/buffer.h"
129#include "ruby/missing.h"
130#include "ruby/thread.h"
131#include "ruby/util.h"
132#include "ruby_atomic.h"
133#include "ruby/ractor.h"
134
135#if !USE_POLL
136# include "vm_core.h"
137#endif
138
139#include "builtin.h"
140
141#ifndef O_ACCMODE
142#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
143#endif
144
145#ifndef PIPE_BUF
146# ifdef _POSIX_PIPE_BUF
147# define PIPE_BUF _POSIX_PIPE_BUF
148# else
149# define PIPE_BUF 512 /* is this ok? */
150# endif
151#endif
152
153#ifndef EWOULDBLOCK
154# define EWOULDBLOCK EAGAIN
155#endif
156
157#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
158/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
159off_t __syscall(quad_t number, ...);
160#endif
161
162#define IO_RBUF_CAPA_MIN 8192
163#define IO_CBUF_CAPA_MIN (128*1024)
164#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
165#define IO_WBUF_CAPA_MIN 8192
166
167#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
168
169/* define system APIs */
170#ifdef _WIN32
171#undef open
172#define open rb_w32_uopen
173#undef rename
174#define rename(f, t) rb_w32_urename((f), (t))
175#include "win32/file.h"
176#endif
177
184
185static VALUE rb_eEAGAINWaitReadable;
186static VALUE rb_eEAGAINWaitWritable;
187#if EAGAIN != EWOULDBLOCK
188static VALUE rb_eEWOULDBLOCKWaitReadable;
189static VALUE rb_eEWOULDBLOCKWaitWritable;
190#endif
191static VALUE rb_eEINPROGRESSWaitWritable;
192static VALUE rb_eEINPROGRESSWaitReadable;
193
195static VALUE orig_stdout, orig_stderr;
196
198VALUE rb_rs;
201
202static VALUE argf;
203
204static ID id_write, id_read, id_flush, id_readpartial, id_set_encoding, id_fileno;
205static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
206static VALUE sym_textmode, sym_binmode, sym_autoclose;
207static VALUE sym_SET, sym_CUR, sym_END;
208static VALUE sym_wait_readable, sym_wait_writable;
209#ifdef SEEK_DATA
210static VALUE sym_DATA;
211#endif
212#ifdef SEEK_HOLE
213static VALUE sym_HOLE;
214#endif
215
216static VALUE prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path);
217
218VALUE
219rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
220{
221 return rb_thread_io_blocking_call(io, function, argument, events);
222}
223
224VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
225{
226 return rb_io_blocking_region_wait(io, function, argument, 0);
227}
228
229struct argf {
230 VALUE filename, current_file;
231 long last_lineno; /* $. */
232 long lineno;
233 VALUE argv;
234 VALUE inplace;
235 struct rb_io_encoding encs;
236 int8_t init_p, next_p, binmode;
237};
238
239
240#if defined(__APPLE__) && \
241 (!defined(MAC_OS_VERSION_27_0) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_27_0))
242
243# if __has_attribute(availability) && __has_warning("-Wunguarded-availability-new")
244
246RBIMPL_WARNING_IGNORED(-Wunguarded-availability-new)
247
248# ifdef HAVE_DUP3
249static inline int (*rb_dup3(void))(int, int, int) {return &dup3;}
250# define dup3 rb_dup3()
251# endif
252
253# ifdef HAVE_PIPE2
254static inline int (*rb_pipe2(void))(int [2], int) {return &pipe2;}
255# define pipe2 rb_pipe2()
256# endif
257
259
260# else /* __API_AVAILABLE macro does nothing on gcc */
261
262# ifdef HAVE_DUP3
263__attribute__((weak)) int dup3(int, int, int);
264# endif
265# ifdef HAVE_PIPE2
266__attribute__((weak)) int pipe2(int [2], int);
267# endif
268
269# endif
270#endif /* __APPLE__ && < MAC_OS_X_VERSION_27_0 */
271
272static rb_atomic_t max_file_descriptor = NOFILE;
273void
275{
276 rb_atomic_t afd = (rb_atomic_t)fd;
277 rb_atomic_t max_fd = max_file_descriptor;
278 int err;
279
280 if (fd < 0 || afd <= max_fd)
281 return;
282
283#if defined(HAVE_FCNTL) && defined(F_GETFL)
284 err = fcntl(fd, F_GETFL) == -1;
285#else
286 {
287 struct stat buf;
288 err = fstat(fd, &buf) != 0;
289 }
290#endif
291 if (err && errno == EBADF) {
292 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
293 }
294
295 while (max_fd < afd) {
296 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
297 }
298}
299
300void
301rb_maygvl_fd_fix_cloexec(int fd)
302{
303 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
304#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
305 int flags, flags2, ret;
306 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
307 if (flags == -1) {
308 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
309 }
310 if (fd <= 2)
311 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
312 else
313 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
314 if (flags != flags2) {
315 ret = fcntl(fd, F_SETFD, flags2);
316 if (ret != 0) {
317 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
318 }
319 }
320#endif
321}
322
323void
325{
326 rb_maygvl_fd_fix_cloexec(fd);
328}
329
330static inline bool
331io_again_p(int e)
332{
333 return (e == EWOULDBLOCK) || (e == EAGAIN);
334}
335
336int
337rb_cloexec_open(const char *pathname, int flags, mode_t mode)
338{
339 int ret;
340
341 static const int retry_interval = 0;
342 static const int retry_max_count = 10000;
343
344 int retry_count = 0;
345
346#ifdef O_CLOEXEC
347 flags |= O_CLOEXEC;
348#elif defined O_NOINHERIT
349 flags |= O_NOINHERIT;
350#endif
351
352 while ((ret = open(pathname, flags, mode)) == -1) {
353 int e = errno;
354 if (!io_again_p(e)) break;
355 if (retry_count++ >= retry_max_count) break;
356
357 sleep(retry_interval);
358 }
359
360 if (ret < 0) return ret;
361#ifdef O_CLOEXEC
362 if (ret > 2) return ret;
363#endif
364 rb_maygvl_fd_fix_cloexec(ret);
365 return ret;
366}
367
368int
370{
371 /* Don't allocate standard file descriptors: 0, 1, 2 */
372 return rb_cloexec_fcntl_dupfd(oldfd, 3);
373}
374
375int
376rb_cloexec_dup2(int oldfd, int newfd)
377{
378 int ret;
379
380 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
381 * rb_cloexec_dup2 succeeds as dup2. */
382 if (oldfd == newfd) {
383 ret = newfd;
384 }
385 else {
386#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
387# if defined(__APPLE__)
388# define try_dup3 (dup3 != NULL)
389# define abandon_dup3() true
390# else
391 static bool try_dup3 = true;
392# define abandon_dup3() (errno != ENOSYS || !!(try_dup3 = false))
393# endif
394 if (newfd <= 2) {
395 /* pass stdin, stdout and stderr to children */
396 }
397 else if (try_dup3) {
398 ret = dup3(oldfd, newfd, O_CLOEXEC);
399 /* dup3 is available since:
400 * - Linux 2.6.27, glibc 2.9
401 * - macOS 27.0
402 */
403 if (ret != -1)
404 return ret;
405 if (abandon_dup3()) return ret;
406 }
407#endif
408 ret = dup2(oldfd, newfd);
409 if (ret < 0) return ret;
410 }
411 rb_maygvl_fd_fix_cloexec(ret);
412 return ret;
413}
414
415static int
416rb_fd_set_nonblock(int fd)
417{
418#ifdef _WIN32
419 return rb_w32_set_nonblock(fd);
420#elif defined(F_GETFL)
421 int oflags = fcntl(fd, F_GETFL);
422
423 if (oflags == -1)
424 return -1;
425 if (oflags & O_NONBLOCK)
426 return 0;
427 oflags |= O_NONBLOCK;
428 return fcntl(fd, F_SETFL, oflags);
429#endif
430 return 0;
431}
432
433static inline int
434cloexec_pipe(int descriptors[2], int flags, bool force_cloexec)
435{
436 int result = -1;
437#ifdef HAVE_PIPE2
438# if defined(__APPLE__)
439# define try_pipe2 (pipe2 != NULL)
440# define abandon_pipe2() true
441# else
442 static bool try_pipe2 = true;
443# define abandon_pipe2() (errno != ENOSYS || !!(try_pipe2 = false))
444# endif
445 if (try_pipe2) {
446 result = pipe2(descriptors, O_CLOEXEC | flags);
447 if (result == 0) return result;
448 if (abandon_pipe2()) return result;
449 }
450#endif
451 if (result < 0 && (result = pipe(descriptors)) < 0)
452 return result;
453
454#ifdef __CYGWIN__
455 if (result == 0 && descriptors[1] == -1) {
456 close(descriptors[0]);
457 descriptors[0] = -1;
458 errno = ENFILE;
459 return -1;
460 }
461#endif
462
463 if (!force_cloexec) return result;
464
465 /* no pipe2 or fallenback to dup */
466 rb_maygvl_fd_fix_cloexec(descriptors[0]);
467 rb_maygvl_fd_fix_cloexec(descriptors[1]);
468
469#ifndef _WIN32
470 rb_fd_set_nonblock(descriptors[0]);
471 rb_fd_set_nonblock(descriptors[1]);
472#endif
473
474 return result;
475}
476
477int
478rb_cloexec_pipe(int descriptors[2])
479{
480 return cloexec_pipe(descriptors, O_NONBLOCK, true);
481}
482
483int
484rb_cloexec_fcntl_dupfd(int fd, int minfd)
485{
486 int ret;
487
488#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC)
489 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
490 if (ret > 2) return ret;
491#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
492 ret = fcntl(fd, F_DUPFD, minfd);
493#else
494 ret = dup(fd);
495 if (ret >= 0 && ret < minfd) {
496 const int prev_fd = ret;
497 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
498 close(prev_fd);
499 }
500 return ret;
501#endif
502 if (ret < 0) return ret;
503 rb_maygvl_fd_fix_cloexec(ret);
504 return ret;
505}
506
507#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
508#define ARGF argf_of(argf)
509#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
510
511#define GetWriteIO(io) rb_io_get_write_io(io)
512
513#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
514#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
515#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
516#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
517
518#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
519#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
520#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
521
522#if defined(_WIN32)
523#define WAIT_FD_IN_WIN32(fptr) \
524 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
525#else
526#define WAIT_FD_IN_WIN32(fptr)
527#endif
528
529#define READ_CHECK(fptr) do {\
530 if (!READ_DATA_PENDING(fptr)) {\
531 WAIT_FD_IN_WIN32(fptr);\
532 rb_io_check_closed(fptr);\
533 }\
534} while(0)
535
536#ifndef S_ISSOCK
537# ifdef _S_ISSOCK
538# define S_ISSOCK(m) _S_ISSOCK(m)
539# else
540# ifdef _S_IFSOCK
541# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
542# else
543# ifdef S_IFSOCK
544# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
545# endif
546# endif
547# endif
548#endif
549
550static int io_fflush(rb_io_t *);
551static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
552static void clear_readconv(rb_io_t *fptr);
553static void clear_codeconv(rb_io_t *fptr);
554
555#define FMODE_SIGNAL_ON_EPIPE (1<<17)
556
557#define fptr_signal_on_epipe(fptr) \
558 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
559
560#define fptr_set_signal_on_epipe(fptr, flag) \
561 ((flag) ? \
562 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
563 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
564
565extern ID ruby_static_id_signo;
566
567NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
568static void
569rb_sys_fail_on_write(rb_io_t *fptr)
570{
571 int e = errno;
572 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
573#if defined EPIPE
574 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
575 const VALUE sig =
576# if defined SIGPIPE
577 INT2FIX(SIGPIPE) - INT2FIX(0) +
578# endif
579 INT2FIX(0);
580 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
581 }
582#endif
583 rb_exc_raise(errinfo);
584}
585
586#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
587#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
588#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
589# define RUBY_CRLF_ENVIRONMENT 1
590#else
591# define RUBY_CRLF_ENVIRONMENT 0
592#endif
593
594#if RUBY_CRLF_ENVIRONMENT
595/* Windows */
596# define DEFAULT_TEXTMODE FMODE_TEXTMODE
597# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
598/*
599 * CRLF newline is set as default newline decorator.
600 * If only CRLF newline conversion is needed, we use binary IO process
601 * with OS's text mode for IO performance improvement.
602 * If encoding conversion is needed or a user sets text mode, we use encoding
603 * conversion IO process and universal newline decorator by default.
604 */
605#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
606#define WRITECONV_MASK ( \
607 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
608 ECONV_STATEFUL_DECORATOR_MASK|\
609 0)
610#define NEED_WRITECONV(fptr) ( \
611 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
612 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
613 0)
614#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
615
616#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
617 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
618 if (((fptr)->mode & FMODE_READABLE) &&\
619 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
620 setmode((fptr)->fd, O_BINARY);\
621 }\
622 else {\
623 setmode((fptr)->fd, O_TEXT);\
624 }\
625 }\
626} while(0)
627
628#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
629 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
630 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
631 }\
632} while(0)
633
634/*
635 * IO unread with taking care of removed '\r' in text mode.
636 */
637static void
638io_unread(rb_io_t *fptr, bool discard_rbuf)
639{
640 rb_off_t r, pos;
641 ssize_t read_size;
642 long i;
643 long newlines = 0;
644 long extra_max;
645 char *p;
646 char *buf;
647
648 rb_io_check_closed(fptr);
649 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
650 return;
651 }
652
653 errno = 0;
654 if (!rb_w32_fd_is_text(fptr->fd)) {
655 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
656 if (r < 0 && errno) {
657 if (errno == ESPIPE)
658 fptr->mode |= FMODE_DUPLEX;
659 if (!discard_rbuf) return;
660 }
661
662 goto end;
663 }
664
665 pos = lseek(fptr->fd, 0, SEEK_CUR);
666 if (pos < 0 && errno) {
667 if (errno == ESPIPE)
668 fptr->mode |= FMODE_DUPLEX;
669 if (!discard_rbuf) goto end;
670 }
671
672 /* add extra offset for removed '\r' in rbuf */
673 extra_max = (long)(pos - fptr->rbuf.len);
674 p = fptr->rbuf.ptr + fptr->rbuf.off;
675
676 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
677 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
678 newlines++;
679 }
680
681 for (i = 0; i < fptr->rbuf.len; i++) {
682 if (*p == '\n') newlines++;
683 if (extra_max == newlines) break;
684 p++;
685 }
686
687 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
688 while (newlines >= 0) {
689 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
690 if (newlines == 0) break;
691 if (r < 0) {
692 newlines--;
693 continue;
694 }
695 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
696 if (read_size < 0) {
697 int e = errno;
698 free(buf);
699 rb_syserr_fail_path(e, fptr->pathv);
700 }
701 if (read_size == fptr->rbuf.len) {
702 lseek(fptr->fd, r, SEEK_SET);
703 break;
704 }
705 else {
706 newlines--;
707 }
708 }
709 free(buf);
710 end:
711 fptr->rbuf.off = 0;
712 fptr->rbuf.len = 0;
713 clear_codeconv(fptr);
714 return;
715}
716
717/*
718 * We use io_seek to back cursor position when changing mode from text to binary,
719 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
720 * conversion for working properly with mode change.
721 *
722 * Return previous translation mode.
723 */
724static inline int
725set_binary_mode_with_seek_cur(rb_io_t *fptr)
726{
727 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
728
729 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
730 return setmode(fptr->fd, O_BINARY);
731 }
732 flush_before_seek(fptr, false);
733 return setmode(fptr->fd, O_BINARY);
734}
735#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
736
737#else
738/* Unix */
739# define DEFAULT_TEXTMODE 0
740#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
741#define NEED_WRITECONV(fptr) ( \
742 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
743 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
744 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
745 0)
746#define SET_BINARY_MODE(fptr) (void)(fptr)
747#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
748#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
749#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
750#endif
751
752#if !defined HAVE_SHUTDOWN && !defined shutdown
753#define shutdown(a,b) 0
754#endif
755
756#if defined(_WIN32)
757#define is_socket(fd, path) rb_w32_is_socket(fd)
758#elif !defined(S_ISSOCK)
759#define is_socket(fd, path) 0
760#else
761static int
762is_socket(int fd, VALUE path)
763{
764 struct stat sbuf;
765 if (fstat(fd, &sbuf) < 0)
766 rb_sys_fail_path(path);
767 return S_ISSOCK(sbuf.st_mode);
768}
769#endif
770
771static const char closed_stream[] = "closed stream";
772
773static void
774io_fd_check_closed(int fd)
775{
776 if (fd < 0) {
777 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
778 rb_raise(rb_eIOError, closed_stream);
779 }
780}
781
782void
783rb_eof_error(void)
784{
785 rb_raise(rb_eEOFError, "end of file reached");
786}
787
788VALUE
790{
791 rb_check_frozen(io);
792 return io;
793}
794
795void
797{
798 if (!fptr) {
799 rb_raise(rb_eIOError, "uninitialized stream");
800 }
801}
802
803void
805{
807 io_fd_check_closed(fptr->fd);
808}
809
810static rb_io_t *
811rb_io_get_fptr(VALUE io)
812{
813 rb_io_t *fptr = RFILE(io)->fptr;
815 return fptr;
816}
817
818VALUE
820{
821 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
822}
823
824VALUE
826{
827 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
828}
829
830VALUE
832{
833 VALUE write_io;
834 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
835 if (write_io) {
836 return write_io;
837 }
838 return io;
839}
840
841VALUE
843{
844 VALUE write_io;
845 rb_io_t *fptr = rb_io_get_fptr(io);
846 if (!RTEST(w)) {
847 w = 0;
848 }
849 else {
850 GetWriteIO(w);
851 }
852 write_io = fptr->tied_io_for_writing;
853 fptr->tied_io_for_writing = w;
854 return write_io ? write_io : Qnil;
855}
856
857/*
858 * call-seq:
859 * timeout -> duration or nil
860 *
861 * Get the internal timeout duration or nil if it was not set.
862 *
863 */
864VALUE
866{
867 rb_io_t *fptr = rb_io_get_fptr(self);
868
869 return fptr->timeout;
870}
871
872/*
873 * call-seq:
874 * timeout = duration -> duration
875 * timeout = nil -> nil
876 *
877 * Sets the internal timeout to the specified duration or nil. The timeout
878 * applies to all blocking operations where possible.
879 *
880 * When the operation performs longer than the timeout set, IO::TimeoutError
881 * is raised.
882 *
883 * This affects the following methods (but is not limited to): #gets, #puts,
884 * #read, #write, #wait_readable and #wait_writable. This also affects
885 * blocking socket operations like Socket#accept and Socket#connect.
886 *
887 * Some operations like File#open and IO#close are not affected by the
888 * timeout. A timeout during a write operation may leave the IO in an
889 * inconsistent state, e.g. data was partially written. Generally speaking, a
890 * timeout is a last ditch effort to prevent an application from hanging on
891 * slow I/O operations, such as those that occur during a slowloris attack.
892 */
893VALUE
895{
896 // Validate it:
897 if (RTEST(timeout)) {
898 rb_time_interval(timeout);
899 }
900
901 rb_io_t *fptr = rb_io_get_fptr(self);
902
903 RB_OBJ_WRITE(self, &fptr->timeout, timeout);
904
905 return self;
906}
907
908/*
909 * call-seq:
910 * IO.try_convert(object) -> new_io or nil
911 *
912 * Attempts to convert +object+ into an \IO object via method +to_io+;
913 * returns the new \IO object if successful, or +nil+ otherwise:
914 *
915 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
916 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
917 * IO.try_convert('STDOUT') # => nil
918 *
919 */
920static VALUE
921rb_io_s_try_convert(VALUE dummy, VALUE io)
922{
923 return rb_io_check_io(io);
924}
925
926#if !RUBY_CRLF_ENVIRONMENT
927static void
928io_unread(rb_io_t *fptr, bool discard_rbuf)
929{
930 rb_off_t r;
931 rb_io_check_closed(fptr);
932 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
933 return;
934 /* xxx: target position may be negative if buffer is filled by ungetc */
935 errno = 0;
936 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
937 if (r < 0 && errno) {
938 if (errno == ESPIPE)
939 fptr->mode |= FMODE_DUPLEX;
940 if (!discard_rbuf) return;
941 }
942 fptr->rbuf.off = 0;
943 fptr->rbuf.len = 0;
944 clear_codeconv(fptr);
945 return;
946}
947#endif
948
949static rb_encoding *io_input_encoding(rb_io_t *fptr);
950
951static void
952io_ungetbyte(VALUE str, rb_io_t *fptr)
953{
954 rb_len_t len = RSTRING_LEN(str);
955
956 if (fptr->rbuf.ptr == NULL) {
957 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
958 fptr->rbuf.off = 0;
959 fptr->rbuf.len = 0;
960#if SIZEOF_RB_LEN_T > SIZEOF_INT
961 if (len > INT_MAX)
962 rb_raise(rb_eIOError, "ungetbyte failed");
963#endif
964 if (len > min_capa)
965 fptr->rbuf.capa = (int)len;
966 else
967 fptr->rbuf.capa = min_capa;
968 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
969 }
970 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
971 rb_raise(rb_eIOError, "ungetbyte failed");
972 }
973 if (fptr->rbuf.off < len) {
974 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
975 fptr->rbuf.ptr+fptr->rbuf.off,
976 char, fptr->rbuf.len);
977 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
978 }
979 fptr->rbuf.off-=(int)len;
980 fptr->rbuf.len+=(int)len;
981 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
982}
983
984static void
985io_restore_read_buffer(VALUE str, rb_io_t *fptr)
986{
987 rb_len_t len = RSTRING_LEN(str);
988
989 if (len > INT_MAX - fptr->rbuf.len) {
990 rb_raise(rb_eIOError, "read buffer too large");
991 }
992 if (fptr->rbuf.ptr == NULL || fptr->rbuf.capa >= len + fptr->rbuf.len) {
993 io_ungetbyte(str, fptr);
994 }
995 else {
996 int pending = fptr->rbuf.len;
997 int capa = (int)len + pending;
998 char *ptr = ALLOC_N(char, capa);
999
1000 MEMMOVE(ptr, RSTRING_PTR(str), char, len);
1001 MEMMOVE(ptr + len, fptr->rbuf.ptr + fptr->rbuf.off, char, pending);
1002 ruby_xfree(fptr->rbuf.ptr);
1003 fptr->rbuf.ptr = ptr;
1004 fptr->rbuf.off = 0;
1005 fptr->rbuf.len = capa;
1006 fptr->rbuf.capa = capa;
1007 }
1008}
1009
1010static rb_io_t *
1011flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
1012{
1013 if (io_fflush(fptr) < 0)
1014 rb_sys_fail_on_write(fptr);
1015 io_unread(fptr, discard_rbuf);
1016 errno = 0;
1017 return fptr;
1018}
1019
1020#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
1021#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1022
1023#ifndef SEEK_CUR
1024# define SEEK_SET 0
1025# define SEEK_CUR 1
1026# define SEEK_END 2
1027#endif
1028
1029void
1031{
1032 rb_io_check_closed(fptr);
1033 if (!(fptr->mode & FMODE_READABLE)) {
1034 rb_raise(rb_eIOError, "not opened for reading");
1035 }
1036 if (fptr->wbuf.len) {
1037 if (io_fflush(fptr) < 0)
1038 rb_sys_fail_on_write(fptr);
1039 }
1040 if (fptr->tied_io_for_writing) {
1041 rb_io_t *wfptr;
1042 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1043 if (io_fflush(wfptr) < 0)
1044 rb_sys_fail_on_write(wfptr);
1045 }
1046}
1047
1048void
1050{
1052 if (READ_CHAR_PENDING(fptr)) {
1053 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1054 }
1055}
1056
1057void
1062
1063static rb_encoding*
1064io_read_encoding(rb_io_t *fptr)
1065{
1066 if (fptr->encs.enc) {
1067 return fptr->encs.enc;
1068 }
1069 return rb_default_external_encoding();
1070}
1071
1072static rb_encoding*
1073io_input_encoding(rb_io_t *fptr)
1074{
1075 if (fptr->encs.enc2) {
1076 return fptr->encs.enc2;
1077 }
1078 return io_read_encoding(fptr);
1079}
1080
1081void
1083{
1084 rb_io_check_closed(fptr);
1085 if (!(fptr->mode & FMODE_WRITABLE)) {
1086 rb_raise(rb_eIOError, "not opened for writing");
1087 }
1088 if (fptr->rbuf.len) {
1089 io_unread(fptr, true);
1090 }
1091}
1092
1093int
1094rb_io_read_pending(rb_io_t *fptr)
1095{
1096 /* This function is used for bytes and chars. Confusing. */
1097 if (READ_CHAR_PENDING(fptr))
1098 return 1; /* should raise? */
1099 return READ_DATA_PENDING(fptr);
1100}
1101
1102void
1104{
1105 if (!READ_DATA_PENDING(fptr)) {
1106 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1107 }
1108 return;
1109}
1110
1111int
1112rb_gc_for_fd(int err)
1113{
1114 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1115 rb_gc();
1116 return 1;
1117 }
1118 return 0;
1119}
1120
1121/* try `expr` upto twice while it returns false and `errno`
1122 * is to GC. Each `errno`s are available as `first_errno` and
1123 * `retried_errno` respectively */
1124#define TRY_WITH_GC(expr) \
1125 for (int first_errno, retried_errno = 0, retried = 0; \
1126 (!retried && \
1127 !(expr) && \
1128 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1129 (retried_errno = errno, 1)); \
1130 (void)retried_errno, retried = 1)
1131
1132static int
1133ruby_dup(int orig)
1134{
1135 int fd = -1;
1136
1137 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1138 rb_syserr_fail(first_errno, 0);
1139 }
1140 rb_update_max_fd(fd);
1141 return fd;
1142}
1143
1144static VALUE
1145io_alloc(VALUE klass)
1146{
1147 UNPROTECTED_NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile));
1148
1149 io->fptr = 0;
1150
1151 return (VALUE)io;
1152}
1153
1154#ifndef S_ISREG
1155# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1156#endif
1157
1159 VALUE th;
1160 rb_io_t *fptr;
1161 int nonblock;
1162 int fd;
1163
1164 void *buf;
1165 size_t capa;
1166 struct timeval *timeout;
1167};
1168
1170 VALUE th;
1171 rb_io_t *fptr;
1172 int nonblock;
1173 int fd;
1174
1175 const void *buf;
1176 size_t capa;
1177 struct timeval *timeout;
1178};
1179
1180#ifdef HAVE_WRITEV
1181struct io_internal_writev_struct {
1182 VALUE th;
1183 rb_io_t *fptr;
1184 int nonblock;
1185 int fd;
1186
1187 int iovcnt;
1188 const struct iovec *iov;
1189 struct timeval *timeout;
1190};
1191#endif
1192
1193static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1194
1200static inline int
1201io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1202{
1203 if (!timeout && rb_thread_mn_schedulable(thread)) {
1204 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1205 return -1;
1206 }
1207
1208 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1209
1210 if (ready > 0) {
1211 return ready;
1212 }
1213 else if (ready == 0) {
1214 errno = ETIMEDOUT;
1215 return -1;
1216 }
1217
1218 // If there was an error BEFORE we started waiting, return it:
1219 if (error) {
1220 errno = error;
1221 return -1;
1222 }
1223 else {
1224 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1225 return ready;
1226 }
1227}
1228
1229static VALUE
1230internal_read_func(void *ptr)
1231{
1232 struct io_internal_read_struct *iis = ptr;
1233 ssize_t result;
1234
1235 if (iis->timeout && !iis->nonblock) {
1236 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1237 return -1;
1238 }
1239 }
1240
1241 retry:
1242 result = read(iis->fd, iis->buf, iis->capa);
1243
1244 if (result < 0 && !iis->nonblock) {
1245 if (io_again_p(errno)) {
1246 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1247 return -1;
1248 }
1249 else {
1250 goto retry;
1251 }
1252 }
1253 }
1254
1255 return result;
1256}
1257
1258#if defined __APPLE__
1259# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1260#else
1261# define do_write_retry(code) result = code
1262#endif
1263
1264static VALUE
1265internal_write_func(void *ptr)
1266{
1267 struct io_internal_write_struct *iis = ptr;
1268 ssize_t result;
1269
1270 if (iis->timeout && !iis->nonblock) {
1271 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1272 return -1;
1273 }
1274 }
1275
1276 retry:
1277 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1278
1279 if (result < 0 && !iis->nonblock) {
1280 int e = errno;
1281 if (io_again_p(e)) {
1282 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1283 return -1;
1284 }
1285 else {
1286 goto retry;
1287 }
1288 }
1289 }
1290
1291 return result;
1292}
1293
1294#ifdef HAVE_WRITEV
1295static VALUE
1296internal_writev_func(void *ptr)
1297{
1298 struct io_internal_writev_struct *iis = ptr;
1299 ssize_t result;
1300
1301 if (iis->timeout && !iis->nonblock) {
1302 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1303 return -1;
1304 }
1305 }
1306
1307 retry:
1308 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1309
1310 if (result < 0 && !iis->nonblock) {
1311 if (io_again_p(errno)) {
1312 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1313 return -1;
1314 }
1315 else {
1316 goto retry;
1317 }
1318 }
1319 }
1320
1321 return result;
1322}
1323#endif
1324
1325static ssize_t
1326rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1327{
1328 rb_thread_t *th = GET_THREAD();
1330 if (scheduler != Qnil) {
1331 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count);
1332
1333 if (!UNDEF_P(result)) {
1335 }
1336 }
1337
1338 struct io_internal_read_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_read_func, &iis, RUBY_IO_READABLE);
1357}
1358
1359static ssize_t
1360rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1361{
1362 rb_thread_t *th = GET_THREAD();
1364 if (scheduler != Qnil) {
1365 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count);
1366
1367 if (!UNDEF_P(result)) {
1369 }
1370 }
1371
1372 struct io_internal_write_struct iis = {
1373 .th = th->self,
1374 .fptr = fptr,
1375 .nonblock = 0,
1376 .fd = fptr->fd,
1377
1378 .buf = buf,
1379 .capa = count,
1380 .timeout = NULL
1381 };
1382
1383 struct timeval timeout_storage;
1384
1385 if (fptr->timeout != Qnil) {
1386 timeout_storage = rb_time_interval(fptr->timeout);
1387 iis.timeout = &timeout_storage;
1388 }
1389
1390 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1391}
1392
1393#ifdef HAVE_WRITEV
1394static ssize_t
1395rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1396{
1397 if (!iovcnt) return 0;
1398
1399 rb_thread_t *th = GET_THREAD();
1400
1402 if (scheduler != Qnil) {
1403 // This path assumes at least one `iov`:
1404 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len);
1405
1406 if (!UNDEF_P(result)) {
1408 }
1409 }
1410
1411 struct io_internal_writev_struct iis = {
1412 .th = th->self,
1413 .fptr = fptr,
1414 .nonblock = 0,
1415 .fd = fptr->fd,
1416
1417 .iov = iov,
1418 .iovcnt = iovcnt,
1419 .timeout = NULL
1420 };
1421
1422 struct timeval timeout_storage;
1423
1424 if (fptr->timeout != Qnil) {
1425 timeout_storage = rb_time_interval(fptr->timeout);
1426 iis.timeout = &timeout_storage;
1427 }
1428
1429 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1430}
1431#endif
1432
1433static VALUE
1434io_flush_buffer_sync(void *arg)
1435{
1436 rb_io_t *fptr = arg;
1437 rb_len_t l = fptr->wbuf.len;
1438 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1439
1440 if (fptr->wbuf.len <= r) {
1441 fptr->wbuf.off = 0;
1442 fptr->wbuf.len = 0;
1443 return 0;
1444 }
1445
1446 if (0 <= r) {
1447 fptr->wbuf.off += (int)r;
1448 fptr->wbuf.len -= (int)r;
1449 errno = EAGAIN;
1450 }
1451
1452 return (VALUE)-1;
1453}
1454
1455static inline VALUE
1456io_flush_buffer_fiber_scheduler(VALUE scheduler, rb_io_t *fptr)
1457{
1458 VALUE ret = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, fptr->wbuf.ptr+fptr->wbuf.off, fptr->wbuf.len);
1459 if (!UNDEF_P(ret)) {
1460 ssize_t result = rb_fiber_scheduler_io_result_apply(ret);
1461 if (result > 0) {
1462 fptr->wbuf.off += result;
1463 fptr->wbuf.len -= result;
1464 }
1465 return result >= 0 ? (VALUE)0 : (VALUE)-1;
1466 }
1467 return ret;
1468}
1469
1470static VALUE
1471io_flush_buffer_async(VALUE arg)
1472{
1473 rb_io_t *fptr = (rb_io_t *)arg;
1474
1475 VALUE scheduler = rb_fiber_scheduler_current();
1476 if (scheduler != Qnil) {
1477 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1478 if (!UNDEF_P(result)) {
1479 return result;
1480 }
1481 }
1482
1483 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1484}
1485
1486static inline int
1487io_flush_buffer(rb_io_t *fptr)
1488{
1489 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1490 return (int)io_flush_buffer_async((VALUE)fptr);
1491 }
1492 else {
1493 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1494 }
1495}
1496
1497static int
1498io_fflush(rb_io_t *fptr)
1499{
1500 rb_io_check_closed(fptr);
1501
1502 if (fptr->wbuf.len == 0)
1503 return 0;
1504
1505 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1506 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1507 return -1;
1508
1509 rb_io_check_closed(fptr);
1510 }
1511
1512 return 0;
1513}
1514
1515VALUE
1516rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1517{
1518 rb_thread_t *th = GET_THREAD();
1520
1521 if (scheduler != Qnil) {
1522 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1523 }
1524
1525 rb_io_t * fptr = NULL;
1526 RB_IO_POINTER(io, fptr);
1527
1528 struct timeval tv_storage;
1529 struct timeval *tv = NULL;
1530
1531 if (NIL_OR_UNDEF_P(timeout)) {
1532 timeout = fptr->timeout;
1533 }
1534
1535 if (timeout != Qnil) {
1536 tv_storage = rb_time_interval(timeout);
1537 tv = &tv_storage;
1538 }
1539
1540 int ready = rb_thread_io_wait(th, fptr, RB_NUM2INT(events), tv);
1541
1542 if (ready < 0) {
1543 rb_sys_fail(0);
1544 }
1545
1546 // Not sure if this is necessary:
1547 rb_io_check_closed(fptr);
1548
1549 if (ready) {
1550 return RB_INT2NUM(ready);
1551 }
1552 else {
1553 return Qfalse;
1554 }
1555}
1556
1557static VALUE
1558io_from_fd(int fd)
1559{
1560 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1561}
1562
1563static int
1564io_wait_for_single_fd(int fd, int events, struct timeval *timeout, rb_thread_t *th, VALUE scheduler)
1565{
1566 if (scheduler != Qnil) {
1567 return RTEST(
1568 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1569 );
1570 }
1571
1572 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1573}
1574
1575int
1577{
1578 io_fd_check_closed(f);
1579
1580 rb_thread_t *th = GET_THREAD();
1582
1583 switch (errno) {
1584 case EINTR:
1585#if defined(ERESTART)
1586 case ERESTART:
1587#endif
1589 return TRUE;
1590
1591 case EAGAIN:
1592#if EWOULDBLOCK != EAGAIN
1593 case EWOULDBLOCK:
1594#endif
1595 if (scheduler != Qnil) {
1596 return RTEST(
1597 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1598 );
1599 }
1600 else {
1601 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL, th, scheduler);
1602 }
1603 return TRUE;
1604
1605 default:
1606 return FALSE;
1607 }
1608}
1609
1610int
1612{
1613 io_fd_check_closed(f);
1614
1615 rb_thread_t *th = GET_THREAD();
1617
1618 switch (errno) {
1619 case EINTR:
1620#if defined(ERESTART)
1621 case ERESTART:
1622#endif
1623 /*
1624 * In old Linux, several special files under /proc and /sys don't handle
1625 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1626 * Otherwise, we face nasty hang up. Sigh.
1627 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1628 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1629 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1630 * Then rb_thread_check_ints() is enough.
1631 */
1633 return TRUE;
1634
1635 case EAGAIN:
1636#if EWOULDBLOCK != EAGAIN
1637 case EWOULDBLOCK:
1638#endif
1639 if (scheduler != Qnil) {
1640 return RTEST(
1641 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1642 );
1643 }
1644 else {
1645 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL, th, scheduler);
1646 }
1647 return TRUE;
1648
1649 default:
1650 return FALSE;
1651 }
1652}
1653
1654int
1655rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1656{
1657 rb_thread_t *th = GET_THREAD();
1659 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1660}
1661
1662int
1664{
1665 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1666}
1667
1668int
1670{
1671 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1672}
1673
1674VALUE
1675rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1676{
1677 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1678 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1679 // instead relies on `read(-1) -> -1` which causes this code path. We then
1680 // check here whether the IO was in fact closed. Probably it's better to
1681 // check that `fptr->fd != -1` before using it in syscall.
1682 rb_io_check_closed(RFILE(io)->fptr);
1683
1684 switch (error) {
1685 // In old Linux, several special files under /proc and /sys don't handle
1686 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1687 // Otherwise, we face nasty hang up. Sigh.
1688 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1689 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1690 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1691 // Then rb_thread_check_ints() is enough.
1692 case EINTR:
1693#if defined(ERESTART)
1694 case ERESTART:
1695#endif
1696 // We might have pending interrupts since the previous syscall was interrupted:
1698
1699 // The operation was interrupted, so retry it immediately:
1700 return events;
1701
1702 case EAGAIN:
1703#if EWOULDBLOCK != EAGAIN
1704 case EWOULDBLOCK:
1705#endif
1706 {
1707 // The operation would block, so wait for the specified events:
1708 VALUE result = rb_io_wait(io, events, timeout);
1709 // The scheduler may change errno while waiting. Preserve the original
1710 // error in case no events are ready and the caller reports the failure.
1711 errno = error;
1712 return result;
1713 }
1714
1715 default:
1716 // Non-specific error, no event is ready:
1717 return Qnil;
1718 }
1719}
1720
1721int
1723{
1724 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1725
1726 if (RTEST(result)) {
1727 return RB_NUM2INT(result);
1728 }
1729 else if (result == RUBY_Qfalse) {
1730 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1731 }
1732
1733 return 0;
1734}
1735
1736int
1738{
1739 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1740
1741 if (RTEST(result)) {
1742 return RB_NUM2INT(result);
1743 }
1744 else if (result == RUBY_Qfalse) {
1745 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1746 }
1747
1748 return 0;
1749}
1750
1751static void
1752make_writeconv(rb_io_t *fptr)
1753{
1754 if (!fptr->writeconv_initialized) {
1755 const char *senc, *denc;
1756 rb_encoding *enc;
1757 int ecflags;
1758 VALUE ecopts;
1759
1760 fptr->writeconv_initialized = 1;
1761
1762 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1763 ecopts = fptr->encs.ecopts;
1764
1765 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1766 /* no encoding conversion */
1767 fptr->writeconv_pre_ecflags = 0;
1768 fptr->writeconv_pre_ecopts = Qnil;
1769 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1770 if (!fptr->writeconv)
1771 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1773 }
1774 else {
1775 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1776 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1777 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1778 /* single conversion */
1779 fptr->writeconv_pre_ecflags = ecflags;
1780 fptr->writeconv_pre_ecopts = ecopts;
1781 fptr->writeconv = NULL;
1783 }
1784 else {
1785 /* double conversion */
1786 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1787 fptr->writeconv_pre_ecopts = ecopts;
1788 if (senc) {
1789 denc = rb_enc_name(enc);
1790 fptr->writeconv_asciicompat = rb_str_new2(senc);
1791 }
1792 else {
1793 senc = denc = "";
1794 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1795 }
1797 ecopts = fptr->encs.ecopts;
1798 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1799 if (!fptr->writeconv)
1800 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1801 }
1802 }
1803 }
1804}
1805
1806/* writing functions */
1808 rb_io_t *fptr;
1809 const char *ptr;
1810 rb_len_t length;
1811};
1812
1814 VALUE io;
1815 VALUE str;
1816 int nosync;
1817};
1818
1819#ifdef HAVE_WRITEV
1820static ssize_t
1821io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, rb_len_t length)
1822{
1823 if (fptr->wbuf.len) {
1824 struct iovec iov[2];
1825
1826 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1827 iov[0].iov_len = fptr->wbuf.len;
1828 iov[1].iov_base = (void*)ptr;
1829 iov[1].iov_len = length;
1830
1831 ssize_t result = rb_writev_internal(fptr, iov, 2);
1832
1833 if (result < 0)
1834 return result;
1835
1836 if (result >= fptr->wbuf.len) {
1837 // We wrote more than the internal buffer:
1838 result -= fptr->wbuf.len;
1839 fptr->wbuf.off = 0;
1840 fptr->wbuf.len = 0;
1841 }
1842 else {
1843 // We only wrote less data than the internal buffer:
1844 fptr->wbuf.off += (int)result;
1845 fptr->wbuf.len -= (int)result;
1846
1847 result = 0;
1848 }
1849
1850 return result;
1851 }
1852 else {
1853 return rb_io_write_memory(fptr, ptr, length);
1854 }
1855}
1856#else
1857static ssize_t
1858io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, rb_len_t length)
1859{
1860 rb_len_t remaining = length;
1861
1862 if (fptr->wbuf.len) {
1863 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1864 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1865 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1866 fptr->wbuf.off = 0;
1867 }
1868
1869 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1870 fptr->wbuf.len += (int)length;
1871
1872 // We copied the entire incoming data to the internal buffer:
1873 remaining = 0;
1874 }
1875
1876 // Flush the internal buffer:
1877 if (io_fflush(fptr) < 0) {
1878 return -1;
1879 }
1880
1881 // If all the data was buffered, we are done:
1882 if (remaining == 0) {
1883 return length;
1884 }
1885 }
1886
1887 // Otherwise, we should write the data directly:
1888 return rb_io_write_memory(fptr, ptr, length);
1889}
1890#endif
1891
1892static VALUE
1893io_binwrite_string(VALUE arg)
1894{
1895 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1896
1897 const char *ptr = p->ptr;
1898 size_t remaining = p->length;
1899
1900 while (remaining) {
1901 // Write as much as possible:
1902 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1903
1904 if (result == 0) {
1905 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1906 // should try again immediately.
1907 }
1908 else if (result > 0) {
1909 if ((size_t)result == remaining) break;
1910 ptr += result;
1911 remaining -= result;
1912 }
1913 // Wait for it to become writable:
1914 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1915 rb_io_check_closed(p->fptr);
1916 }
1917 else {
1918 // The error was unrelated to waiting for it to become writable, so we fail:
1919 return -1;
1920 }
1921 }
1922
1923 return p->length;
1924}
1925
1926inline static void
1927io_allocate_write_buffer(rb_io_t *fptr, int sync)
1928{
1929 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1930 fptr->wbuf.off = 0;
1931 fptr->wbuf.len = 0;
1932 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1933 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1934 }
1935
1936 if (NIL_P(fptr->write_lock)) {
1937 fptr->write_lock = rb_mutex_new();
1938 rb_mutex_allow_trap(fptr->write_lock, 1);
1939 }
1940}
1941
1942static inline int
1943io_binwrite_requires_flush_write(rb_io_t *fptr, rb_len_t len, int nosync)
1944{
1945 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1946 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1947 return 1;
1948
1949 // If the amount of data we want to write exceeds the internal buffer:
1950 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1951 return 1;
1952
1953 // Otherwise, we can append to the internal buffer:
1954 return 0;
1955}
1956
1957static rb_len_t
1958io_binwrite(const char *ptr, rb_len_t len, rb_io_t *fptr, int nosync)
1959{
1960 if (len <= 0) return len;
1961
1962 // Don't write anything if current thread has a pending interrupt:
1964
1965 io_allocate_write_buffer(fptr, !nosync);
1966
1967 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1968 struct binwrite_arg arg;
1969
1970 arg.fptr = fptr;
1971 arg.ptr = ptr;
1972 arg.length = len;
1973
1974 if (!NIL_P(fptr->write_lock)) {
1975 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1976 }
1977 else {
1978 return io_binwrite_string((VALUE)&arg);
1979 }
1980 }
1981 else {
1982 if (fptr->wbuf.off) {
1983 if (fptr->wbuf.len)
1984 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1985 fptr->wbuf.off = 0;
1986 }
1987
1988 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1989 fptr->wbuf.len += (int)len;
1990
1991 return len;
1992 }
1993}
1994
1995# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1996 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1997
1998#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1999 MODE_BTMODE(d, e, f) : \
2000 MODE_BTMODE(a, b, c))
2001
2002static VALUE
2003do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
2004{
2005 if (NEED_WRITECONV(fptr)) {
2006 VALUE common_encoding = Qnil;
2007 SET_BINARY_MODE(fptr);
2008
2009 make_writeconv(fptr);
2010
2011 if (fptr->writeconv) {
2012#define fmode (fptr->mode)
2013 if (!NIL_P(fptr->writeconv_asciicompat))
2014 common_encoding = fptr->writeconv_asciicompat;
2015 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
2016 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2017 rb_enc_name(rb_enc_get(str)));
2018 }
2019#undef fmode
2020 }
2021 else {
2022 if (fptr->encs.enc2)
2023 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
2024 else if (fptr->encs.enc != rb_ascii8bit_encoding())
2025 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
2026 }
2027
2028 if (!NIL_P(common_encoding)) {
2029 str = rb_str_encode(str, common_encoding,
2031 *converted = 1;
2032 }
2033
2034 if (fptr->writeconv) {
2036 *converted = 1;
2037 }
2038 }
2039#if RUBY_CRLF_ENVIRONMENT
2040#define fmode (fptr->mode)
2041 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2042 if ((fptr->mode & FMODE_READABLE) &&
2044 setmode(fptr->fd, O_BINARY);
2045 }
2046 else {
2047 setmode(fptr->fd, O_TEXT);
2048 }
2049 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2050 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2051 rb_enc_name(rb_enc_get(str)));
2052 }
2053 }
2054#undef fmode
2055#endif
2056 return str;
2057}
2058
2059static rb_len_t
2060io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
2061{
2062 int converted = 0;
2063 VALUE tmp;
2064 rb_len_t n, len;
2065 const char *ptr;
2066
2067#ifdef _WIN32
2068 if (fptr->mode & FMODE_TTY) {
2069 if (rb_w32_write_console(str, fptr->fd) > 0) return RSTRING_LEN(str);
2070 }
2071#endif
2072
2073 str = do_writeconv(str, fptr, &converted);
2074 if (converted)
2075 OBJ_FREEZE(str);
2076
2077 tmp = rb_str_no_gvl_safe_acquire(str);
2078 RSTRING_GETMEM(tmp, ptr, len);
2079 n = io_binwrite(ptr, len, fptr, nosync);
2081
2082 return n;
2083}
2084
2085ssize_t
2086rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2087{
2088 rb_io_t *fptr;
2089
2090 GetOpenFile(io, fptr);
2092 return (ssize_t)io_binwrite(buf, (rb_len_t)size, fptr, 0);
2093}
2094
2095static VALUE
2096io_write(VALUE io, VALUE str, int nosync)
2097{
2098 rb_io_t *fptr;
2099 rb_len_t n;
2100 VALUE tmp;
2101
2102 io = GetWriteIO(io);
2103 str = rb_obj_as_string(str);
2104 tmp = rb_io_check_io(io);
2105
2106 if (NIL_P(tmp)) {
2107 /* port is not IO, call write method for it. */
2108 return rb_funcall(io, id_write, 1, str);
2109 }
2110
2111 io = tmp;
2112 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2113
2114 GetOpenFile(io, fptr);
2116
2117 n = io_fwrite(str, fptr, nosync);
2118 if (n < 0L) rb_sys_fail_on_write(fptr);
2119
2120 return LEN2NUM(n);
2121}
2122
2123#ifdef HAVE_WRITEV
2124struct binwritev_arg {
2125 rb_io_t *fptr;
2126 struct iovec *iov;
2127 int iovcnt;
2128 size_t total;
2129};
2130
2131static VALUE
2132io_binwritev_internal(VALUE arg)
2133{
2134 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2135
2136 size_t remaining = p->total;
2137 size_t offset = 0;
2138
2139 rb_io_t *fptr = p->fptr;
2140 struct iovec *iov = p->iov;
2141 int iovcnt = p->iovcnt;
2142
2143 while (remaining) {
2144 rb_len_t result = rb_writev_internal(fptr, iov, iovcnt);
2145
2146 if (result >= 0) {
2147 offset += result;
2148 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2149 if (offset < (size_t)fptr->wbuf.len) {
2150 fptr->wbuf.off += result;
2151 fptr->wbuf.len -= result;
2152 }
2153 else {
2154 offset -= (size_t)fptr->wbuf.len;
2155 fptr->wbuf.off = 0;
2156 fptr->wbuf.len = 0;
2157 }
2158 }
2159
2160 if (offset == p->total) {
2161 return p->total;
2162 }
2163
2164 while (result >= (ssize_t)iov->iov_len) {
2165 /* iovcnt > 0 */
2166 result -= iov->iov_len;
2167 iov->iov_len = 0;
2168 iov++;
2169
2170 if (!--iovcnt) {
2171 // I don't believe this code path can ever occur.
2172 return offset;
2173 }
2174 }
2175
2176 iov->iov_base = (char *)iov->iov_base + result;
2177 iov->iov_len -= result;
2178 }
2179 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2180 rb_io_check_closed(fptr);
2181 }
2182 else {
2183 return -1;
2184 }
2185 }
2186
2187 return offset;
2188}
2189
2190static rb_len_t
2191io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2192{
2193 // Don't write anything if current thread has a pending interrupt:
2195
2196 if (iovcnt == 0) return 0;
2197
2198 size_t total = 0;
2199 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2200
2201 io_allocate_write_buffer(fptr, 1);
2202
2203 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2204 // The end of the buffered data:
2205 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2206
2207 if (offset + total <= (size_t)fptr->wbuf.capa) {
2208 for (int i = 1; i < iovcnt; i++) {
2209 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2210 offset += iov[i].iov_len;
2211 }
2212
2213 fptr->wbuf.len += total;
2214
2215 /* io_binwritev is only reached in sync/TTY mode (it is called only
2216 * from io_fwritev, which io_writev uses only when FMODE_SYNC or
2217 * FMODE_TTY is set), so the coalesced data must be flushed
2218 * immediately rather than left in the buffer until the next flush
2219 * or close. Otherwise a multi-argument write with many arguments
2220 * would not be observably atomic under sync. */
2221 if (io_fflush(fptr) < 0) return -1;
2222
2223 return total;
2224 }
2225 else {
2226 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2227 iov[0].iov_len = fptr->wbuf.len;
2228 }
2229 }
2230 else {
2231 // The first iov is reserved for the internal buffer, and it's empty.
2232 iov++;
2233
2234 if (!--iovcnt) {
2235 // If there are no other io vectors we are done.
2236 return 0;
2237 }
2238 }
2239
2240 struct binwritev_arg arg;
2241 arg.fptr = fptr;
2242 arg.iov = iov;
2243 arg.iovcnt = iovcnt;
2244 arg.total = total;
2245
2246 if (!NIL_P(fptr->write_lock)) {
2247 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2248 }
2249 else {
2250 return io_binwritev_internal((VALUE)&arg);
2251 }
2252}
2253
2254static rb_len_t
2255io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2256{
2257 int i, converted, iovcnt = argc + 1;
2258 rb_len_t n;
2259 VALUE v1, v2, str, tmp, *tmp_array;
2260 struct iovec *iov;
2261
2262 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2263 tmp_array = ALLOCV_N(VALUE, v2, argc);
2264
2265 for (i = 0; i < argc; i++) {
2266 str = rb_obj_as_string(argv[i]);
2267 converted = 0;
2268 str = do_writeconv(str, fptr, &converted);
2269
2270 if (converted)
2271 OBJ_FREEZE(str);
2272
2273 tmp = rb_str_tmp_frozen_acquire(str);
2274 tmp_array[i] = tmp;
2275
2276 /* iov[0] is reserved for buffer of fptr */
2277 iov[i+1].iov_base = RSTRING_PTR(tmp);
2278 iov[i+1].iov_len = RSTRING_LEN(tmp);
2279 }
2280
2281 n = io_binwritev(iov, iovcnt, fptr);
2282 if (v1) ALLOCV_END(v1);
2283
2284 for (i = 0; i < argc; i++) {
2285 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2286 }
2287
2288 if (v2) ALLOCV_END(v2);
2289
2290 return n;
2291}
2292
2293static int
2294iovcnt_ok(int iovcnt)
2295{
2296#ifdef IOV_MAX
2297 return iovcnt < IOV_MAX;
2298#else /* GNU/Hurd has writev, but no IOV_MAX */
2299 return 1;
2300#endif
2301}
2302#endif /* HAVE_WRITEV */
2303
2304static VALUE
2305io_writev(int argc, const VALUE *argv, VALUE io)
2306{
2307 rb_io_t *fptr;
2308 rb_len_t n;
2309 VALUE tmp, total = INT2FIX(0);
2310 int i, cnt = 1;
2311
2312 io = GetWriteIO(io);
2313 tmp = rb_io_check_io(io);
2314
2315 if (NIL_P(tmp)) {
2316 /* port is not IO, call write method for it. */
2317 return rb_funcallv(io, id_write, argc, argv);
2318 }
2319
2320 io = tmp;
2321
2322 GetOpenFile(io, fptr);
2324
2325 for (i = 0; i < argc; i += cnt) {
2326#ifdef HAVE_WRITEV
2327 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2328 n = io_fwritev(cnt, &argv[i], fptr);
2329 }
2330 else
2331#endif
2332 {
2333 cnt = 1;
2334 /* sync at last item */
2335 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2336 }
2337
2338 if (n < 0L)
2339 rb_sys_fail_on_write(fptr);
2340
2341 total = rb_int_plus(LEN2NUM(n), total);
2342 }
2343
2344 return total;
2345}
2346
2347/*
2348 * call-seq:
2349 * write(*objects) -> integer
2350 *
2351 * Writes each of the given +objects+ to +self+,
2352 * which must be opened for writing
2353 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2354 * returns the total number bytes written;
2355 * each of +objects+ that is not a string is converted via method +to_s+:
2356 *
2357 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2358 * $stdout.write('foo', :bar, 2, "\n") # => 8
2359 *
2360 * Output:
2361 *
2362 * Hello, World!
2363 * foobar2
2364 *
2365 * Related: IO#read.
2366 */
2367
2368static VALUE
2369io_write_m(int argc, VALUE *argv, VALUE io)
2370{
2371 if (argc != 1) {
2372 return io_writev(argc, argv, io);
2373 }
2374 else {
2375 VALUE str = argv[0];
2376 return io_write(io, str, 0);
2377 }
2378}
2379
2380VALUE
2381rb_io_write(VALUE io, VALUE str)
2382{
2383 return rb_funcallv(io, id_write, 1, &str);
2384}
2385
2386static VALUE
2387rb_io_writev(VALUE io, int argc, const VALUE *argv)
2388{
2389 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2390 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2391 VALUE klass = CLASS_OF(io);
2392 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2394 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2395 " which accepts just one argument",
2396 klass, sep
2397 );
2398 }
2399
2400 do rb_io_write(io, *argv++); while (--argc);
2401
2402 return Qnil;
2403 }
2404
2405 return rb_funcallv(io, id_write, argc, argv);
2406}
2407
2408/*
2409 * call-seq:
2410 * self << object -> self
2411 *
2412 * Writes the given +object+ to +self+,
2413 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2414 * returns +self+;
2415 * if +object+ is not a string, it is converted via method +to_s+:
2416 *
2417 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2418 * $stdout << 'foo' << :bar << 2 << "\n"
2419 *
2420 * Output:
2421 *
2422 * Hello, World!
2423 * foobar2
2424 *
2425 */
2426
2427
2428VALUE
2430{
2431 rb_io_write(io, str);
2432 return io;
2433}
2434
2435#ifdef HAVE_FSYNC
2436static VALUE
2437nogvl_fsync(void *ptr)
2438{
2439 rb_io_t *fptr = ptr;
2440
2441#ifdef _WIN32
2442 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2443 return 0;
2444#endif
2445 return (VALUE)fsync(fptr->fd);
2446}
2447#endif
2448
2449VALUE
2450rb_io_flush_raw(VALUE io, int sync)
2451{
2452 rb_io_t *fptr;
2453
2454 if (!RB_TYPE_P(io, T_FILE)) {
2455 return rb_funcall(io, id_flush, 0);
2456 }
2457
2458 io = GetWriteIO(io);
2459 GetOpenFile(io, fptr);
2460
2461 if (fptr->mode & FMODE_WRITABLE) {
2462 if (io_fflush(fptr) < 0)
2463 rb_sys_fail_on_write(fptr);
2464 }
2465 if (fptr->mode & FMODE_READABLE) {
2466 io_unread(fptr, true);
2467 }
2468
2469 return io;
2470}
2471
2472/*
2473 * call-seq:
2474 * flush -> self
2475 *
2476 * Flushes data buffered in +self+ to the operating system
2477 * (but does not necessarily flush data buffered in the operating system):
2478 *
2479 * $stdout.print 'no newline' # Not necessarily flushed.
2480 * $stdout.flush # Flushed.
2481 *
2482 */
2483
2484VALUE
2485rb_io_flush(VALUE io)
2486{
2487 return rb_io_flush_raw(io, 1);
2488}
2489
2490/*
2491 * call-seq:
2492 * tell -> integer
2493 *
2494 * Returns the current position (in bytes) in +self+
2495 * (see {Position}[rdoc-ref:IO@Position]):
2496 *
2497 * f = File.open('t.txt')
2498 * f.tell # => 0
2499 * f.gets # => "First line\n"
2500 * f.tell # => 12
2501 * f.close
2502 *
2503 * Related: IO#pos=, IO#seek.
2504 */
2505
2506static VALUE
2507rb_io_tell(VALUE io)
2508{
2509 rb_io_t *fptr;
2510 rb_off_t pos;
2511
2512 GetOpenFile(io, fptr);
2513 pos = io_tell(fptr);
2514 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2515 pos -= fptr->rbuf.len;
2516 return OFFT2NUM(pos);
2517}
2518
2519static VALUE
2520rb_io_seek(VALUE io, VALUE offset, int whence)
2521{
2522 rb_io_t *fptr;
2523 rb_off_t pos;
2524
2525 pos = NUM2OFFT(offset);
2526 GetOpenFile(io, fptr);
2527 pos = io_seek(fptr, pos, whence);
2528 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2529 if (fptr->readconv) clear_readconv(fptr);
2530
2531 return INT2FIX(0);
2532}
2533
2534static int
2535interpret_seek_whence(VALUE vwhence)
2536{
2537 if (vwhence == sym_SET)
2538 return SEEK_SET;
2539 if (vwhence == sym_CUR)
2540 return SEEK_CUR;
2541 if (vwhence == sym_END)
2542 return SEEK_END;
2543#ifdef SEEK_DATA
2544 if (vwhence == sym_DATA)
2545 return SEEK_DATA;
2546#endif
2547#ifdef SEEK_HOLE
2548 if (vwhence == sym_HOLE)
2549 return SEEK_HOLE;
2550#endif
2551 return NUM2INT(vwhence);
2552}
2553
2554/*
2555 * call-seq:
2556 * seek(offset, whence = IO::SEEK_SET) -> 0
2557 *
2558 * Seeks to the position given by integer +offset+
2559 * (see {Position}[rdoc-ref:IO@Position])
2560 * and constant +whence+, which is one of:
2561 *
2562 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2563 * Repositions the stream to its current position plus the given +offset+:
2564 *
2565 * f = File.open('t.txt')
2566 * f.tell # => 0
2567 * f.seek(20, :CUR) # => 0
2568 * f.tell # => 20
2569 * f.seek(-10, :CUR) # => 0
2570 * f.tell # => 10
2571 * f.close
2572 *
2573 * - +:END+ or <tt>IO::SEEK_END</tt>:
2574 * Repositions the stream to its end plus the given +offset+:
2575 *
2576 * f = File.open('t.txt')
2577 * f.tell # => 0
2578 * f.seek(0, :END) # => 0 # Repositions to stream end.
2579 * f.tell # => 52
2580 * f.seek(-20, :END) # => 0
2581 * f.tell # => 32
2582 * f.seek(-40, :END) # => 0
2583 * f.tell # => 12
2584 * f.close
2585 *
2586 * - +:SET+ or <tt>IO::SEEK_SET</tt>:
2587 * Repositions the stream to the given +offset+:
2588 *
2589 * f = File.open('t.txt')
2590 * f.tell # => 0
2591 * f.seek(20, :SET) # => 0
2592 * f.tell # => 20
2593 * f.seek(40, :SET) # => 0
2594 * f.tell # => 40
2595 * f.close
2596 *
2597 * Related: IO#pos=, IO#tell.
2598 *
2599 */
2600
2601static VALUE
2602rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2603{
2604 VALUE offset, ptrname;
2605 int whence = SEEK_SET;
2606
2607 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2608 whence = interpret_seek_whence(ptrname);
2609 }
2610
2611 return rb_io_seek(io, offset, whence);
2612}
2613
2614/*
2615 * call-seq:
2616 * pos = new_position -> new_position
2617 *
2618 * Seeks to the given +new_position+ (in bytes);
2619 * see {Position}[rdoc-ref:IO@Position]:
2620 *
2621 * f = File.open('t.txt')
2622 * f.tell # => 0
2623 * f.pos = 20 # => 20
2624 * f.tell # => 20
2625 * f.close
2626 *
2627 * Related: IO#seek, IO#tell.
2628 *
2629 */
2630
2631static VALUE
2632rb_io_set_pos(VALUE io, VALUE offset)
2633{
2634 rb_io_t *fptr;
2635 rb_off_t pos;
2636
2637 pos = NUM2OFFT(offset);
2638 GetOpenFile(io, fptr);
2639 pos = io_seek(fptr, pos, SEEK_SET);
2640 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2641 if (fptr->readconv) clear_readconv(fptr);
2642
2643 return OFFT2NUM(pos);
2644}
2645
2646/*
2647 * call-seq:
2648 * rewind -> 0
2649 *
2650 * Repositions the stream to its beginning,
2651 * setting both the position and the line number to zero;
2652 * see {Position}[rdoc-ref:IO@Position]
2653 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2654 *
2655 * f = File.open('t.txt')
2656 * f.tell # => 0
2657 * f.lineno # => 0
2658 * f.gets # => "First line\n"
2659 * f.tell # => 12
2660 * f.lineno # => 1
2661 * f.rewind # => 0
2662 * f.tell # => 0
2663 * f.lineno # => 0
2664 * f.close
2665 *
2666 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2667 *
2668 */
2669
2670static VALUE
2671rb_io_rewind(VALUE io)
2672{
2673 rb_io_t *fptr;
2674
2675 GetOpenFile(io, fptr);
2676 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2677 if (io == ARGF.current_file) {
2678 ARGF.lineno -= fptr->lineno;
2679 }
2680 fptr->lineno = 0;
2681 if (fptr->readconv) {
2682 clear_readconv(fptr);
2683 }
2684
2685 return INT2FIX(0);
2686}
2687
2688static int
2689fptr_wait_readable(rb_io_t *fptr)
2690{
2691 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2692
2693 if (result)
2694 rb_io_check_closed(fptr);
2695
2696 return result;
2697}
2698
2699static int
2700io_fillbuf(rb_io_t *fptr)
2701{
2702 ssize_t r;
2703
2704 if (fptr->rbuf.ptr == NULL) {
2705 fptr->rbuf.off = 0;
2706 fptr->rbuf.len = 0;
2707 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2708 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2709 }
2710 if (fptr->rbuf.len == 0) {
2711 retry:
2712 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2713
2714 if (r < 0) {
2715 if (fptr_wait_readable(fptr))
2716 goto retry;
2717
2718 int e = errno;
2719 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2720 if (!NIL_P(fptr->pathv)) {
2721 rb_str_append(path, fptr->pathv);
2722 }
2723
2724 rb_syserr_fail_path(e, path);
2725 }
2726 if (r > 0) rb_io_check_closed(fptr);
2727 fptr->rbuf.off = 0;
2728 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2729 if (r == 0)
2730 return -1; /* EOF */
2731 }
2732 return 0;
2733}
2734
2735/*
2736 * call-seq:
2737 * eof -> true or false
2738 *
2739 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2740 * see {Position}[rdoc-ref:IO@Position]:
2741 *
2742 * f = File.open('t.txt')
2743 * f.eof # => false
2744 * f.seek(0, :END) # => 0
2745 * f.eof # => true
2746 * f.close
2747 *
2748 * Raises an exception unless the stream is opened for reading;
2749 * see {Mode}[rdoc-ref:File@Access+Modes].
2750 *
2751 * If +self+ is a stream such as pipe or socket, this method
2752 * blocks until the other end sends some data or closes it:
2753 *
2754 * r, w = IO.pipe
2755 * Thread.new { sleep 1; w.close }
2756 * r.eof? # => true # After 1-second wait.
2757 *
2758 * r, w = IO.pipe
2759 * Thread.new { sleep 1; w.puts "a" }
2760 * r.eof? # => false # After 1-second wait.
2761 *
2762 * r, w = IO.pipe
2763 * r.eof? # blocks forever
2764 *
2765 * Note that this method reads data to the input byte buffer. So
2766 * IO#sysread may not behave as you intend with IO#eof?, unless you
2767 * call IO#rewind first (which is not available for some streams).
2768 */
2769
2770VALUE
2772{
2773 rb_io_t *fptr;
2774
2775 GetOpenFile(io, fptr);
2777
2778 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2779 if (READ_DATA_PENDING(fptr)) return Qfalse;
2780 READ_CHECK(fptr);
2781#if RUBY_CRLF_ENVIRONMENT
2782 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2783 return RBOOL(eof(fptr->fd));
2784 }
2785#endif
2786 return RBOOL(io_fillbuf(fptr) < 0);
2787}
2788
2789/*
2790 * call-seq:
2791 * sync -> true or false
2792 *
2793 * Returns the current sync mode of the stream.
2794 * When sync mode is true, all output is immediately flushed to the underlying
2795 * operating system and is not buffered by Ruby internally. See also #fsync.
2796 *
2797 * f = File.open('t.tmp', 'w')
2798 * f.sync # => false
2799 * f.sync = true
2800 * f.sync # => true
2801 * f.close
2802 *
2803 */
2804
2805static VALUE
2806rb_io_sync(VALUE io)
2807{
2808 rb_io_t *fptr;
2809
2810 io = GetWriteIO(io);
2811 GetOpenFile(io, fptr);
2812 return RBOOL(fptr->mode & FMODE_SYNC);
2813}
2814
2815#ifdef HAVE_FSYNC
2816
2817/*
2818 * call-seq:
2819 * sync = boolean -> boolean
2820 *
2821 * Sets the _sync_ _mode_ for the stream to the given value;
2822 * returns the given value.
2823 *
2824 * Values for the sync mode:
2825 *
2826 * - +true+: All output is immediately flushed to the
2827 * underlying operating system and is not buffered internally.
2828 * - +false+: Output may be buffered internally.
2829 *
2830 * Example;
2831 *
2832 * f = File.open('t.tmp', 'w')
2833 * f.sync # => false
2834 * f.sync = true
2835 * f.sync # => true
2836 * f.close
2837 *
2838 * Related: IO#fsync.
2839 *
2840 */
2841
2842static VALUE
2843rb_io_set_sync(VALUE io, VALUE sync)
2844{
2845 rb_io_t *fptr;
2846
2847 io = GetWriteIO(io);
2848 GetOpenFile(io, fptr);
2849 if (RTEST(sync)) {
2850 fptr->mode |= FMODE_SYNC;
2851 }
2852 else {
2853 fptr->mode &= ~FMODE_SYNC;
2854 }
2855 return sync;
2856}
2857
2858/*
2859 * call-seq:
2860 * fsync -> 0
2861 *
2862 * Immediately writes to disk all data buffered in the stream,
2863 * via the operating system's <tt>fsync(2)</tt>.
2864
2865 * Note this difference:
2866 *
2867 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2868 * but does not guarantee that the operating system actually writes the data to disk.
2869 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2870 * and that data is written to disk.
2871 *
2872 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2873 *
2874 */
2875
2876static VALUE
2877rb_io_fsync(VALUE io)
2878{
2879 rb_io_t *fptr;
2880
2881 io = GetWriteIO(io);
2882 GetOpenFile(io, fptr);
2883
2884 if (io_fflush(fptr) < 0)
2885 rb_sys_fail_on_write(fptr);
2886
2887 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2888 rb_sys_fail_path(fptr->pathv);
2889
2890 return INT2FIX(0);
2891}
2892#else
2893# define rb_io_fsync rb_f_notimplement
2894# define rb_io_sync rb_f_notimplement
2895static VALUE
2896rb_io_set_sync(VALUE io, VALUE sync)
2897{
2898 rb_notimplement();
2900}
2901#endif
2902
2903#ifdef HAVE_FDATASYNC
2904static VALUE
2905nogvl_fdatasync(void *ptr)
2906{
2907 rb_io_t *fptr = ptr;
2908
2909 return (VALUE)fdatasync(fptr->fd);
2910}
2911
2912/*
2913 * call-seq:
2914 * fdatasync -> 0
2915 *
2916 * Immediately writes to disk all data buffered in the stream,
2917 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2918 * otherwise via <tt>fsync(2)</tt>, if supported;
2919 * otherwise raises an exception.
2920 *
2921 */
2922
2923static VALUE
2924rb_io_fdatasync(VALUE io)
2925{
2926 rb_io_t *fptr;
2927
2928 io = GetWriteIO(io);
2929 GetOpenFile(io, fptr);
2930
2931 if (io_fflush(fptr) < 0)
2932 rb_sys_fail_on_write(fptr);
2933
2934 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2935 return INT2FIX(0);
2936
2937 /* fall back */
2938 return rb_io_fsync(io);
2939}
2940#else
2941#define rb_io_fdatasync rb_io_fsync
2942#endif
2943
2944/*
2945 * call-seq:
2946 * fileno -> integer
2947 *
2948 * Returns the integer file descriptor for the stream:
2949 *
2950 * $stdin.fileno # => 0
2951 * $stdout.fileno # => 1
2952 * $stderr.fileno # => 2
2953 * File.open('t.txt').fileno # => 10
2954 * f.close
2955 *
2956 */
2957
2958static VALUE
2959rb_io_fileno(VALUE io)
2960{
2961 rb_io_t *fptr = RFILE(io)->fptr;
2962 int fd;
2963
2964 rb_io_check_closed(fptr);
2965 fd = fptr->fd;
2966 return INT2FIX(fd);
2967}
2968
2969int
2971{
2972 if (RB_TYPE_P(io, T_FILE)) {
2973 rb_io_t *fptr = RFILE(io)->fptr;
2974 rb_io_check_closed(fptr);
2975 return fptr->fd;
2976 }
2977 else {
2978 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2979 if (!UNDEF_P(fileno)) {
2980 return RB_NUM2INT(fileno);
2981 }
2982 }
2983
2984 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2985
2987}
2988
2989int
2990rb_io_mode(VALUE io)
2991{
2992 rb_io_t *fptr;
2993 GetOpenFile(io, fptr);
2994 return fptr->mode;
2995}
2996
2997/*
2998 * call-seq:
2999 * pid -> integer or nil
3000 *
3001 * Returns the process ID of a child process associated with the stream,
3002 * which will have been set by IO#popen, or +nil+ if the stream was not
3003 * created by IO#popen:
3004 *
3005 * pipe = IO.popen("-")
3006 * if pipe
3007 * $stderr.puts "In parent, child pid is #{pipe.pid}"
3008 * else
3009 * $stderr.puts "In child, pid is #{$$}"
3010 * end
3011 *
3012 * Output:
3013 *
3014 * In child, pid is 26209
3015 * In parent, child pid is 26209
3016 *
3017 */
3018
3019static VALUE
3020rb_io_pid(VALUE io)
3021{
3022 rb_io_t *fptr;
3023
3024 GetOpenFile(io, fptr);
3025 if (!fptr->pid)
3026 return Qnil;
3027 return PIDT2NUM(fptr->pid);
3028}
3029
3030/*
3031 * :markup: markdown
3032 *
3033 * call-seq:
3034 * path -> string or nil
3035 *
3036 * Returns the string path associated with `self`,
3037 * or `nil` if there is no associated path:
3038 *
3039 * ```ruby
3040 * path = 'doc/maintainers.md'
3041 * fd = File.open(path).fileno # => 6
3042 * IO.new(fd, path: path).path # => "doc/maintainers.md"
3043 * IO.new(fd).path # => nil
3044 * ```
3045 *
3046 */
3047
3048VALUE
3050{
3051 rb_io_t *fptr = RFILE(io)->fptr;
3052
3053 if (!fptr)
3054 return Qnil;
3055
3056 return rb_obj_dup(fptr->pathv);
3057}
3058
3059/*
3060 * call-seq:
3061 * inspect -> string
3062 *
3063 * Returns a string representation of +self+:
3064 *
3065 * f = File.open('t.txt')
3066 * f.inspect # => "#<File:t.txt>"
3067 * f.close
3068 *
3069 */
3070
3071static VALUE
3072rb_io_inspect(VALUE obj)
3073{
3074 rb_io_t *fptr;
3075 VALUE result;
3076 static const char closed[] = " (closed)";
3077
3078 fptr = RFILE(obj)->fptr;
3079 if (!fptr) return rb_any_to_s(obj);
3080 result = rb_str_new_cstr("#<");
3081 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3082 rb_str_cat2(result, ":");
3083 if (NIL_P(fptr->pathv)) {
3084 if (fptr->fd < 0) {
3085 rb_str_cat(result, closed+1, strlen(closed)-1);
3086 }
3087 else {
3088 rb_str_catf(result, "fd %d", fptr->fd);
3089 }
3090 }
3091 else {
3092 rb_str_append(result, fptr->pathv);
3093 if (fptr->fd < 0) {
3094 rb_str_cat(result, closed, strlen(closed));
3095 }
3096 }
3097 return rb_str_cat2(result, ">");
3098}
3099
3100/*
3101 * call-seq:
3102 * to_io -> self
3103 *
3104 * Returns +self+.
3105 *
3106 */
3107
3108static VALUE
3109rb_io_to_io(VALUE io)
3110{
3111 return io;
3112}
3113
3114/* reading functions */
3115static rb_len_t
3116read_buffered_data(char *ptr, rb_len_t len, rb_io_t *fptr)
3117{
3118 int n;
3119
3120 n = READ_DATA_PENDING_COUNT(fptr);
3121 if (n <= 0) return 0;
3122 if (n > len) n = (int)len;
3123 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3124 fptr->rbuf.off += n;
3125 fptr->rbuf.len -= n;
3126 return n;
3127}
3128
3129static rb_len_t
3130io_bufread(char *ptr, rb_len_t len, rb_io_t *fptr, rb_len_t *read_len)
3131{
3132 rb_len_t offset = 0;
3133 rb_len_t n = len;
3134 rb_len_t c;
3135
3136 *read_len = 0;
3137 if (READ_DATA_PENDING(fptr) == 0) {
3138 while (n > 0) {
3139 again:
3140 rb_io_check_closed(fptr);
3141 c = rb_io_read_memory(fptr, ptr+offset, n);
3142 if (c == 0) break;
3143 if (c < 0) {
3144 if (fptr_wait_readable(fptr))
3145 goto again;
3146 return -1;
3147 }
3148 offset += c;
3149 *read_len = offset;
3150 if ((n -= c) <= 0) break;
3151 }
3152 return len - n;
3153 }
3154
3155 while (n > 0) {
3156 c = read_buffered_data(ptr+offset, n, fptr);
3157 if (c > 0) {
3158 offset += c;
3159 *read_len = offset;
3160 if ((n -= c) <= 0) break;
3161 }
3162 rb_io_check_closed(fptr);
3163 if (io_fillbuf(fptr) < 0) {
3164 break;
3165 }
3166 }
3167 return len - n;
3168}
3169
3170static int io_setstrbuf(VALUE *str, rb_len_t len);
3171
3173 char *str_ptr;
3174 rb_len_t offset;
3175 rb_len_t len;
3176 rb_len_t read_len;
3177 rb_io_t *fptr;
3178};
3179
3180static VALUE
3181bufread_body(VALUE arg)
3182{
3183 struct bufread_arg *p = (struct bufread_arg *)arg;
3184 p->len = io_bufread(p->str_ptr + p->offset, p->len, p->fptr, &p->read_len);
3185 return Qundef;
3186}
3187
3188static VALUE
3189bufread_timeout(VALUE arg, VALUE error)
3190{
3191 struct bufread_arg *p = (struct bufread_arg *)arg;
3192
3193 if (p->offset + p->read_len > 0) {
3194 VALUE str = rb_str_new(p->str_ptr, p->offset + p->read_len);
3195 io_restore_read_buffer(str, p->fptr);
3196 }
3197 rb_exc_raise(error);
3199}
3200
3201static VALUE
3202bufread_call(VALUE arg)
3203{
3204 struct bufread_arg *p = (struct bufread_arg *)arg;
3205
3206 if (NIL_P(p->fptr->timeout)) {
3207 return bufread_body(arg);
3208 }
3209 return rb_rescue2(bufread_body, arg, bufread_timeout, arg,
3210 rb_eIOTimeoutError, (VALUE)0);
3211}
3212
3213static rb_len_t
3214io_fread(VALUE str, rb_len_t offset, rb_len_t size, rb_io_t *fptr)
3215{
3216 rb_len_t len;
3217 struct bufread_arg arg;
3218
3219 io_setstrbuf(&str, offset + size);
3220 if (!READ_DATA_PENDING(fptr))
3221 rb_str_make_heap(str);
3222 arg.str_ptr = RSTRING_PTR(str);
3223 arg.offset = offset;
3224 arg.len = size;
3225 arg.read_len = 0;
3226 arg.fptr = fptr;
3227 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3228 len = arg.len;
3229 if (len < 0) rb_sys_fail_path(fptr->pathv);
3230 return len;
3231}
3232
3233static rb_len_t
3234remain_size(rb_io_t *fptr)
3235{
3236 struct stat st;
3237 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3238 rb_off_t pos;
3239
3240 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3241#if defined(__HAIKU__)
3242 && (st.st_dev > 3)
3243#endif
3244 )
3245 {
3246 if (io_fflush(fptr) < 0)
3247 rb_sys_fail_on_write(fptr);
3248 pos = lseek(fptr->fd, 0, SEEK_CUR);
3249 if (st.st_size >= pos && pos >= 0) {
3250 siz += st.st_size - pos;
3251 if (siz > RB_LEN_MAX) {
3252 rb_raise(rb_eIOError, "file too big for single read");
3253 }
3254 }
3255 }
3256 else {
3257 siz += BUFSIZ;
3258 }
3259 return (rb_len_t)siz;
3260}
3261
3262static VALUE
3263io_enc_str(VALUE str, rb_io_t *fptr)
3264{
3265 rb_enc_associate(str, io_read_encoding(fptr));
3266 return str;
3267}
3268
3269static void
3270make_readconv(rb_io_t *fptr, int size)
3271{
3272 if (!fptr->readconv) {
3273 int ecflags;
3274 VALUE ecopts;
3275 const char *sname, *dname;
3276 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3277 ecopts = fptr->encs.ecopts;
3278 if (fptr->encs.enc2) {
3279 sname = rb_enc_name(fptr->encs.enc2);
3280 dname = rb_enc_name(io_read_encoding(fptr));
3281 }
3282 else {
3283 sname = dname = "";
3284 }
3285 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3286 if (!fptr->readconv)
3287 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3288 fptr->cbuf.off = 0;
3289 fptr->cbuf.len = 0;
3290 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3291 fptr->cbuf.capa = size;
3292 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3293 }
3294}
3295
3296#define MORE_CHAR_SUSPENDED Qtrue
3297#define MORE_CHAR_FINISHED Qnil
3298static VALUE
3299fill_cbuf(rb_io_t *fptr, int ec_flags)
3300{
3301 const unsigned char *ss, *sp, *se;
3302 unsigned char *ds, *dp, *de;
3304 int putbackable;
3305 int cbuf_len0;
3306 VALUE exc;
3307
3308 ec_flags |= ECONV_PARTIAL_INPUT;
3309
3310 if (fptr->cbuf.len == fptr->cbuf.capa)
3311 return MORE_CHAR_SUSPENDED; /* cbuf full */
3312 if (fptr->cbuf.len == 0)
3313 fptr->cbuf.off = 0;
3314 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3315 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3316 fptr->cbuf.off = 0;
3317 }
3318
3319 cbuf_len0 = fptr->cbuf.len;
3320
3321 while (1) {
3322 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3323 se = sp + fptr->rbuf.len;
3324 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3325 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3326 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3327 fptr->rbuf.off += (int)(sp - ss);
3328 fptr->rbuf.len -= (int)(sp - ss);
3329 fptr->cbuf.len += (int)(dp - ds);
3330
3331 putbackable = rb_econv_putbackable(fptr->readconv);
3332 /* The converter can hold readagain bytes it received in an earlier
3333 * fill (a character split across reads). Only bytes still in rbuf
3334 * can be put back there; the rest stay in the converter. */
3335 if (putbackable > fptr->rbuf.off)
3336 putbackable = fptr->rbuf.off;
3337 if (putbackable) {
3338 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3339 fptr->rbuf.off -= putbackable;
3340 fptr->rbuf.len += putbackable;
3341 }
3342
3343 exc = rb_econv_make_exception(fptr->readconv);
3344 if (!NIL_P(exc))
3345 return exc;
3346
3347 if (cbuf_len0 != fptr->cbuf.len)
3348 return MORE_CHAR_SUSPENDED;
3349
3350 if (res == econv_finished) {
3351 return MORE_CHAR_FINISHED;
3352 }
3353
3354 if (res == econv_source_buffer_empty) {
3355 if (fptr->rbuf.len == 0) {
3356 READ_CHECK(fptr);
3357 if (io_fillbuf(fptr) < 0) {
3358 if (!fptr->readconv) {
3359 return MORE_CHAR_FINISHED;
3360 }
3361 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3362 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3363 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3364 fptr->cbuf.len += (int)(dp - ds);
3366 break;
3367 }
3368 }
3369 }
3370 }
3371 if (cbuf_len0 != fptr->cbuf.len)
3372 return MORE_CHAR_SUSPENDED;
3373
3374 return MORE_CHAR_FINISHED;
3375}
3376
3377static VALUE
3378more_char(rb_io_t *fptr)
3379{
3380 VALUE v;
3381 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3382 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3383 rb_exc_raise(v);
3384 return v;
3385}
3386
3387static VALUE
3388io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3389{
3390 VALUE str = Qnil;
3391 if (strp) {
3392 str = *strp;
3393 if (NIL_P(str)) {
3394 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3395 }
3396 else {
3397 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3398 }
3399 rb_enc_associate(str, fptr->encs.enc);
3400 }
3401 fptr->cbuf.off += len;
3402 fptr->cbuf.len -= len;
3403 /* xxx: set coderange */
3404 if (fptr->cbuf.len == 0)
3405 fptr->cbuf.off = 0;
3406 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3407 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3408 fptr->cbuf.off = 0;
3409 }
3410 return str;
3411}
3412
3413static int
3414io_setstrbuf(VALUE *str, rb_len_t len)
3415{
3416 if (NIL_P(*str)) {
3417 *str = rb_str_new(0, len);
3418 return TRUE;
3419 }
3420 else {
3421 VALUE s = StringValue(*str);
3422 rb_str_modify(s);
3423
3424 rb_len_t clen = RSTRING_LEN(s);
3425 if (clen >= len) {
3426 return FALSE;
3427 }
3428 len -= clen;
3429 }
3430 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3432 }
3433 return FALSE;
3434}
3435
3436#define MAX_REALLOC_GAP 4096
3437static void
3438io_shrink_read_string(VALUE str, rb_len_t n)
3439{
3440 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3441 rb_str_resize(str, n);
3442 }
3443}
3444
3445static void
3446io_set_read_length(VALUE str, rb_len_t n, int shrinkable)
3447{
3448 if (RSTRING_LEN(str) != n) {
3449 rb_str_modify(str);
3450 rb_str_set_len(str, n);
3451 if (shrinkable) io_shrink_read_string(str, n);
3452 }
3453}
3454
3455static VALUE
3456read_all(rb_io_t *fptr, rb_len_t siz, VALUE str)
3457{
3458 rb_len_t bytes;
3459 rb_len_t n;
3460 rb_len_t pos;
3461 rb_encoding *enc;
3462 int cr;
3463 int shrinkable;
3464
3465 if (NEED_READCONV(fptr)) {
3466 int first = !NIL_P(str);
3467 SET_BINARY_MODE(fptr);
3468 shrinkable = io_setstrbuf(&str,0);
3469 make_readconv(fptr, 0);
3470 while (1) {
3471 VALUE v;
3472 if (fptr->cbuf.len) {
3473 if (first) rb_str_set_len(str, first = 0);
3474 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3475 }
3476 v = fill_cbuf(fptr, 0);
3477 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3478 if (fptr->cbuf.len) {
3479 if (first) rb_str_set_len(str, first = 0);
3480 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3481 }
3482 rb_exc_raise(v);
3483 }
3484 if (v == MORE_CHAR_FINISHED) {
3485 clear_readconv(fptr);
3486 if (first) rb_str_set_len(str, first = 0);
3487 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3488 return io_enc_str(str, fptr);
3489 }
3490 }
3491 }
3492
3493 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3494 bytes = 0;
3495 pos = 0;
3496
3497 enc = io_read_encoding(fptr);
3498 cr = 0;
3499
3500 if (siz == 0) {
3501 siz = BUFSIZ;
3502 }
3503 else {
3504 // If `siz` is set, we got it from `stat(2)`.
3505 // We attempt to read one extra byte because:
3506 // - If the file was appended to since then, we'll continue reading.
3507 // - If the file is still the same length, we won't issue a second `io_fread`.
3508 siz++;
3509 }
3510 shrinkable = io_setstrbuf(&str, siz);
3511 for (;;) {
3512 READ_CHECK(fptr);
3513 n = io_fread(str, bytes, siz - bytes, fptr);
3514 if (n == 0 && bytes == 0) {
3515 rb_str_set_len(str, 0);
3516 break;
3517 }
3518 bytes += n;
3519 rb_str_set_len(str, bytes);
3520 if (cr != ENC_CODERANGE_BROKEN)
3521 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3522 if (bytes < siz) break;
3523 siz += BUFSIZ;
3524
3525 size_t capa = rb_str_capacity(str);
3526 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3527 if (capa < BUFSIZ) {
3528 capa = BUFSIZ;
3529 }
3530 else if (capa > IO_MAX_BUFFER_GROWTH) {
3531 capa = IO_MAX_BUFFER_GROWTH;
3532 }
3534 }
3535 }
3536 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3537 str = io_enc_str(str, fptr);
3538 ENC_CODERANGE_SET(str, cr);
3539 return str;
3540}
3541
3542void
3544{
3545 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3546 rb_sys_fail_path(fptr->pathv);
3547 }
3548}
3549
3550static VALUE
3551io_read_memory_call(VALUE arg)
3552{
3553 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3554
3555 VALUE scheduler = rb_fiber_scheduler_current();
3556 if (scheduler != Qnil) {
3557 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa);
3558
3559 if (!UNDEF_P(result)) {
3560 // This is actually returned as a pseudo-VALUE and later cast to a rb_len_t:
3562 }
3563 }
3564
3565 if (iis->nonblock) {
3566 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3567 }
3568 else {
3569 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3570 }
3571}
3572
3573static rb_len_t
3574io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3575{
3576 return (rb_len_t)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3577}
3578
3579#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3580
3581static VALUE
3582io_getpartial(VALUE io, VALUE length, VALUE str, int no_exception, int nonblock)
3583{
3584 rb_io_t *fptr;
3585 rb_len_t n, len;
3586 struct io_internal_read_struct iis;
3587 int shrinkable;
3588
3589 if ((len = NUM2LEN(length)) < 0) {
3590 rb_raise(rb_eArgError, "negative length %"PRIdLEN" given", len);
3591 }
3592
3593 shrinkable = io_setstrbuf(&str, len);
3594
3595 GetOpenFile(io, fptr);
3597
3598 if (len == 0) {
3599 io_set_read_length(str, 0, shrinkable);
3600 return str;
3601 }
3602
3603 if (!nonblock)
3604 READ_CHECK(fptr);
3605 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3606 if (n <= 0) {
3607 again:
3608 if (nonblock) {
3609 /* NOTE: The result is deliberately ignored */
3610 rb_fd_set_nonblock(fptr->fd);
3611 }
3612 io_setstrbuf(&str, len);
3613 rb_str_make_heap(str);
3614 iis.th = rb_thread_current();
3615 iis.fptr = fptr;
3616 iis.nonblock = nonblock;
3617 iis.fd = fptr->fd;
3618 iis.buf = RSTRING_PTR(str);
3619 iis.capa = len;
3620 iis.timeout = NULL;
3621 n = io_read_memory_locktmp(str, &iis);
3622 if (n < 0) {
3623 int e = errno;
3624 if (!nonblock && fptr_wait_readable(fptr))
3625 goto again;
3626 if (nonblock && (io_again_p(e))) {
3627 if (no_exception)
3628 return sym_wait_readable;
3629 else
3630 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3631 e, "read would block");
3632 }
3633 rb_syserr_fail_path(e, fptr->pathv);
3634 }
3635 }
3636 io_set_read_length(str, n, shrinkable);
3637
3638 if (n == 0)
3639 return Qnil;
3640 else
3641 return str;
3642}
3643
3644/*
3645 * call-seq:
3646 * readpartial(maxlen) -> string
3647 * readpartial(maxlen, out_string) -> out_string
3648 *
3649 * Reads up to +maxlen+ bytes from the stream;
3650 * returns a string (either a new string or the given +out_string+).
3651 * Its encoding is:
3652 *
3653 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3654 * - ASCII-8BIT, otherwise.
3655 *
3656 * - Contains +maxlen+ bytes from the stream, if available.
3657 * - Otherwise contains all available bytes, if any available.
3658 * - Is an empty string if +maxlen+ is zero.
3659 *
3660 * With the single non-negative integer argument +maxlen+ given,
3661 * returns a new string:
3662 *
3663 * f = File.new('t.txt')
3664 * f.readpartial(20) # => "First line\nSecond l"
3665 * f.readpartial(20) # => "ine\n\nFourth line\n"
3666 * f.readpartial(20) # => "Fifth line\n"
3667 * f.readpartial(20) # Raises EOFError.
3668 * f.close
3669 *
3670 * With both argument +maxlen+ and string argument +out_string+ given,
3671 * returns modified +out_string+:
3672 *
3673 * f = File.new('t.txt')
3674 * s = 'foo'
3675 * f.readpartial(20, s) # => "First line\nSecond l"
3676 * s = 'bar'
3677 * f.readpartial(0, s) # => ""
3678 * f.close
3679 *
3680 * This method is useful for a stream such as a pipe, a socket, or a tty.
3681 * It blocks only when no data is immediately available.
3682 * This means that it blocks only when _all_ of the following are true:
3683 *
3684 * - The byte buffer in the stream is empty.
3685 * - The content of the stream is empty.
3686 * - The stream is not at EOF.
3687 *
3688 * When blocked, the method waits for either more data or EOF on the stream:
3689 *
3690 * - If more data is read, the method returns the data.
3691 * - If EOF is reached, the method raises EOFError.
3692 *
3693 * When not blocked, the method responds immediately:
3694 *
3695 * - Returns data from the buffer if there is any.
3696 * - Otherwise returns data from the stream if there is any.
3697 * - Otherwise raises EOFError if the stream has reached EOF.
3698 *
3699 * Note that this method is similar to sysread. The differences are:
3700 *
3701 * - If the byte buffer is not empty, read from the byte buffer
3702 * instead of "sysread for buffered IO (IOError)".
3703 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3704 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3705 * readpartial retries the system call.
3706 *
3707 * The latter means that readpartial is non-blocking-flag insensitive.
3708 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3709 * if the fd is blocking mode.
3710 *
3711 * Examples:
3712 *
3713 * # # Returned Buffer Content Pipe Content
3714 * r, w = IO.pipe #
3715 * w << 'abc' # "" "abc".
3716 * r.readpartial(4096) # => "abc" "" ""
3717 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3718 *
3719 * # # Returned Buffer Content Pipe Content
3720 * r, w = IO.pipe #
3721 * w << 'abc' # "" "abc"
3722 * w.close # "" "abc" EOF
3723 * r.readpartial(4096) # => "abc" "" EOF
3724 * r.readpartial(4096) # raises EOFError
3725 *
3726 * # # Returned Buffer Content Pipe Content
3727 * r, w = IO.pipe #
3728 * w << "abc\ndef\n" # "" "abc\ndef\n"
3729 * r.gets # => "abc\n" "def\n" ""
3730 * w << "ghi\n" # "def\n" "ghi\n"
3731 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3732 * r.readpartial(4096) # => "ghi\n" "" ""
3733 *
3734 */
3735
3736static VALUE
3737io_readpartial(int argc, VALUE *argv, VALUE io)
3738{
3739 VALUE ret, length, str;
3740
3741 rb_scan_args(argc, argv, "11", &length, &str);
3742 ret = io_getpartial(io, length, str, 0, 0);
3743 if (NIL_P(ret))
3744 rb_eof_error();
3745 return ret;
3746}
3747
3748static VALUE
3749io_nonblock_eof(int no_exception)
3750{
3751 if (!no_exception) {
3752 rb_eof_error();
3753 }
3754 return Qnil;
3755}
3756
3757/* :nodoc: */
3758static VALUE
3759io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3760{
3761 int no_exception = !rb_bool_expected(ex, "exception", TRUE);
3762 VALUE ret = io_getpartial(io, length, str, no_exception, 1);
3763 if (NIL_P(ret))
3764 io_nonblock_eof(no_exception);
3765
3766 return ret;
3767}
3768
3769/* :nodoc: */
3770static VALUE
3771io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3772{
3773 rb_io_t *fptr;
3774 rb_len_t n;
3775
3776 if (!RB_TYPE_P(str, T_STRING))
3777 str = rb_obj_as_string(str);
3778 rb_bool_expected(ex, "exception", TRUE);
3779
3780 io = GetWriteIO(io);
3781 GetOpenFile(io, fptr);
3783
3784 if (io_fflush(fptr) < 0)
3785 rb_sys_fail_on_write(fptr);
3786
3787 rb_fd_set_nonblock(fptr->fd);
3788 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3789 RB_GC_GUARD(str);
3790
3791 if (n < 0) {
3792 int e = errno;
3793 if (io_again_p(e)) {
3794 if (!ex) {
3795 return sym_wait_writable;
3796 }
3797 else {
3798 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3799 }
3800 }
3801 rb_syserr_fail_path(e, fptr->pathv);
3802 }
3803
3804 return LEN2NUM(n);
3805}
3806
3807/*
3808 * call-seq:
3809 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3810 *
3811 * Reads bytes from the stream; the stream must be opened for reading
3812 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3813 *
3814 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3815 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3816 *
3817 * Returns a string (either a new string or the given +out_string+)
3818 * containing the bytes read.
3819 * The encoding of the string depends on both +maxLen+ and +out_string+:
3820 *
3821 * - +maxlen+ is +nil+: uses internal encoding of +self+
3822 * (regardless of whether +out_string+ was given).
3823 * - +maxlen+ not +nil+:
3824 *
3825 * - +out_string+ given: encoding of +out_string+ not modified.
3826 * - +out_string+ not given: ASCII-8BIT is used.
3827 *
3828 * <b>Without Argument +out_string+</b>
3829 *
3830 * When argument +out_string+ is omitted,
3831 * the returned value is a new string:
3832 *
3833 * f = File.new('t.txt')
3834 * f.read
3835 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3836 * f.rewind
3837 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3838 * f.read(30) # => "rth line\r\nFifth line\r\n"
3839 * f.read(30) # => nil
3840 * f.close
3841 *
3842 * If +maxlen+ is zero, returns an empty string.
3843 *
3844 * <b> With Argument +out_string+</b>
3845 *
3846 * When argument +out_string+ is given,
3847 * the returned value is +out_string+, whose content is replaced:
3848 *
3849 * f = File.new('t.txt')
3850 * s = 'foo' # => "foo"
3851 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3852 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3853 * f.rewind
3854 * s = 'bar'
3855 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3856 * s # => "First line\r\nSecond line\r\n\r\nFou"
3857 * s = 'baz'
3858 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3859 * s # => "rth line\r\nFifth line\r\n"
3860 * s = 'bat'
3861 * f.read(30, s) # => nil
3862 * s # => ""
3863 * f.close
3864 *
3865 * Note that this method behaves like the fread() function in C.
3866 * This means it retries to invoke read(2) system calls to read data
3867 * with the specified maxlen (or until EOF).
3868 *
3869 * This behavior is preserved even if the stream is in non-blocking mode.
3870 * (This method is non-blocking-flag insensitive as other methods.)
3871 *
3872 * If you need the behavior like a single read(2) system call,
3873 * consider #readpartial, #read_nonblock, and #sysread.
3874 *
3875 * Related: IO#write.
3876 */
3877
3878static VALUE
3879io_read(int argc, VALUE *argv, VALUE io)
3880{
3881 rb_io_t *fptr;
3882 rb_len_t n, len;
3883 VALUE length, str;
3884 int shrinkable;
3885#if RUBY_CRLF_ENVIRONMENT
3886 int previous_mode;
3887#endif
3888
3889 rb_scan_args(argc, argv, "02", &length, &str);
3890
3891 if (NIL_P(length)) {
3892 GetOpenFile(io, fptr);
3894 return read_all(fptr, remain_size(fptr), str);
3895 }
3896 len = NUM2LEN(length);
3897 if (len < 0) {
3898 rb_raise(rb_eArgError, "negative length %"PRIdLEN" given", len);
3899 }
3900
3901 shrinkable = io_setstrbuf(&str,len);
3902
3903 GetOpenFile(io, fptr);
3905 if (len == 0) {
3906 io_set_read_length(str, 0, shrinkable);
3907 return str;
3908 }
3909
3910 READ_CHECK(fptr);
3911#if RUBY_CRLF_ENVIRONMENT
3912 previous_mode = set_binary_mode_with_seek_cur(fptr);
3913#endif
3914 n = io_fread(str, 0, len, fptr);
3915 io_set_read_length(str, n, shrinkable);
3916#if RUBY_CRLF_ENVIRONMENT
3917 if (previous_mode == O_TEXT) {
3918 setmode(fptr->fd, O_TEXT);
3919 }
3920#endif
3921 if (n == 0) return Qnil;
3922
3923 return str;
3924}
3925
3926static void
3927rscheck(const char *rsptr, rb_len_t rslen, VALUE rs)
3928{
3929 if (!rs) return;
3930 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3931 rb_raise(rb_eRuntimeError, "rs modified");
3932}
3933
3934static const char *
3935search_delim(const char *p, rb_len_t len, int delim, rb_encoding *enc)
3936{
3937 if (rb_enc_mbminlen(enc) == 1) {
3938 p = memchr(p, delim, len);
3939 if (p) return p + 1;
3940 }
3941 else {
3942 const char *end = p + len;
3943 while (p < end) {
3944 int r = rb_enc_precise_mbclen(p, end, enc);
3945 if (!MBCLEN_CHARFOUND_P(r)) {
3946 p += rb_enc_mbminlen(enc);
3947 continue;
3948 }
3949 int n = MBCLEN_CHARFOUND_LEN(r);
3950 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3951 return p + n;
3952 }
3953 p += n;
3954 }
3955 }
3956 return NULL;
3957}
3958
3959static int
3960read_raw_character(rb_io_t *fptr, rb_encoding *enc, char *buf)
3961{
3962 int n = 0;
3963 int r;
3964
3965 do {
3966 if (!READ_DATA_PENDING(fptr)) {
3967 READ_CHECK(fptr);
3968 if (io_fillbuf(fptr) < 0) break;
3969 }
3970 buf[n++] = *READ_DATA_PENDING_PTR(fptr);
3971 fptr->rbuf.off++;
3972 fptr->rbuf.len--;
3973 r = rb_enc_precise_mbclen(buf, buf + n, enc);
3974 } while (MBCLEN_NEEDMORE_P(r) && n < rb_enc_mbmaxlen(enc));
3975
3976 return n;
3977}
3978
3979static void
3980unread_raw_character(rb_io_t *fptr, const char *buf, int len)
3981{
3982 if (fptr->rbuf.capa - fptr->rbuf.len < len) {
3983 if (fptr->rbuf.capa > INT_MAX - len)
3984 rb_raise(rb_eIOError, "ungetbyte failed");
3985 fptr->rbuf.capa += len;
3986 REALLOC_N(fptr->rbuf.ptr, char, fptr->rbuf.capa);
3987 }
3988 io_ungetbyte(rb_str_new(buf, len), fptr);
3989}
3990
3991static const char *
3992search_wide_delim(const char *p, long len, const char *delim, int width)
3993{
3994 const char *e = p + len;
3995 int index = 0;
3996
3997 while (index < width && delim[index] == 0) index++;
3998 if (index == width) index = 0;
3999
4000 const char *candidate = p + index;
4001 while (candidate < e) {
4002 candidate = memchr(candidate, (unsigned char)delim[index], e - candidate);
4003 if (candidate == NULL) break;
4004 const char *start = candidate - index;
4005 if ((start - p) % width == 0 && start + width <= e &&
4006 memcmp(start, delim, width) == 0) {
4007 return start;
4008 }
4009 candidate++;
4010 }
4011 return NULL;
4012}
4013
4014static int
4015appendline(rb_io_t *fptr, int delim, VALUE *strp, rb_len_t *lp, rb_encoding *enc)
4016{
4017 VALUE str = *strp;
4018 rb_len_t limit = *lp;
4019
4020 if (NEED_READCONV(fptr)) {
4021 SET_BINARY_MODE(fptr);
4022 make_readconv(fptr, 0);
4023 do {
4024 const char *p, *e;
4025 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
4026 if (searchlen) {
4027 p = READ_CHAR_PENDING_PTR(fptr);
4028 if (0 < limit && limit < searchlen)
4029 searchlen = (int)limit;
4030 e = search_delim(p, searchlen, delim, enc);
4031 if (e) {
4032 int len = (int)(e-p);
4033 if (NIL_P(str))
4034 *strp = str = rb_str_new(p, len);
4035 else
4036 rb_str_buf_cat(str, p, len);
4037 fptr->cbuf.off += len;
4038 fptr->cbuf.len -= len;
4039 limit -= len;
4040 *lp = limit;
4041 return delim;
4042 }
4043
4044 if (NIL_P(str))
4045 *strp = str = rb_str_new(p, searchlen);
4046 else
4047 rb_str_buf_cat(str, p, searchlen);
4048 fptr->cbuf.off += searchlen;
4049 fptr->cbuf.len -= searchlen;
4050 limit -= searchlen;
4051
4052 if (limit == 0) {
4053 *lp = limit;
4054 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4055 }
4056 }
4057 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4058 clear_readconv(fptr);
4059 *lp = limit;
4060 return EOF;
4061 }
4062
4063 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4064 if (rb_enc_mbminlen(enc) != 1) {
4065 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4066 int len;
4067
4068 if (limit < 0) {
4069 int width = rb_enc_mbminlen(enc);
4070 int delim_len = rb_enc_codelen(delim, enc);
4071
4072 if (delim_len == width) {
4073 rb_enc_mbcput(delim, buf, enc);
4074 for (;;) {
4075 if (!READ_DATA_PENDING(fptr)) {
4076 READ_CHECK(fptr);
4077 if (io_fillbuf(fptr) < 0) return EOF;
4078 }
4079 long pending = READ_DATA_PENDING_COUNT(fptr);
4080 long complete = pending - pending % width;
4081 const char *p = READ_DATA_PENDING_PTR(fptr);
4082 const char *q = complete ? search_wide_delim(p, complete, buf, width) : NULL;
4083 long take = q ? q - p + width : complete;
4084
4085 if (take > 0) {
4086 if (NIL_P(str))
4087 *strp = str = rb_str_buf_new(0);
4088 rb_str_buf_cat(str, p, take);
4089 fptr->rbuf.off += (int)take;
4090 fptr->rbuf.len -= (int)take;
4091 }
4092 if (q) return delim;
4093 if (complete == pending) continue;
4094
4095 len = read_raw_character(fptr, enc, buf);
4096 if (len == 0) return EOF;
4097 if (NIL_P(str))
4098 *strp = str = rb_str_buf_new(0);
4099 rb_str_buf_cat(str, buf, len);
4100 int r = rb_enc_precise_mbclen(buf, buf + len, enc);
4101 if (MBCLEN_CHARFOUND_P(r) &&
4102 rb_enc_mbc_to_codepoint(buf, buf + len, enc) == (unsigned int)delim)
4103 return delim;
4104 }
4105 }
4106 }
4107
4108 while ((len = read_raw_character(fptr, enc, buf)) > 0) {
4109 if (NIL_P(str))
4110 *strp = str = rb_str_buf_new(0);
4111 rb_str_buf_cat(str, buf, len);
4112 if (limit > 0) {
4113 if (len > limit) {
4114 *lp = 0;
4115 return (unsigned char)buf[len - 1];
4116 }
4117 *lp = limit -= len;
4118 }
4119 int r = rb_enc_precise_mbclen(buf, buf + len, enc);
4120 if (MBCLEN_CHARFOUND_P(r) &&
4121 rb_enc_mbc_to_codepoint(buf, buf + len, enc) == (unsigned int)delim)
4122 return delim;
4123 if (limit == 0)
4124 return (unsigned char)buf[len - 1];
4125 }
4126 *lp = limit;
4127 return EOF;
4128 }
4129 do {
4130 rb_len_t pending = READ_DATA_PENDING_COUNT(fptr);
4131 if (pending > 0) {
4132 const char *p = READ_DATA_PENDING_PTR(fptr);
4133 const char *e;
4134 rb_len_t last;
4135
4136 if (limit > 0 && pending > limit) pending = limit;
4137 e = search_delim(p, pending, delim, enc);
4138 if (e) pending = e - p;
4139 if (!NIL_P(str)) {
4140 last = RSTRING_LEN(str);
4141 rb_str_resize(str, last + pending);
4142 }
4143 else {
4144 last = 0;
4145 *strp = str = rb_str_buf_new(pending);
4146 rb_str_set_len(str, pending);
4147 }
4148 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
4149 limit -= pending;
4150 *lp = limit;
4151 if (e) return delim;
4152 if (limit == 0)
4153 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4154 }
4155 READ_CHECK(fptr);
4156 } while (io_fillbuf(fptr) >= 0);
4157 *lp = limit;
4158 return EOF;
4159}
4160
4161static inline int
4162swallow(rb_io_t *fptr, int term)
4163{
4164 if (NEED_READCONV(fptr)) {
4165 rb_encoding *enc = io_read_encoding(fptr);
4166 int needconv = rb_enc_mbminlen(enc) != 1;
4167 SET_BINARY_MODE(fptr);
4168 make_readconv(fptr, 0);
4169 do {
4170 size_t cnt;
4171 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4172 const char *p = READ_CHAR_PENDING_PTR(fptr);
4173 int i;
4174 if (!needconv) {
4175 if (*p != term) return TRUE;
4176 i = (int)cnt;
4177 while (--i && *++p == term);
4178 }
4179 else {
4180 const char *e = p + cnt;
4181 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
4182 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4183 i = (int)(e - p);
4184 }
4185 io_shift_cbuf(fptr, (int)cnt - i, NULL);
4186 }
4187 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4188 return FALSE;
4189 }
4190
4191 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4192 rb_encoding *enc = io_read_encoding(fptr);
4193 int widechar = rb_enc_mbminlen(enc) != 1;
4194 if (widechar) {
4195 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4196 int len;
4197
4198 while ((len = read_raw_character(fptr, enc, buf)) > 0) {
4199 if (rb_enc_ascget(buf, buf + len, NULL, enc) != term) {
4200 unread_raw_character(fptr, buf, len);
4201 return TRUE;
4202 }
4203 }
4204 return FALSE;
4205 }
4206 do {
4207 size_t cnt;
4208 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4209 char buf[1024];
4210 const char *p = READ_DATA_PENDING_PTR(fptr);
4211 int i;
4212 if (cnt > sizeof buf) cnt = sizeof buf;
4213 if (*p != term) return TRUE;
4214 i = (int)cnt;
4215 while (--i && *++p == term);
4216 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4217 rb_sys_fail_path(fptr->pathv);
4218 }
4219 READ_CHECK(fptr);
4220 } while (io_fillbuf(fptr) == 0);
4221 return FALSE;
4222}
4223
4224static VALUE
4225rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4226{
4227 VALUE str = Qnil;
4228 rb_len_t len = 0;
4229 rb_len_t pos = 0;
4230 int cr = 0;
4231
4232 do {
4233 int pending = READ_DATA_PENDING_COUNT(fptr);
4234
4235 if (pending > 0) {
4236 const char *p = READ_DATA_PENDING_PTR(fptr);
4237 const char *e;
4238 int chomplen = 0;
4239
4240 e = memchr(p, '\n', pending);
4241 if (e) {
4242 pending = (int)(e - p + 1);
4243 if (chomp) {
4244 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4245 }
4246 }
4247 if (NIL_P(str)) {
4248 str = rb_str_new(p, pending - chomplen);
4249 fptr->rbuf.off += pending;
4250 fptr->rbuf.len -= pending;
4251 }
4252 else {
4253 rb_str_resize(str, len + pending - chomplen);
4254 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4255 fptr->rbuf.off += chomplen;
4256 fptr->rbuf.len -= chomplen;
4257 if (pending == 1 && chomplen == 1 && len > 0) {
4258 if (RSTRING_PTR(str)[len-1] == '\r') {
4259 rb_str_resize(str, --len);
4260 break;
4261 }
4262 }
4263 }
4264 len += pending - chomplen;
4265 if (cr != ENC_CODERANGE_BROKEN)
4266 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4267 if (e) break;
4268 }
4269 READ_CHECK(fptr);
4270 } while (io_fillbuf(fptr) >= 0);
4271 if (NIL_P(str)) return Qnil;
4272
4273 str = io_enc_str(str, fptr);
4274 ENC_CODERANGE_SET(str, cr);
4275 fptr->lineno++;
4276
4277 return str;
4278}
4279
4281 VALUE io;
4282 VALUE rs;
4283 rb_len_t limit;
4284 unsigned int chomp: 1;
4285};
4286
4287static void
4288extract_getline_opts(VALUE opts, struct getline_arg *args)
4289{
4290 int chomp = FALSE;
4291 if (!NIL_P(opts)) {
4292 static ID kwds[1];
4293 VALUE vchomp;
4294 if (!kwds[0]) {
4295 kwds[0] = rb_intern_const("chomp");
4296 }
4297 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4298 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4299 }
4300 args->chomp = chomp;
4301}
4302
4303static void
4304extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4305{
4306 VALUE rs = rb_rs, lim = Qnil;
4307
4308 if (argc == 1) {
4309 VALUE tmp = Qnil;
4310
4311 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4312 rs = tmp;
4313 }
4314 else {
4315 lim = argv[0];
4316 }
4317 }
4318 else if (2 <= argc) {
4319 rs = argv[0], lim = argv[1];
4320 if (!NIL_P(rs))
4321 StringValue(rs);
4322 }
4323 args->rs = rs;
4324 args->limit = NIL_P(lim) ? -1L : NUM2LEN(lim);
4325}
4326
4327static void
4328check_getline_args(VALUE *rsp, rb_len_t *limit, VALUE io)
4329{
4330 rb_io_t *fptr;
4331 VALUE rs = *rsp;
4332
4333 if (!NIL_P(rs)) {
4334 rb_encoding *enc_rs, *enc_io;
4335
4336 GetOpenFile(io, fptr);
4337 enc_rs = rb_enc_get(rs);
4338 enc_io = io_read_encoding(fptr);
4339 if (enc_io != enc_rs &&
4340 (!is_ascii_string(rs) ||
4341 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4342 if (rs == rb_default_rs) {
4343 rs = rb_enc_str_new(0, 0, enc_io);
4344 rb_str_buf_cat_ascii(rs, "\n");
4345 *rsp = rs;
4346 }
4347 else {
4348 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4349 rb_enc_name(enc_io),
4350 rb_enc_name(enc_rs));
4351 }
4352 }
4353 }
4354}
4355
4356static void
4357prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4358{
4359 VALUE opts;
4360 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4361 extract_getline_args(argc, argv, args);
4362 extract_getline_opts(opts, args);
4363 check_getline_args(&args->rs, &args->limit, io);
4364}
4365
4366static VALUE
4367rb_io_getline_0(VALUE rs, rb_len_t limit, int chomp, rb_io_t *fptr)
4368{
4369 VALUE str = Qnil;
4370 int nolimit = 0;
4371 rb_encoding *enc;
4372
4374 if (NIL_P(rs) && limit < 0) {
4375 str = read_all(fptr, 0, Qnil);
4376 if (RSTRING_LEN(str) == 0) return Qnil;
4377 }
4378 else if (limit == 0) {
4379 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4380 }
4381 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4382 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4383 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4384 return rb_io_getline_fast(fptr, enc, chomp);
4385 }
4386 else {
4387 int c, newline = -1;
4388 const char *rsptr = 0;
4389 rb_len_t rslen = 0;
4390 int rspara = 0;
4391 int extra_limit = 16;
4392 int chomp_cr = chomp;
4393
4394 SET_BINARY_MODE(fptr);
4395 enc = io_read_encoding(fptr);
4396
4397 if (!NIL_P(rs)) {
4398 rslen = RSTRING_LEN(rs);
4399 if (rslen == 0) {
4400 rsptr = "\n\n";
4401 rslen = 2;
4402 rspara = 1;
4403 swallow(fptr, '\n');
4404 rs = 0;
4405 if (!rb_enc_asciicompat(enc)) {
4406 rs = rb_usascii_str_new(rsptr, rslen);
4407 rs = rb_str_conv_enc(rs, 0, enc);
4408 OBJ_FREEZE(rs);
4409 rsptr = RSTRING_PTR(rs);
4410 rslen = RSTRING_LEN(rs);
4411 }
4412 newline = '\n';
4413 }
4414 else if (rb_enc_mbminlen(enc) == 1) {
4415 rsptr = RSTRING_PTR(rs);
4416 newline = (unsigned char)rsptr[rslen - 1];
4417 }
4418 else {
4419 rs = rb_str_conv_enc(rs, 0, enc);
4420 rsptr = RSTRING_PTR(rs);
4421 const char *e = rsptr + rslen;
4422 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4423 int n;
4424 newline = rb_enc_codepoint_len(last, e, &n, enc);
4425 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4426 }
4427 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4428 }
4429
4430 /* MS - Optimization */
4431 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4432 const char *s, *p, *pp, *e;
4433
4434 if (c == newline && RSTRING_LEN(str) >= rslen) {
4435 s = RSTRING_PTR(str);
4436 e = RSTRING_END(str);
4437 p = e - rslen;
4438 if (at_char_boundary(s, p, e, enc)) {
4439 if (!rspara) rscheck(rsptr, rslen, rs);
4440 if (memcmp(p, rsptr, rslen) == 0) {
4441 if (chomp) {
4442 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4443 rb_str_set_len(str, p - s);
4444 }
4445 break;
4446 }
4447 }
4448 }
4449 if (limit == 0) {
4450 s = RSTRING_PTR(str);
4451 p = RSTRING_END(str);
4452 pp = rb_enc_prev_char(s, p, p, enc);
4453 if (extra_limit && pp &&
4454 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4455 /* relax the limit while incomplete character.
4456 * extra_limit limits the relax length */
4457 limit = 1;
4458 extra_limit--;
4459 }
4460 else {
4461 nolimit = 1;
4462 break;
4463 }
4464 }
4465 }
4466
4467 if (rspara && c != EOF)
4468 swallow(fptr, '\n');
4469 if (!NIL_P(str))
4470 str = io_enc_str(str, fptr);
4471 }
4472
4473 if (!NIL_P(str) && !nolimit) {
4474 fptr->lineno++;
4475 }
4476
4477 return str;
4478}
4479
4480static VALUE
4481rb_io_getline_1(VALUE rs, rb_len_t limit, int chomp, VALUE io)
4482{
4483 rb_io_t *fptr;
4484 int old_lineno, new_lineno;
4485 VALUE str;
4486
4487 GetOpenFile(io, fptr);
4488 old_lineno = fptr->lineno;
4489 str = rb_io_getline_0(rs, limit, chomp, fptr);
4490 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4491 if (io == ARGF.current_file) {
4492 ARGF.lineno += new_lineno - old_lineno;
4493 ARGF.last_lineno = ARGF.lineno;
4494 }
4495 else {
4496 ARGF.last_lineno = new_lineno;
4497 }
4498 }
4499
4500 return str;
4501}
4502
4503static VALUE
4504rb_io_getline(int argc, VALUE *argv, VALUE io)
4505{
4506 struct getline_arg args;
4507
4508 prepare_getline_args(argc, argv, &args, io);
4509 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4510}
4511
4512VALUE
4514{
4515 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4516}
4517
4518VALUE
4519rb_io_gets_limit_internal(VALUE io, rb_len_t limit)
4520{
4521 rb_io_t *fptr;
4522 GetOpenFile(io, fptr);
4523 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4524}
4525
4526VALUE
4527rb_io_gets_internal(VALUE io)
4528{
4529 return rb_io_gets_limit_internal(io, -1);
4530}
4531
4532/*
4533 * call-seq:
4534 * gets(sep = $/, chomp: false) -> string or nil
4535 * gets(limit, chomp: false) -> string or nil
4536 * gets(sep, limit, chomp: false) -> string or nil
4537 *
4538 * Reads and returns a line from the stream;
4539 * assigns the return value to <tt>$_</tt>.
4540 * See {Line IO}[rdoc-ref:IO@Line+IO].
4541 *
4542 * With no arguments given, returns the next line
4543 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4544 *
4545 * f = File.open('t.txt')
4546 * f.gets # => "First line\n"
4547 * $_ # => "First line\n"
4548 * f.gets # => "\n"
4549 * f.gets # => "Fourth line\n"
4550 * f.gets # => "Fifth line\n"
4551 * f.gets # => nil
4552 * f.close
4553 *
4554 * With only string argument +sep+ given,
4555 * returns the next line as determined by line separator +sep+,
4556 * or +nil+ if none;
4557 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4558 *
4559 * f = File.new('t.txt')
4560 * f.gets('l') # => "First l"
4561 * f.gets('li') # => "ine\nSecond li"
4562 * f.gets('lin') # => "ne\n\nFourth lin"
4563 * f.gets # => "e\n"
4564 * f.close
4565 *
4566 * The two special values for +sep+ are honored:
4567 *
4568 * f = File.new('t.txt')
4569 * # Get all.
4570 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4571 * f.rewind
4572 * # Get paragraph (up to two line separators).
4573 * f.gets('') # => "First line\nSecond line\n\n"
4574 * f.close
4575 *
4576 * With only integer argument +limit+ given,
4577 * limits the number of bytes in the line;
4578 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4579 *
4580 * # No more than one line.
4581 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4582 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4583 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4584 *
4585 * With arguments +sep+ and +limit+ given,
4586 * combines the two behaviors
4587 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4588 *
4589 * Optional keyword argument +chomp+ specifies whether line separators
4590 * are to be omitted:
4591 *
4592 * f = File.open('t.txt')
4593 * # Chomp the lines.
4594 * f.gets(chomp: true) # => "First line"
4595 * f.gets(chomp: true) # => "Second line"
4596 * f.gets(chomp: true) # => ""
4597 * f.gets(chomp: true) # => "Fourth line"
4598 * f.gets(chomp: true) # => "Fifth line"
4599 * f.gets(chomp: true) # => nil
4600 * f.close
4601 *
4602 */
4603
4604static VALUE
4605rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4606{
4607 VALUE str;
4608
4609 str = rb_io_getline(argc, argv, io);
4610 rb_lastline_set(str);
4611
4612 return str;
4613}
4614
4615/*
4616 * call-seq:
4617 * lineno -> integer
4618 *
4619 * Returns the current line number for the stream;
4620 * see {Line Number}[rdoc-ref:IO@Line+Number].
4621 *
4622 */
4623
4624static VALUE
4625rb_io_lineno(VALUE io)
4626{
4627 rb_io_t *fptr;
4628
4629 GetOpenFile(io, fptr);
4631 return INT2NUM(fptr->lineno);
4632}
4633
4634/*
4635 * call-seq:
4636 * lineno = integer -> integer
4637 *
4638 * Sets and returns the line number for the stream;
4639 * see {Line Number}[rdoc-ref:IO@Line+Number].
4640 *
4641 */
4642
4643static VALUE
4644rb_io_set_lineno(VALUE io, VALUE lineno)
4645{
4646 rb_io_t *fptr;
4647
4648 GetOpenFile(io, fptr);
4650 fptr->lineno = NUM2INT(lineno);
4651 return lineno;
4652}
4653
4654/* :nodoc: */
4655static VALUE
4656io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4657{
4658 rb_len_t limit = -1;
4659 if (NIL_P(lim)) {
4660 VALUE tmp = Qnil;
4661 // If sep is specified, but it's not a string and not nil, then assume
4662 // it's the limit (it should be an integer)
4663 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4664 // If the user has specified a non-nil / non-string value
4665 // for the separator, we assume it's the limit and set the
4666 // separator to default: rb_rs.
4667 lim = sep;
4668 limit = NUM2LEN(lim);
4669 sep = rb_rs;
4670 }
4671 else {
4672 sep = tmp;
4673 }
4674 }
4675 else {
4676 if (!NIL_P(sep)) StringValue(sep);
4677 limit = NUM2LEN(lim);
4678 }
4679
4680 check_getline_args(&sep, &limit, io);
4681
4682 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4683 rb_lastline_set_up(line, 1);
4684
4685 if (NIL_P(line)) {
4686 rb_eof_error();
4687 }
4688 return line;
4689}
4690
4691static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4692
4693/*
4694 * call-seq:
4695 * readlines(sep = $/, chomp: false) -> array
4696 * readlines(limit, chomp: false) -> array
4697 * readlines(sep, limit, chomp: false) -> array
4698 *
4699 * Reads and returns all remaining line from the stream;
4700 * does not modify <tt>$_</tt>.
4701 * See {Line IO}[rdoc-ref:IO@Line+IO].
4702 *
4703 * With no arguments given, returns lines
4704 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4705 *
4706 * f = File.new('t.txt')
4707 * f.readlines
4708 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4709 * f.readlines # => []
4710 * f.close
4711 *
4712 * With only string argument +sep+ given,
4713 * returns lines as determined by line separator +sep+,
4714 * or +nil+ if none;
4715 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4716 *
4717 * f = File.new('t.txt')
4718 * f.readlines('li')
4719 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4720 * f.close
4721 *
4722 * The two special values for +sep+ are honored:
4723 *
4724 * f = File.new('t.txt')
4725 * # Get all into one string.
4726 * f.readlines(nil)
4727 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4728 * # Get paragraphs (up to two line separators).
4729 * f.rewind
4730 * f.readlines('')
4731 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4732 * f.close
4733 *
4734 * With only integer argument +limit+ given,
4735 * limits the number of bytes in each line;
4736 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4737 *
4738 * f = File.new('t.txt')
4739 * f.readlines(8)
4740 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4741 * f.close
4742 *
4743 * With arguments +sep+ and +limit+ given,
4744 * combines the two behaviors
4745 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4746 *
4747 * Optional keyword argument +chomp+ specifies whether line separators
4748 * are to be omitted:
4749 *
4750 * f = File.new('t.txt')
4751 * f.readlines(chomp: true)
4752 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4753 * f.close
4754 *
4755 */
4756
4757static VALUE
4758rb_io_readlines(int argc, VALUE *argv, VALUE io)
4759{
4760 struct getline_arg args;
4761
4762 prepare_getline_args(argc, argv, &args, io);
4763 return io_readlines(&args, io);
4764}
4765
4766static VALUE
4767io_readlines(const struct getline_arg *arg, VALUE io)
4768{
4769 VALUE line, ary;
4770
4771 if (arg->limit == 0)
4772 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4773 ary = rb_ary_new();
4774 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4775 rb_ary_push(ary, line);
4776 }
4777 return ary;
4778}
4779
4780/*
4781 * call-seq:
4782 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4783 * each_line(limit, chomp: false) {|line| ... } -> self
4784 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4785 * each_line -> enumerator
4786 *
4787 * Calls the block with each remaining line read from the stream;
4788 * returns +self+.
4789 * Does nothing if already at end-of-stream;
4790 * See {Line IO}[rdoc-ref:IO@Line+IO].
4791 *
4792 * With no arguments given, reads lines
4793 * as determined by line separator <tt>$/</tt>:
4794 *
4795 * f = File.new('t.txt')
4796 * f.each_line {|line| p line }
4797 * f.each_line {|line| fail 'Cannot happen' }
4798 * f.close
4799 *
4800 * Output:
4801 *
4802 * "First line\n"
4803 * "Second line\n"
4804 * "\n"
4805 * "Fourth line\n"
4806 * "Fifth line\n"
4807 *
4808 * With only string argument +sep+ given,
4809 * reads lines as determined by line separator +sep+;
4810 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4811 *
4812 * f = File.new('t.txt')
4813 * f.each_line('li') {|line| p line }
4814 * f.close
4815 *
4816 * Output:
4817 *
4818 * "First li"
4819 * "ne\nSecond li"
4820 * "ne\n\nFourth li"
4821 * "ne\nFifth li"
4822 * "ne\n"
4823 *
4824 * The two special values for +sep+ are honored:
4825 *
4826 * f = File.new('t.txt')
4827 * # Get all into one string.
4828 * f.each_line(nil) {|line| p line }
4829 * f.close
4830 *
4831 * Output:
4832 *
4833 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4834 *
4835 * f.rewind
4836 * # Get paragraphs (up to two line separators).
4837 * f.each_line('') {|line| p line }
4838 *
4839 * Output:
4840 *
4841 * "First line\nSecond line\n\n"
4842 * "Fourth line\nFifth line\n"
4843 *
4844 * With only integer argument +limit+ given,
4845 * limits the number of bytes in each line;
4846 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4847 *
4848 * f = File.new('t.txt')
4849 * f.each_line(8) {|line| p line }
4850 * f.close
4851 *
4852 * Output:
4853 *
4854 * "First li"
4855 * "ne\n"
4856 * "Second l"
4857 * "ine\n"
4858 * "\n"
4859 * "Fourth l"
4860 * "ine\n"
4861 * "Fifth li"
4862 * "ne\n"
4863 *
4864 * With arguments +sep+ and +limit+ given,
4865 * combines the two behaviors
4866 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4867 *
4868 * Optional keyword argument +chomp+ specifies whether line separators
4869 * are to be omitted:
4870 *
4871 * f = File.new('t.txt')
4872 * f.each_line(chomp: true) {|line| p line }
4873 * f.close
4874 *
4875 * Output:
4876 *
4877 * "First line"
4878 * "Second line"
4879 * ""
4880 * "Fourth line"
4881 * "Fifth line"
4882 *
4883 * Returns an Enumerator if no block is given.
4884 */
4885
4886static VALUE
4887rb_io_each_line(int argc, VALUE *argv, VALUE io)
4888{
4889 VALUE str;
4890 struct getline_arg args;
4891
4892 RETURN_ENUMERATOR(io, argc, argv);
4893 prepare_getline_args(argc, argv, &args, io);
4894 if (args.limit == 0)
4895 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4896 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4897 rb_yield(str);
4898 }
4899 return io;
4900}
4901
4902/*
4903 * call-seq:
4904 * each_byte {|byte| ... } -> self
4905 * each_byte -> enumerator
4906 *
4907 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4908 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4909 *
4910 * File.read('t.ja') # => "こんにちは"
4911 * f = File.new('t.ja')
4912 * a = []
4913 * f.each_byte {|b| a << b }
4914 * a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
4915 * f.close
4916 *
4917 * Returns an Enumerator if no block is given.
4918 *
4919 * Related: IO#each_char, IO#each_codepoint.
4920 *
4921 */
4922
4923static VALUE
4924rb_io_each_byte(VALUE io)
4925{
4926 rb_io_t *fptr;
4927
4928 RETURN_ENUMERATOR(io, 0, 0);
4929 GetOpenFile(io, fptr);
4930
4931 do {
4932 while (fptr->rbuf.len > 0) {
4933 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4934 fptr->rbuf.len--;
4935 rb_yield(INT2FIX(*p & 0xff));
4937 errno = 0;
4938 }
4939 READ_CHECK(fptr);
4940 } while (io_fillbuf(fptr) >= 0);
4941 return io;
4942}
4943
4944static VALUE
4945io_getc(rb_io_t *fptr, rb_encoding *enc)
4946{
4947 int r, n, cr = 0;
4948 VALUE str;
4949
4950 if (NEED_READCONV(fptr)) {
4951 rb_encoding *read_enc = io_read_encoding(fptr);
4952
4953 str = Qnil;
4954 SET_BINARY_MODE(fptr);
4955 make_readconv(fptr, 0);
4956
4957 while (1) {
4958 if (fptr->cbuf.len) {
4959 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4960 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4961 read_enc);
4962 if (!MBCLEN_NEEDMORE_P(r))
4963 break;
4964 if (fptr->cbuf.len == fptr->cbuf.capa) {
4965 rb_raise(rb_eIOError, "too long character");
4966 }
4967 }
4968
4969 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4970 if (fptr->cbuf.len == 0) {
4971 clear_readconv(fptr);
4972 return Qnil;
4973 }
4974 /* return an unit of an incomplete character just before EOF */
4975 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4976 fptr->cbuf.off += 1;
4977 fptr->cbuf.len -= 1;
4978 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4980 return str;
4981 }
4982 }
4983 if (MBCLEN_INVALID_P(r)) {
4984 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4985 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4986 read_enc);
4987 io_shift_cbuf(fptr, r, &str);
4989 }
4990 else {
4991 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4993 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4994 ISASCII(RSTRING_PTR(str)[0])) {
4995 cr = ENC_CODERANGE_7BIT;
4996 }
4997 }
4998 str = io_enc_str(str, fptr);
4999 ENC_CODERANGE_SET(str, cr);
5000 return str;
5001 }
5002
5003 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5004 if (io_fillbuf(fptr) < 0) {
5005 return Qnil;
5006 }
5007 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
5008 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
5009 fptr->rbuf.off += 1;
5010 fptr->rbuf.len -= 1;
5011 cr = ENC_CODERANGE_7BIT;
5012 }
5013 else {
5014 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5015 if (MBCLEN_CHARFOUND_P(r) &&
5016 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
5017 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
5018 fptr->rbuf.off += n;
5019 fptr->rbuf.len -= n;
5021 }
5022 else if (MBCLEN_NEEDMORE_P(r)) {
5023 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
5024 fptr->rbuf.len = 0;
5025 getc_needmore:
5026 if (io_fillbuf(fptr) != -1) {
5027 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
5028 fptr->rbuf.off++;
5029 fptr->rbuf.len--;
5030 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
5031 if (MBCLEN_NEEDMORE_P(r)) {
5032 goto getc_needmore;
5033 }
5034 else if (MBCLEN_CHARFOUND_P(r)) {
5036 }
5037 }
5038 }
5039 else {
5040 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
5041 fptr->rbuf.off++;
5042 fptr->rbuf.len--;
5043 }
5044 }
5045 if (!cr) cr = ENC_CODERANGE_BROKEN;
5046 str = io_enc_str(str, fptr);
5047 ENC_CODERANGE_SET(str, cr);
5048 return str;
5049}
5050
5051/*
5052 * call-seq:
5053 * each_char {|c| ... } -> self
5054 * each_char -> enumerator
5055 *
5056 * Calls the given block with each character in the stream; returns +self+.
5057 * See {Character IO}[rdoc-ref:IO@Character+IO].
5058 *
5059 * File.read('t.ja') # => "こんにちは"
5060 * f = File.new('t.ja')
5061 * a = []
5062 * f.each_char {|c| a << c.ord }
5063 * a # => [12371, 12435, 12395, 12385, 12399]
5064 * f.close
5065 *
5066 * Returns an Enumerator if no block is given.
5067 *
5068 * Related: IO#each_byte, IO#each_codepoint.
5069 *
5070 */
5071
5072static VALUE
5073rb_io_each_char(VALUE io)
5074{
5075 rb_io_t *fptr;
5076 rb_encoding *enc;
5077 VALUE c;
5078
5079 RETURN_ENUMERATOR(io, 0, 0);
5080 GetOpenFile(io, fptr);
5082
5083 enc = io_input_encoding(fptr);
5084 READ_CHECK(fptr);
5085 while (!NIL_P(c = io_getc(fptr, enc))) {
5086 rb_yield(c);
5087 }
5088 return io;
5089}
5090
5091/*
5092 * call-seq:
5093 * each_codepoint {|c| ... } -> self
5094 * each_codepoint -> enumerator
5095 *
5096 * Calls the given block with each codepoint in the stream; returns +self+:
5097 *
5098 * File.read('t.ja') # => "こんにちは"
5099 * f = File.new('t.ja')
5100 * a = []
5101 * f.each_codepoint {|c| a << c }
5102 * a # => [12371, 12435, 12395, 12385, 12399]
5103 * f.close
5104 *
5105 * Returns an Enumerator if no block is given.
5106 *
5107 * Related: IO#each_byte, IO#each_char.
5108 *
5109 */
5110
5111static VALUE
5112rb_io_each_codepoint(VALUE io)
5113{
5114 rb_io_t *fptr;
5115 rb_encoding *enc;
5116 unsigned int c;
5117 int r, n;
5118
5119 RETURN_ENUMERATOR(io, 0, 0);
5120 GetOpenFile(io, fptr);
5122
5123 READ_CHECK(fptr);
5124 enc = io_read_encoding(fptr);
5125 if (NEED_READCONV(fptr)) {
5126 SET_BINARY_MODE(fptr);
5127 r = 1; /* no invalid char yet */
5128 for (;;) {
5129 make_readconv(fptr, 0);
5130 for (;;) {
5131 if (fptr->cbuf.len) {
5132 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
5133 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5134 enc);
5135 if (!MBCLEN_NEEDMORE_P(r))
5136 break;
5137 if (fptr->cbuf.len == fptr->cbuf.capa) {
5138 rb_raise(rb_eIOError, "too long character");
5139 }
5140 }
5141 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5142 clear_readconv(fptr);
5143 if (!MBCLEN_CHARFOUND_P(r)) {
5144 goto invalid;
5145 }
5146 return io;
5147 }
5148 }
5149 if (MBCLEN_INVALID_P(r)) {
5150 goto invalid;
5151 }
5152 n = MBCLEN_CHARFOUND_LEN(r);
5153 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
5154 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5155 enc);
5156 fptr->cbuf.off += n;
5157 fptr->cbuf.len -= n;
5158 rb_yield(UINT2NUM(c));
5160 }
5161 }
5162 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5163 while (io_fillbuf(fptr) >= 0) {
5164 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
5165 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5166 if (MBCLEN_CHARFOUND_P(r) &&
5167 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
5168 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
5169 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5170 fptr->rbuf.off += n;
5171 fptr->rbuf.len -= n;
5172 rb_yield(UINT2NUM(c));
5173 }
5174 else if (MBCLEN_INVALID_P(r)) {
5175 goto invalid;
5176 }
5177 else if (MBCLEN_NEEDMORE_P(r)) {
5178 char cbuf[8], *p = cbuf;
5179 int more = MBCLEN_NEEDMORE_LEN(r);
5180 if (more > numberof(cbuf)) goto invalid;
5181 more += n = fptr->rbuf.len;
5182 if (more > numberof(cbuf)) goto invalid;
5183 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
5184 (p += n, (more -= n) > 0)) {
5185 if (io_fillbuf(fptr) < 0) goto invalid;
5186 if ((n = fptr->rbuf.len) > more) n = more;
5187 }
5188 r = rb_enc_precise_mbclen(cbuf, p, enc);
5189 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
5190 c = rb_enc_codepoint(cbuf, p, enc);
5191 rb_yield(UINT2NUM(c));
5192 }
5193 else {
5194 continue;
5195 }
5197 }
5198 return io;
5199
5200 invalid:
5201 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
5203}
5204
5205/*
5206 * call-seq:
5207 * getc -> character or nil
5208 *
5209 * Reads and returns the next 1-character string from the stream;
5210 * returns +nil+ if already at end-of-stream.
5211 * See {Character IO}[rdoc-ref:IO@Character+IO].
5212 *
5213 * f = File.open('t.txt')
5214 * f.getc # => "F"
5215 * f.close
5216 * File.read('t.ja') # => "こんにちは"
5217 * f = File.open('t.ja')
5218 * f.getc.ord # => 12371
5219 * f.close
5220 *
5221 * Related: IO#readchar (may raise EOFError).
5222 *
5223 */
5224
5225static VALUE
5226rb_io_getc(VALUE io)
5227{
5228 rb_io_t *fptr;
5229 rb_encoding *enc;
5230
5231 GetOpenFile(io, fptr);
5233
5234 enc = io_input_encoding(fptr);
5235 READ_CHECK(fptr);
5236 return io_getc(fptr, enc);
5237}
5238
5239/*
5240 * call-seq:
5241 * readchar -> string
5242 *
5243 * Reads and returns the next 1-character string from the stream;
5244 * raises EOFError if already at end-of-stream.
5245 * See {Character IO}[rdoc-ref:IO@Character+IO].
5246 *
5247 * f = File.open('t.txt')
5248 * f.readchar # => "F"
5249 * f.close
5250 * File.read('t.ja') # => "こんにちは"
5251 * f = File.open('t.ja')
5252 * f.readchar.ord # => 12371
5253 * f.close
5254 *
5255 * Related: IO#getc (will not raise EOFError).
5256 *
5257 */
5258
5259static VALUE
5260rb_io_readchar(VALUE io)
5261{
5262 VALUE c = rb_io_getc(io);
5263
5264 if (NIL_P(c)) {
5265 rb_eof_error();
5266 }
5267 return c;
5268}
5269
5270/*
5271 * call-seq:
5272 * getbyte -> integer or nil
5273 *
5274 * Reads and returns the next byte (in range 0..255) from the stream;
5275 * returns +nil+ if already at end-of-stream.
5276 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5277 *
5278 * f = File.open('t.txt')
5279 * f.getbyte # => 70
5280 * f.close
5281 * File.read('t.ja') # => "こんにちは"
5282 * f = File.open('t.ja')
5283 * f.getbyte # => 227
5284 * f.close
5285 *
5286 * Related: IO#readbyte (may raise EOFError).
5287 */
5288
5289VALUE
5291{
5292 rb_io_t *fptr;
5293 int c;
5294
5295 GetOpenFile(io, fptr);
5297 READ_CHECK(fptr);
5298 VALUE r_stdout = rb_ractor_stdout();
5299 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5300 rb_io_t *ofp;
5301 GetOpenFile(r_stdout, ofp);
5302 if (ofp->mode & FMODE_TTY) {
5303 rb_io_flush(r_stdout);
5304 }
5305 }
5306 if (io_fillbuf(fptr) < 0) {
5307 return Qnil;
5308 }
5309 fptr->rbuf.off++;
5310 fptr->rbuf.len--;
5311 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5312 return INT2FIX(c & 0xff);
5313}
5314
5315/*
5316 * call-seq:
5317 * readbyte -> integer
5318 *
5319 * Reads and returns the next byte (in range 0..255) from the stream;
5320 * raises EOFError if already at end-of-stream.
5321 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5322 *
5323 * f = File.open('t.txt')
5324 * f.readbyte # => 70
5325 * f.close
5326 * File.read('t.ja') # => "こんにちは"
5327 * f = File.open('t.ja')
5328 * f.readbyte # => 227
5329 * f.close
5330 *
5331 * Related: IO#getbyte (will not raise EOFError).
5332 *
5333 */
5334
5335static VALUE
5336rb_io_readbyte(VALUE io)
5337{
5338 VALUE c = rb_io_getbyte(io);
5339
5340 if (NIL_P(c)) {
5341 rb_eof_error();
5342 }
5343 return c;
5344}
5345
5346/*
5347 * call-seq:
5348 * ungetbyte(integer) -> nil
5349 * ungetbyte(string) -> nil
5350 *
5351 * Pushes back ("unshifts") the given data onto the stream's buffer,
5352 * placing the data so that it is next to be read; returns +nil+.
5353 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5354 *
5355 * Note that:
5356 *
5357 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5358 * - Calling #rewind on the stream discards the pushed-back data.
5359 *
5360 * When argument +integer+ is given, uses only its low-order byte:
5361 *
5362 * File.write('t.tmp', '012')
5363 * f = File.open('t.tmp')
5364 * f.ungetbyte(0x41) # => nil
5365 * f.read # => "A012"
5366 * f.rewind
5367 * f.ungetbyte(0x4243) # => nil
5368 * f.read # => "C012"
5369 * f.close
5370 *
5371 * When argument +string+ is given, uses all bytes:
5372 *
5373 * File.write('t.tmp', '012')
5374 * f = File.open('t.tmp')
5375 * f.ungetbyte('A') # => nil
5376 * f.read # => "A012"
5377 * f.rewind
5378 * f.ungetbyte('BCDE') # => nil
5379 * f.read # => "BCDE012"
5380 * f.close
5381 *
5382 */
5383
5384VALUE
5386{
5387 rb_io_t *fptr;
5388
5389 GetOpenFile(io, fptr);
5391 switch (TYPE(b)) {
5392 case T_NIL:
5393 return Qnil;
5394 case T_FIXNUM:
5395 case T_BIGNUM: ;
5396 VALUE v = rb_int_modulo(b, INT2FIX(256));
5397 unsigned char c = NUM2INT(v) & 0xFF;
5398 b = rb_str_new((const char *)&c, 1);
5399 break;
5400 default:
5401 StringValue(b);
5402 }
5403 io_ungetbyte(b, fptr);
5404 return Qnil;
5405}
5406
5407/*
5408 * call-seq:
5409 * ungetc(integer) -> nil
5410 * ungetc(string) -> nil
5411 *
5412 * Pushes back ("unshifts") the given data onto the stream's buffer,
5413 * placing the data so that it is next to be read; returns +nil+.
5414 * See {Character IO}[rdoc-ref:IO@Character+IO].
5415 *
5416 * Note that:
5417 *
5418 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5419 * - Calling #rewind on the stream discards the pushed-back data.
5420 *
5421 * When argument +integer+ is given, interprets the integer as a character:
5422 *
5423 * File.write('t.tmp', '012')
5424 * f = File.open('t.tmp')
5425 * f.ungetc(0x41) # => nil
5426 * f.read # => "A012"
5427 * f.rewind
5428 * f.ungetc(0x0442) # => nil
5429 * f.getc.ord # => 1090
5430 * f.close
5431 *
5432 * When argument +string+ is given, uses all characters:
5433 *
5434 * File.write('t.tmp', '012')
5435 * f = File.open('t.tmp')
5436 * f.ungetc('A') # => nil
5437 * f.read # => "A012"
5438 * f.rewind
5439 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5440 * f.getc.ord # => 1090
5441 * f.getc.ord # => 1077
5442 * f.getc.ord # => 1089
5443 * f.getc.ord # => 1090
5444 * f.close
5445 *
5446 */
5447
5448VALUE
5450{
5451 rb_io_t *fptr;
5452 rb_len_t len;
5453
5454 GetOpenFile(io, fptr);
5456 if (FIXNUM_P(c)) {
5457 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5458 }
5459 else if (RB_BIGNUM_TYPE_P(c)) {
5460 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5461 }
5462 else {
5463 StringValue(c);
5464 }
5465 if (NEED_READCONV(fptr)) {
5466 SET_BINARY_MODE(fptr);
5467 len = RSTRING_LEN(c);
5468#if SIZEOF_RB_LEN_T > SIZEOF_INT
5469 if (len > INT_MAX)
5470 rb_raise(rb_eIOError, "ungetc failed");
5471#endif
5472 make_readconv(fptr, (int)len);
5473 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5474 rb_raise(rb_eIOError, "ungetc failed");
5475 if (fptr->cbuf.off < len) {
5476 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5477 fptr->cbuf.ptr+fptr->cbuf.off,
5478 char, fptr->cbuf.len);
5479 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5480 }
5481 fptr->cbuf.off -= (int)len;
5482 fptr->cbuf.len += (int)len;
5483 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5484 }
5485 else {
5486 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5487 io_ungetbyte(c, fptr);
5488 }
5489 return Qnil;
5490}
5491
5492/*
5493 * call-seq:
5494 * isatty -> true or false
5495 *
5496 * Returns +true+ if the stream is associated with a terminal device (tty),
5497 * +false+ otherwise:
5498 *
5499 * f = File.new('t.txt').isatty #=> false
5500 * f.close
5501 * f = File.new('/dev/tty').isatty #=> true
5502 * f.close
5503 *
5504 */
5505
5506static VALUE
5507rb_io_isatty(VALUE io)
5508{
5509 rb_io_t *fptr;
5510
5511 GetOpenFile(io, fptr);
5512 return RBOOL(isatty(fptr->fd) != 0);
5513}
5514
5515#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5516/*
5517 * call-seq:
5518 * close_on_exec? -> true or false
5519 *
5520 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5521 *
5522 * f = File.open('t.txt')
5523 * f.close_on_exec? # => true
5524 * f.close_on_exec = false
5525 * f.close_on_exec? # => false
5526 * f.close
5527 *
5528 */
5529
5530static VALUE
5531rb_io_close_on_exec_p(VALUE io)
5532{
5533 rb_io_t *fptr;
5534 VALUE write_io;
5535 int fd, ret;
5536
5537 write_io = GetWriteIO(io);
5538 if (io != write_io) {
5539 GetOpenFile(write_io, fptr);
5540 if (fptr && 0 <= (fd = fptr->fd)) {
5541 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5542 if (!(ret & FD_CLOEXEC)) return Qfalse;
5543 }
5544 }
5545
5546 GetOpenFile(io, fptr);
5547 if (fptr && 0 <= (fd = fptr->fd)) {
5548 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5549 if (!(ret & FD_CLOEXEC)) return Qfalse;
5550 }
5551 return Qtrue;
5552}
5553#else
5554#define rb_io_close_on_exec_p rb_f_notimplement
5555#endif
5556
5557#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5558/*
5559 * call-seq:
5560 * self.close_on_exec = bool -> true or false
5561 *
5562 * Sets a close-on-exec flag.
5563 *
5564 * f = File.open(File::NULL)
5565 * f.close_on_exec = true
5566 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5567 * f.closed? #=> false
5568 *
5569 * Ruby sets close-on-exec flags of all file descriptors by default
5570 * since Ruby 2.0.0.
5571 * So you don't need to set by yourself.
5572 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5573 * if another thread use fork() and exec() (via system() method for example).
5574 * If you really needs file descriptor inheritance to child process,
5575 * use spawn()'s argument such as fd=>fd.
5576 */
5577
5578static VALUE
5579rb_io_set_close_on_exec(VALUE io, VALUE arg)
5580{
5581 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5582 rb_io_t *fptr;
5583 VALUE write_io;
5584 int fd, ret;
5585
5586 write_io = GetWriteIO(io);
5587 if (io != write_io) {
5588 GetOpenFile(write_io, fptr);
5589 if (fptr && 0 <= (fd = fptr->fd)) {
5590 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5591 if ((ret & FD_CLOEXEC) != flag) {
5592 ret = (ret & ~FD_CLOEXEC) | flag;
5593 ret = fcntl(fd, F_SETFD, ret);
5594 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5595 }
5596 }
5597
5598 }
5599
5600 GetOpenFile(io, fptr);
5601 if (fptr && 0 <= (fd = fptr->fd)) {
5602 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5603 if ((ret & FD_CLOEXEC) != flag) {
5604 ret = (ret & ~FD_CLOEXEC) | flag;
5605 ret = fcntl(fd, F_SETFD, ret);
5606 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5607 }
5608 }
5609 return Qnil;
5610}
5611#else
5612#define rb_io_set_close_on_exec rb_f_notimplement
5613#endif
5614
5615#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5616#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5617
5618static VALUE
5619finish_writeconv(rb_io_t *fptr, int noalloc)
5620{
5621 unsigned char *ds, *dp, *de;
5623
5624 if (!fptr->wbuf.ptr) {
5625 unsigned char buf[1024];
5626
5628 while (res == econv_destination_buffer_full) {
5629 ds = dp = buf;
5630 de = buf + sizeof(buf);
5631 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5632 while (dp-ds) {
5633 size_t remaining = dp-ds;
5634 rb_len_t result = rb_io_write_memory(fptr, ds, remaining);
5635
5636 if (result > 0) {
5637 ds += result;
5638 if ((size_t)result == remaining) break;
5639 }
5640 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5641 if (fptr->fd < 0)
5642 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5643 }
5644 else {
5645 return noalloc ? Qtrue : INT2NUM(errno);
5646 }
5647 }
5648 if (res == econv_invalid_byte_sequence ||
5649 res == econv_incomplete_input ||
5651 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5652 }
5653 }
5654
5655 return Qnil;
5656 }
5657
5659 while (res == econv_destination_buffer_full) {
5660 if (fptr->wbuf.len == fptr->wbuf.capa) {
5661 if (io_fflush(fptr) < 0) {
5662 return noalloc ? Qtrue : INT2NUM(errno);
5663 }
5664 }
5665
5666 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5667 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5668 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5669 fptr->wbuf.len += (int)(dp - ds);
5670 if (res == econv_invalid_byte_sequence ||
5671 res == econv_incomplete_input ||
5673 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5674 }
5675 }
5676 return Qnil;
5677}
5678
5680 rb_io_t *fptr;
5681 int noalloc;
5682};
5683
5684static VALUE
5685finish_writeconv_sync(VALUE arg)
5686{
5687 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5688 return finish_writeconv(p->fptr, p->noalloc);
5689}
5690
5691static void*
5692nogvl_close(void *ptr)
5693{
5694 int *fd = ptr;
5695
5696 return (void*)(intptr_t)close(*fd);
5697}
5698
5699static int
5700maygvl_close(int fd, int keepgvl)
5701{
5702 if (keepgvl)
5703 return close(fd);
5704
5705 /*
5706 * close() may block for certain file types (NFS, SO_LINGER sockets,
5707 * inotify), so let other threads run.
5708 */
5709 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5710}
5711
5712static void*
5713nogvl_fclose(void *ptr)
5714{
5715 FILE *file = ptr;
5716
5717 return (void*)(intptr_t)fclose(file);
5718}
5719
5720static int
5721maygvl_fclose(FILE *file, int keepgvl)
5722{
5723 if (keepgvl)
5724 return fclose(file);
5725
5726 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5727}
5728
5729static void free_io_buffer(rb_io_buffer_t *buf);
5730
5731static void
5732fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5733{
5734 VALUE error = Qnil;
5735 int fd = fptr->fd;
5736 FILE *stdio_file = fptr->stdio_file;
5737 int mode = fptr->mode;
5738
5739 if (fptr->writeconv) {
5740 if (!NIL_P(fptr->write_lock) && !noraise) {
5741 struct finish_writeconv_arg arg;
5742 arg.fptr = fptr;
5743 arg.noalloc = noraise;
5744 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5745 }
5746 else {
5747 error = finish_writeconv(fptr, noraise);
5748 }
5749 }
5750 /* Do not flush the write buffer on close when the stream is in sync
5751 * mode. In sync mode Ruby's write buffer is not authoritative (writes go
5752 * straight to the OS), so any bytes left in the buffer are the result of
5753 * writes made while sync was disabled. Setting sync = true is therefore a
5754 * way to abandon that pending output rather than replaying it on close,
5755 * which matters after an interrupted write where the amount actually
5756 * written is indeterminate. Call flush before enabling sync if the
5757 * buffered data should still be sent. */
5758 if (fptr->wbuf.len && !(fptr->mode & FMODE_SYNC)) {
5759 if (noraise) {
5760 io_flush_buffer_sync(fptr);
5761 }
5762 else {
5763 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5764 error = INT2NUM(errno);
5765 }
5766 }
5767 }
5768
5769 int done = 0;
5770
5771 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5772 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5773 done = 1;
5774 }
5775
5776 fptr->fd = -1;
5777 fptr->stdio_file = 0;
5779
5780 // Wait for blocking operations to ensure they do not hit EBADF:
5781 rb_thread_io_close_wait(fptr);
5782
5783 if (!done && stdio_file) {
5784 // stdio_file is deallocated anyway even if fclose failed.
5785 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5786 if (!noraise) {
5787 error = INT2NUM(errno);
5788 }
5789 }
5790
5791 done = 1;
5792 }
5793
5794 VALUE scheduler = rb_fiber_scheduler_current();
5795 if (!done && fd >= 0 && scheduler != Qnil) {
5796 VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
5797
5798 if (!UNDEF_P(result)) {
5799 done = RTEST(result);
5800 }
5801 }
5802
5803 if (!done && fd >= 0) {
5804 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5805 // We assumes it is closed.
5806
5807 keepgvl |= !(mode & FMODE_WRITABLE);
5808 keepgvl |= noraise;
5809 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5810 if (!noraise) {
5811 error = INT2NUM(errno);
5812 }
5813 }
5814
5815 done = 1;
5816 }
5817
5818 if (!NIL_P(error) && !noraise) {
5819 if (RB_INTEGER_TYPE_P(error))
5820 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5821 else
5822 rb_exc_raise(error);
5823 }
5824}
5825
5826static void
5827fptr_finalize(rb_io_t *fptr, int noraise)
5828{
5829 fptr_finalize_flush(fptr, noraise, FALSE);
5830 free_io_buffer(&fptr->rbuf);
5831 free_io_buffer(&fptr->wbuf);
5832 clear_codeconv(fptr);
5833}
5834
5835static void
5836rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5837{
5838 if (fptr->finalize) {
5839 (*fptr->finalize)(fptr, noraise);
5840 }
5841 else {
5842 fptr_finalize(fptr, noraise);
5843 }
5844}
5845
5846static void
5847free_io_buffer(rb_io_buffer_t *buf)
5848{
5849 if (buf->ptr) {
5850 ruby_xfree_sized(buf->ptr, (size_t)buf->capa);
5851 buf->ptr = NULL;
5852 }
5853 buf->off = buf->len = buf->capa = 0;
5854}
5855
5856static void
5857clear_readconv(rb_io_t *fptr)
5858{
5859 if (fptr->readconv) {
5860 rb_econv_close(fptr->readconv);
5861 fptr->readconv = NULL;
5862 }
5863 free_io_buffer(&fptr->cbuf);
5864}
5865
5866static void
5867clear_writeconv(rb_io_t *fptr)
5868{
5869 if (fptr->writeconv) {
5871 fptr->writeconv = NULL;
5872 }
5873 fptr->writeconv_initialized = 0;
5874}
5875
5876static void
5877clear_codeconv(rb_io_t *fptr)
5878{
5879 clear_readconv(fptr);
5880 clear_writeconv(fptr);
5881}
5882
5883static void
5884rb_io_fptr_cleanup_all(rb_io_t *fptr)
5885{
5886 fptr->pathv = Qnil;
5887 if (0 <= fptr->fd)
5888 rb_io_fptr_cleanup(fptr, TRUE);
5889 fptr->write_lock = Qnil;
5890 free_io_buffer(&fptr->rbuf);
5891 free_io_buffer(&fptr->wbuf);
5892 clear_codeconv(fptr);
5893}
5894
5895int
5897{
5898 if (!io) return 0;
5899 rb_io_fptr_cleanup_all(io);
5900 free(io);
5901
5902 return 1;
5903}
5904
5905bool
5906rb_io_fptr_finalize_closed(struct rb_io *io)
5907{
5908 if (!io) return true;
5909 if (io->fd >= 0) return false;
5911 return true;
5912}
5913
5914size_t
5915rb_io_memsize(const rb_io_t *io)
5916{
5917 size_t size = sizeof(rb_io_t);
5918 size += io->rbuf.capa;
5919 size += io->wbuf.capa;
5920 size += io->cbuf.capa;
5921 if (io->readconv) size += rb_econv_memsize(io->readconv);
5922 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5923
5924 struct rb_io_blocking_operation *blocking_operation = 0;
5925
5926 // 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.
5927 rb_serial_t fork_generation = GET_VM()->fork_gen;
5928 if (io->fork_generation == fork_generation) {
5929 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5930 size += sizeof(struct rb_io_blocking_operation);
5931 }
5932 }
5933
5934 return size;
5935}
5936
5937#ifdef _WIN32
5938/* keep GVL while closing to prevent crash on Windows */
5939# define KEEPGVL TRUE
5940#else
5941# define KEEPGVL FALSE
5942#endif
5943
5944static rb_io_t *
5945io_close_fptr(VALUE io)
5946{
5947 rb_io_t *fptr;
5948 VALUE write_io;
5949 rb_io_t *write_fptr;
5950
5951 write_io = GetWriteIO(io);
5952 if (io != write_io) {
5953 write_fptr = RFILE(write_io)->fptr;
5954 if (write_fptr && 0 <= write_fptr->fd) {
5955 rb_io_fptr_cleanup(write_fptr, TRUE);
5956 }
5957 }
5958
5959 fptr = RFILE(io)->fptr;
5960 if (!fptr) return 0;
5961 if (fptr->fd < 0) return 0;
5962
5963 // This guards against multiple threads closing the same IO object:
5964 if (rb_thread_io_close_interrupt(fptr)) {
5965 /* calls close(fptr->fd): */
5966 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5967 }
5968
5969 rb_io_fptr_cleanup(fptr, FALSE);
5970 return fptr;
5971}
5972
5973static void
5974fptr_waitpid(rb_io_t *fptr, int nohang)
5975{
5976 int status;
5977 if (fptr->pid) {
5978 rb_last_status_clear();
5979 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5980 fptr->pid = 0;
5981 }
5982}
5983
5984VALUE
5986{
5987 rb_io_t *fptr = io_close_fptr(io);
5988 if (fptr) fptr_waitpid(fptr, 0);
5989 return Qnil;
5990}
5991
5992/*
5993 * call-seq:
5994 * close -> nil
5995 *
5996 * Closes the stream for both reading and writing
5997 * if open for either or both; returns +nil+.
5998 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5999 *
6000 * If the stream is open for writing, flushes any buffered writes
6001 * to the operating system before closing.
6002 *
6003 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
6004 * (child exit status).
6005 *
6006 * It is not an error to close an IO object that has already been closed.
6007 * It just returns nil.
6008 *
6009 * Example:
6010 *
6011 * IO.popen('ruby', 'r+') do |pipe|
6012 * puts pipe.closed?
6013 * pipe.close
6014 * puts $?
6015 * puts pipe.closed?
6016 * end
6017 *
6018 * Output:
6019 *
6020 * false
6021 * pid 13760 exit 0
6022 * true
6023 *
6024 * Related: IO#close_read, IO#close_write, IO#closed?.
6025 */
6026
6027static VALUE
6028rb_io_close_m(VALUE io)
6029{
6030 rb_io_t *fptr = rb_io_get_fptr(io);
6031 if (fptr->fd < 0) {
6032 return Qnil;
6033 }
6034 rb_io_close(io);
6035 return Qnil;
6036}
6037
6038static VALUE
6039io_call_close(VALUE io)
6040{
6041 rb_check_funcall(io, rb_intern("close"), 0, 0);
6042 return io;
6043}
6044
6045static VALUE
6046ignore_closed_stream(VALUE io, VALUE exc)
6047{
6048 enum {mesg_len = sizeof(closed_stream)-1};
6049 VALUE mesg = rb_attr_get(exc, idMesg);
6050 if (!RB_TYPE_P(mesg, T_STRING) ||
6051 RSTRING_LEN(mesg) != mesg_len ||
6052 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
6053 rb_exc_raise(exc);
6054 }
6055 return io;
6056}
6057
6058static VALUE
6059io_close(VALUE io)
6060{
6061 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
6062 if (!UNDEF_P(closed) && RTEST(closed)) return io;
6063 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
6064 rb_eIOError, (VALUE)0);
6065 return io;
6066}
6067
6068/*
6069 * call-seq:
6070 * closed? -> true or false
6071 *
6072 * Returns +true+ if the stream is closed for both reading and writing,
6073 * +false+ otherwise.
6074 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6075 *
6076 * IO.popen('ruby', 'r+') do |pipe|
6077 * puts pipe.closed?
6078 * pipe.close_read
6079 * puts pipe.closed?
6080 * pipe.close_write
6081 * puts pipe.closed?
6082 * end
6083 *
6084 * Output:
6085 *
6086 * false
6087 * false
6088 * true
6089 *
6090 * Related: IO#close_read, IO#close_write, IO#close.
6091 */
6092VALUE
6094{
6095 rb_io_t *fptr;
6096 VALUE write_io;
6097 rb_io_t *write_fptr;
6098
6099 write_io = GetWriteIO(io);
6100 if (io != write_io) {
6101 write_fptr = RFILE(write_io)->fptr;
6102 if (write_fptr && 0 <= write_fptr->fd) {
6103 return Qfalse;
6104 }
6105 }
6106
6107 fptr = rb_io_get_fptr(io);
6108 return RBOOL(0 > fptr->fd);
6109}
6110
6111/*
6112 * call-seq:
6113 * close_read -> nil
6114 *
6115 * Closes the stream for reading if open for reading;
6116 * returns +nil+.
6117 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6118 *
6119 * If the stream was opened by IO.popen and is also closed for writing,
6120 * sets global variable <tt>$?</tt> (child exit status).
6121 *
6122 * Example:
6123 *
6124 * IO.popen('ruby', 'r+') do |pipe|
6125 * puts pipe.closed?
6126 * pipe.close_write
6127 * puts pipe.closed?
6128 * pipe.close_read
6129 * puts $?
6130 * puts pipe.closed?
6131 * end
6132 *
6133 * Output:
6134 *
6135 * false
6136 * false
6137 * pid 14748 exit 0
6138 * true
6139 *
6140 * Related: IO#close, IO#close_write, IO#closed?.
6141 */
6142
6143static VALUE
6144rb_io_close_read(VALUE io)
6145{
6146 rb_io_t *fptr;
6147 VALUE write_io;
6148
6149 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6150 if (fptr->fd < 0) return Qnil;
6151 if (is_socket(fptr->fd, fptr->pathv)) {
6152#ifndef SHUT_RD
6153# define SHUT_RD 0
6154#endif
6155 if (shutdown(fptr->fd, SHUT_RD) < 0)
6156 rb_sys_fail_path(fptr->pathv);
6157 fptr->mode &= ~FMODE_READABLE;
6158 if (!(fptr->mode & FMODE_WRITABLE))
6159 return rb_io_close(io);
6160 return Qnil;
6161 }
6162
6163 write_io = GetWriteIO(io);
6164 if (io != write_io) {
6165 rb_io_t *wfptr;
6166 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6167 wfptr->pid = fptr->pid;
6168 fptr->pid = 0;
6169 RFILE(io)->fptr = wfptr;
6170 /* bind to write_io temporarily to get rid of memory/fd leak */
6171 fptr->tied_io_for_writing = 0;
6172 RFILE(write_io)->fptr = fptr;
6173 rb_io_fptr_cleanup(fptr, FALSE);
6174 /* should not finalize fptr because another thread may be reading it */
6175 return Qnil;
6176 }
6177
6178 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
6179 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
6180 }
6181 return rb_io_close(io);
6182}
6183
6184/*
6185 * call-seq:
6186 * close_write -> nil
6187 *
6188 * Closes the stream for writing if open for writing;
6189 * returns +nil+.
6190 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6191 *
6192 * Flushes any buffered writes to the operating system before closing.
6193 *
6194 * If the stream was opened by IO.popen and is also closed for reading,
6195 * sets global variable <tt>$?</tt> (child exit status).
6196 *
6197 * IO.popen('ruby', 'r+') do |pipe|
6198 * puts pipe.closed?
6199 * pipe.close_read
6200 * puts pipe.closed?
6201 * pipe.close_write
6202 * puts $?
6203 * puts pipe.closed?
6204 * end
6205 *
6206 * Output:
6207 *
6208 * false
6209 * false
6210 * pid 15044 exit 0
6211 * true
6212 *
6213 * Related: IO#close, IO#close_read, IO#closed?.
6214 */
6215
6216static VALUE
6217rb_io_close_write(VALUE io)
6218{
6219 rb_io_t *fptr;
6220 VALUE write_io;
6221
6222 write_io = GetWriteIO(io);
6223 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6224 if (fptr->fd < 0) return Qnil;
6225 if (is_socket(fptr->fd, fptr->pathv)) {
6226#ifndef SHUT_WR
6227# define SHUT_WR 1
6228#endif
6229 /* Flush any buffered data before shutting down the write side.
6230 * Otherwise the buffered bytes are silently dropped here, and a
6231 * subsequent #close would try to flush them into the now
6232 * shutdown(SHUT_WR) socket and fail with EPIPE. This matches the
6233 * behaviour of the non-socket path below, which flushes via
6234 * rb_io_close(). */
6235 if (fptr->mode & FMODE_WRITABLE) {
6236 if (io_fflush(fptr) < 0)
6237 rb_sys_fail_on_write(fptr);
6238 }
6239 if (shutdown(fptr->fd, SHUT_WR) < 0)
6240 rb_sys_fail_path(fptr->pathv);
6241 fptr->mode &= ~FMODE_WRITABLE;
6242 if (!(fptr->mode & FMODE_READABLE))
6243 return rb_io_close(write_io);
6244 return Qnil;
6245 }
6246
6247 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6248 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6249 }
6250
6251 if (io != write_io) {
6252 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6253 fptr->tied_io_for_writing = 0;
6254 }
6255 rb_io_close(write_io);
6256 return Qnil;
6257}
6258
6259/*
6260 * call-seq:
6261 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6262 *
6263 * Behaves like IO#seek, except that it:
6264 *
6265 * - Uses low-level system functions.
6266 * - Returns the new position.
6267 *
6268 */
6269
6270static VALUE
6271rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6272{
6273 VALUE offset, ptrname;
6274 int whence = SEEK_SET;
6275 rb_io_t *fptr;
6276 rb_off_t pos;
6277
6278 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6279 whence = interpret_seek_whence(ptrname);
6280 }
6281 pos = NUM2OFFT(offset);
6282 GetOpenFile(io, fptr);
6283 if ((fptr->mode & FMODE_READABLE) &&
6284 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6285 rb_raise(rb_eIOError, "sysseek for buffered IO");
6286 }
6287 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6288 rb_warn("sysseek for buffered IO");
6289 }
6290 errno = 0;
6291 pos = lseek(fptr->fd, pos, whence);
6292 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6293
6294 return OFFT2NUM(pos);
6295}
6296
6297/*
6298 * call-seq:
6299 * syswrite(object) -> integer
6300 *
6301 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6302 * returns the number bytes written.
6303 * If +object+ is not a string is converted via method to_s:
6304 *
6305 * f = File.new('t.tmp', 'w')
6306 * f.syswrite('foo') # => 3
6307 * f.syswrite(30) # => 2
6308 * f.syswrite(:foo) # => 3
6309 * f.close
6310 *
6311 * This methods should not be used with other stream-writer methods.
6312 *
6313 */
6314
6315static VALUE
6316rb_io_syswrite(VALUE io, VALUE str)
6317{
6318 VALUE tmp;
6319 rb_io_t *fptr;
6320 rb_len_t n, len;
6321 const char *ptr;
6322
6323 if (!RB_TYPE_P(str, T_STRING))
6324 str = rb_obj_as_string(str);
6325
6326 io = GetWriteIO(io);
6327 GetOpenFile(io, fptr);
6329
6330 if (fptr->wbuf.len) {
6331 rb_warn("syswrite for buffered IO");
6332 }
6333
6334 tmp = rb_str_tmp_frozen_acquire(str);
6335 RSTRING_GETMEM(tmp, ptr, len);
6336 n = rb_io_write_memory(fptr, ptr, len);
6337 if (n < 0) rb_sys_fail_path(fptr->pathv);
6338 rb_str_tmp_frozen_release(str, tmp);
6339
6340 return LEN2NUM(n);
6341}
6342
6343/*
6344 * call-seq:
6345 * sysread(maxlen) -> string
6346 * sysread(maxlen, out_string) -> string
6347 *
6348 * Behaves like IO#readpartial, except that it uses low-level system functions.
6349 *
6350 * This method should not be used with other stream-reader methods.
6351 *
6352 */
6353
6354static VALUE
6355rb_io_sysread(int argc, VALUE *argv, VALUE io)
6356{
6357 VALUE len, str;
6358 rb_io_t *fptr;
6359 rb_len_t n, ilen;
6360 struct io_internal_read_struct iis;
6361 int shrinkable;
6362
6363 rb_scan_args(argc, argv, "11", &len, &str);
6364 ilen = NUM2LEN(len);
6365
6366 shrinkable = io_setstrbuf(&str, ilen);
6367 if (ilen == 0) return str;
6368
6369 GetOpenFile(io, fptr);
6371
6372 if (READ_DATA_BUFFERED(fptr)) {
6373 rb_raise(rb_eIOError, "sysread for buffered IO");
6374 }
6375
6376 rb_io_check_closed(fptr);
6377
6378 io_setstrbuf(&str, ilen);
6379 rb_str_make_heap(str);
6380 iis.th = rb_thread_current();
6381 iis.fptr = fptr;
6382 iis.nonblock = 0;
6383 iis.fd = fptr->fd;
6384 iis.buf = RSTRING_PTR(str);
6385 iis.capa = ilen;
6386 iis.timeout = NULL;
6387 n = io_read_memory_locktmp(str, &iis);
6388
6389 if (n < 0) {
6390 rb_sys_fail_path(fptr->pathv);
6391 }
6392
6393 io_set_read_length(str, n, shrinkable);
6394
6395 if (n == 0 && ilen > 0) {
6396 rb_eof_error();
6397 }
6398
6399 return str;
6400}
6401
6403 struct rb_io *io;
6404 int fd;
6405 void *buf;
6406 size_t count;
6407 rb_off_t offset;
6408};
6409
6410static VALUE
6411internal_pread_func(void *_arg)
6412{
6413 struct prdwr_internal_arg *arg = _arg;
6414
6415 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6416}
6417
6418static VALUE
6419pread_internal_call(VALUE _arg)
6420{
6421 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6422
6423 VALUE scheduler = rb_fiber_scheduler_current();
6424 if (scheduler != Qnil) {
6425 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6426
6427 if (!UNDEF_P(result)) {
6429 }
6430 }
6431
6432 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6433}
6434
6435/*
6436 * call-seq:
6437 * pread(maxlen, offset) -> string
6438 * pread(maxlen, offset, out_string) -> string
6439 *
6440 * Behaves like IO#readpartial, except that it:
6441 *
6442 * - Reads at the given +offset+ (in bytes).
6443 * - Disregards, and does not modify, the stream's position
6444 * (see {Position}[rdoc-ref:IO@Position]).
6445 * - Bypasses any user space buffering in the stream.
6446 *
6447 * Because this method does not disturb the stream's state
6448 * (its position, in particular), +pread+ allows multiple threads and processes
6449 * to use the same \IO object for reading at various offsets.
6450 *
6451 * f = File.open('t.txt')
6452 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6453 * f.pos # => 52
6454 * # Read 12 bytes at offset 0.
6455 * f.pread(12, 0) # => "First line\n"
6456 * # Read 9 bytes at offset 8.
6457 * f.pread(9, 8) # => "ne\nSecon"
6458 * f.close
6459 *
6460 * Not available on some platforms.
6461 *
6462 */
6463static VALUE
6464rb_io_pread(int argc, VALUE *argv, VALUE io)
6465{
6466 VALUE len, offset, str;
6467 rb_io_t *fptr;
6468 ssize_t n;
6469 struct prdwr_internal_arg arg;
6470 int shrinkable;
6471
6472 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6473 arg.count = NUM2SIZET(len);
6474 arg.offset = NUM2OFFT(offset);
6475
6476 shrinkable = io_setstrbuf(&str, (rb_len_t)arg.count);
6477 if (arg.count == 0) return str;
6478 rb_str_make_heap(str);
6479 arg.buf = RSTRING_PTR(str);
6480
6481 GetOpenFile(io, fptr);
6483
6484 arg.io = fptr;
6485 arg.fd = fptr->fd;
6486 rb_io_check_closed(fptr);
6487
6488 rb_str_locktmp(str);
6489 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6490
6491 if (n < 0) {
6492 rb_sys_fail_path(fptr->pathv);
6493 }
6494 io_set_read_length(str, n, shrinkable);
6495 if (n == 0 && arg.count > 0) {
6496 rb_eof_error();
6497 }
6498
6499 return str;
6500}
6501
6502static VALUE
6503internal_pwrite_func(void *_arg)
6504{
6505 struct prdwr_internal_arg *arg = _arg;
6506
6507 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6508}
6509
6510static VALUE
6511pwrite_internal_call(VALUE _arg)
6512{
6513 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6514
6515 VALUE scheduler = rb_fiber_scheduler_current();
6516 if (scheduler != Qnil) {
6517 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6518
6519 if (!UNDEF_P(result)) {
6521 }
6522 }
6523
6524 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
6525}
6526
6527/*
6528 * call-seq:
6529 * pwrite(object, offset) -> integer
6530 *
6531 * Behaves like IO#write, except that it:
6532 *
6533 * - Writes at the given +offset+ (in bytes).
6534 * - Disregards, and does not modify, the stream's position
6535 * (see {Position}[rdoc-ref:IO@Position]).
6536 * - Bypasses any user space buffering in the stream.
6537 *
6538 * Because this method does not disturb the stream's state
6539 * (its position, in particular), +pwrite+ allows multiple threads and processes
6540 * to use the same \IO object for writing at various offsets.
6541 *
6542 * f = File.open('t.tmp', 'w+')
6543 * # Write 6 bytes at offset 3.
6544 * f.pwrite('ABCDEF', 3) # => 6
6545 * f.rewind
6546 * f.read # => "\u0000\u0000\u0000ABCDEF"
6547 * f.close
6548 *
6549 * Not available on some platforms.
6550 *
6551 */
6552static VALUE
6553rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6554{
6555 rb_io_t *fptr;
6556 ssize_t n;
6557 struct prdwr_internal_arg arg;
6558 VALUE tmp;
6559
6560 if (!RB_TYPE_P(str, T_STRING))
6561 str = rb_obj_as_string(str);
6562
6563 arg.offset = NUM2OFFT(offset);
6564
6565 io = GetWriteIO(io);
6566 GetOpenFile(io, fptr);
6568
6569 arg.io = fptr;
6570 arg.fd = fptr->fd;
6571
6572 tmp = rb_str_tmp_frozen_acquire(str);
6573 arg.buf = RSTRING_PTR(tmp);
6574 arg.count = (size_t)RSTRING_LEN(tmp);
6575
6576 n = (ssize_t)pwrite_internal_call((VALUE)&arg);
6577 if (n < 0) rb_sys_fail_path(fptr->pathv);
6578 rb_str_tmp_frozen_release(str, tmp);
6579
6580 return SSIZET2NUM(n);
6581}
6582
6583VALUE
6585{
6586 rb_io_t *fptr;
6587
6588 GetOpenFile(io, fptr);
6589 if (fptr->readconv)
6591 if (fptr->writeconv)
6593 fptr->mode |= FMODE_BINMODE;
6594 fptr->mode &= ~FMODE_TEXTMODE;
6595 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6596#ifdef O_BINARY
6597 if (!fptr->readconv) {
6598 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6599 }
6600 else {
6601 setmode(fptr->fd, O_BINARY);
6602 }
6603#endif
6604 return io;
6605}
6606
6607static void
6608io_ascii8bit_binmode(rb_io_t *fptr)
6609{
6610 if (fptr->readconv) {
6611 rb_econv_close(fptr->readconv);
6612 fptr->readconv = NULL;
6613 }
6614 if (fptr->writeconv) {
6616 fptr->writeconv = NULL;
6617 }
6618 fptr->mode |= FMODE_BINMODE;
6619 fptr->mode &= ~FMODE_TEXTMODE;
6620 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6621
6622 fptr->encs.enc = rb_ascii8bit_encoding();
6623 fptr->encs.enc2 = NULL;
6624 fptr->encs.ecflags = 0;
6625 fptr->encs.ecopts = Qnil;
6626 clear_codeconv(fptr);
6627}
6628
6629VALUE
6631{
6632 rb_io_t *fptr;
6633
6634 GetOpenFile(io, fptr);
6635 io_ascii8bit_binmode(fptr);
6636
6637 return io;
6638}
6639
6640/*
6641 * call-seq:
6642 * binmode -> self
6643 *
6644 * Sets the stream's data mode as binary
6645 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6646 *
6647 * A stream's data mode may not be changed from binary to text.
6648 *
6649 */
6650
6651static VALUE
6652rb_io_binmode_m(VALUE io)
6653{
6654 VALUE write_io;
6655
6657
6658 write_io = GetWriteIO(io);
6659 if (write_io != io)
6660 rb_io_ascii8bit_binmode(write_io);
6661 return io;
6662}
6663
6664/*
6665 * call-seq:
6666 * binmode? -> true or false
6667 *
6668 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6669 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6670 *
6671 */
6672static VALUE
6673rb_io_binmode_p(VALUE io)
6674{
6675 rb_io_t *fptr;
6676 GetOpenFile(io, fptr);
6677 return RBOOL(fptr->mode & FMODE_BINMODE);
6678}
6679
6680static const char*
6681rb_io_fmode_modestr(enum rb_io_mode fmode)
6682{
6683 if (fmode & FMODE_APPEND) {
6684 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6685 return MODE_BTMODE("a+", "ab+", "at+");
6686 }
6687 return MODE_BTMODE("a", "ab", "at");
6688 }
6689 switch (fmode & FMODE_READWRITE) {
6690 default:
6691 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6692 case FMODE_READABLE:
6693 return MODE_BTMODE("r", "rb", "rt");
6694 case FMODE_WRITABLE:
6695 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6696 case FMODE_READWRITE:
6697 if (fmode & FMODE_CREATE) {
6698 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6699 }
6700 return MODE_BTMODE("r+", "rb+", "rt+");
6701 }
6702}
6703
6704static const char bom_prefix[] = "bom|";
6705static const char utf_prefix[] = "utf-";
6706enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6707enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6708
6709static int
6710io_encname_bom_p(const char *name, rb_len_t len)
6711{
6712 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6713}
6714
6715enum rb_io_mode
6716rb_io_modestr_fmode(const char *modestr)
6717{
6718 enum rb_io_mode fmode = 0;
6719 const char *m = modestr, *p = NULL;
6720
6721 switch (*m++) {
6722 case 'r':
6723 fmode |= FMODE_READABLE;
6724 break;
6725 case 'w':
6727 break;
6728 case 'a':
6730 break;
6731 default:
6732 goto error;
6733 }
6734
6735 while (*m) {
6736 switch (*m++) {
6737 case 'b':
6738 fmode |= FMODE_BINMODE;
6739 break;
6740 case 't':
6741 fmode |= FMODE_TEXTMODE;
6742 break;
6743 case '+':
6744 fmode |= FMODE_READWRITE;
6745 break;
6746 case 'x':
6747 if (modestr[0] != 'w')
6748 goto error;
6749 fmode |= FMODE_EXCL;
6750 break;
6751 default:
6752 goto error;
6753 case ':':
6754 p = strchr(m, ':');
6755 if (io_encname_bom_p(m, p ? (rb_len_t)(p - m) : (rb_len_t)strlen(m)))
6756 fmode |= FMODE_SETENC_BY_BOM;
6757 goto finished;
6758 }
6759 }
6760
6761 finished:
6762 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6763 goto error;
6764
6765 return fmode;
6766
6767 error:
6768 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6770}
6771
6772int
6773rb_io_oflags_fmode(int oflags)
6774{
6775 enum rb_io_mode fmode = 0;
6776
6777 switch (oflags & O_ACCMODE) {
6778 case O_RDONLY:
6779 fmode = FMODE_READABLE;
6780 break;
6781 case O_WRONLY:
6782 fmode = FMODE_WRITABLE;
6783 break;
6784 case O_RDWR:
6785 fmode = FMODE_READWRITE;
6786 break;
6787 }
6788
6789 if (oflags & O_APPEND) {
6790 fmode |= FMODE_APPEND;
6791 }
6792 if (oflags & O_TRUNC) {
6793 fmode |= FMODE_TRUNC;
6794 }
6795 if (oflags & O_CREAT) {
6796 fmode |= FMODE_CREATE;
6797 }
6798 if (oflags & O_EXCL) {
6799 fmode |= FMODE_EXCL;
6800 }
6801#ifdef O_BINARY
6802 if (oflags & O_BINARY) {
6803 fmode |= FMODE_BINMODE;
6804 }
6805#endif
6806
6807 return fmode;
6808}
6809
6810static int
6811rb_io_fmode_oflags(enum rb_io_mode fmode)
6812{
6813 int oflags = 0;
6814
6815 switch (fmode & FMODE_READWRITE) {
6816 case FMODE_READABLE:
6817 oflags |= O_RDONLY;
6818 break;
6819 case FMODE_WRITABLE:
6820 oflags |= O_WRONLY;
6821 break;
6822 case FMODE_READWRITE:
6823 oflags |= O_RDWR;
6824 break;
6825 }
6826
6827 if (fmode & FMODE_APPEND) {
6828 oflags |= O_APPEND;
6829 }
6830 if (fmode & FMODE_TRUNC) {
6831 oflags |= O_TRUNC;
6832 }
6833 if (fmode & FMODE_CREATE) {
6834 oflags |= O_CREAT;
6835 }
6836 if (fmode & FMODE_EXCL) {
6837 oflags |= O_EXCL;
6838 }
6839#ifdef O_BINARY
6840 if (fmode & FMODE_BINMODE) {
6841 oflags |= O_BINARY;
6842 }
6843#endif
6844
6845 return oflags;
6846}
6847
6848int
6849rb_io_modestr_oflags(const char *modestr)
6850{
6851 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6852}
6853
6854static const char*
6855rb_io_oflags_modestr(int oflags)
6856{
6857#ifdef O_BINARY
6858# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6859#else
6860# define MODE_BINARY(a,b) (a)
6861#endif
6862 int accmode;
6863 if (oflags & O_EXCL) {
6864 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6865 }
6866 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6867 if (oflags & O_APPEND) {
6868 if (accmode == O_WRONLY) {
6869 return MODE_BINARY("a", "ab");
6870 }
6871 if (accmode == O_RDWR) {
6872 return MODE_BINARY("a+", "ab+");
6873 }
6874 }
6875 switch (accmode) {
6876 default:
6877 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6878 case O_RDONLY:
6879 return MODE_BINARY("r", "rb");
6880 case O_WRONLY:
6881 return MODE_BINARY("w", "wb");
6882 case O_RDWR:
6883 if (oflags & O_TRUNC) {
6884 return MODE_BINARY("w+", "wb+");
6885 }
6886 return MODE_BINARY("r+", "rb+");
6887 }
6888}
6889
6890/*
6891 * Convert external/internal encodings to enc/enc2
6892 * NULL => use default encoding
6893 * Qnil => no encoding specified (internal only)
6894 */
6895static void
6896rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6897{
6898 int default_ext = 0;
6899
6900 if (ext == NULL) {
6901 ext = rb_default_external_encoding();
6902 default_ext = 1;
6903 }
6904 if (rb_is_ascii8bit_enc(ext)) {
6905 /* If external is ASCII-8BIT, no transcoding */
6906 intern = NULL;
6907 }
6908 else if (intern == NULL) {
6909 intern = rb_default_internal_encoding();
6910 }
6911 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6912 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6913 /* No internal encoding => use external + no transcoding */
6914 *enc = (default_ext && intern != ext) ? NULL : ext;
6915 *enc2 = NULL;
6916 }
6917 else {
6918 *enc = intern;
6919 *enc2 = ext;
6920 }
6921}
6922
6923static void
6924unsupported_encoding(const char *name, rb_encoding *enc)
6925{
6926 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6927}
6928
6929static void
6930parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6931 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6932{
6933 const char *p;
6934 char encname[ENCODING_MAXNAMELEN+1];
6935 int idx, idx2;
6936 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6937 rb_encoding *ext_enc, *int_enc;
6938 rb_len_t len;
6939
6940 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6941
6942 p = strrchr(estr, ':');
6943 len = p ? (p++ - estr) : (rb_len_t)strlen(estr);
6944 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6945 estr += bom_prefix_len;
6946 len -= bom_prefix_len;
6947 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6948 fmode |= FMODE_SETENC_BY_BOM;
6949 }
6950 else {
6951 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6952 fmode &= ~FMODE_SETENC_BY_BOM;
6953 }
6954 }
6955 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6956 idx = -1;
6957 }
6958 else {
6959 if (p) {
6960 memcpy(encname, estr, len);
6961 encname[len] = '\0';
6962 estr = encname;
6963 }
6964 idx = rb_enc_find_index(estr);
6965 }
6966 if (fmode_p) *fmode_p = fmode;
6967
6968 if (idx >= 0)
6969 ext_enc = rb_enc_from_index(idx);
6970 else {
6971 if (idx != -2)
6972 unsupported_encoding(estr, estr_enc);
6973 ext_enc = NULL;
6974 }
6975
6976 int_enc = NULL;
6977 if (p) {
6978 if (*p == '-' && *(p+1) == '\0') {
6979 /* Special case - "-" => no transcoding */
6980 int_enc = (rb_encoding *)Qnil;
6981 }
6982 else {
6983 idx2 = rb_enc_find_index(p);
6984 if (idx2 < 0)
6985 unsupported_encoding(p, estr_enc);
6986 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6987 int_enc = (rb_encoding *)Qnil;
6988 }
6989 else
6990 int_enc = rb_enc_from_index(idx2);
6991 }
6992 }
6993
6994 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6995}
6996
6997int
6998rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6999{
7000 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
7001 int extracted = 0;
7002 rb_encoding *extencoding = NULL;
7003 rb_encoding *intencoding = NULL;
7004
7005 if (!NIL_P(opt)) {
7006 VALUE v;
7007 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
7008 if (v != Qnil) encoding = v;
7009 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
7010 if (v != Qnil) extenc = v;
7011 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
7012 if (!UNDEF_P(v)) intenc = v;
7013 }
7014 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
7015 if (!NIL_P(ruby_verbose)) {
7016 int idx = rb_to_encoding_index(encoding);
7017 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
7018 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
7019 encoding, UNDEF_P(extenc) ? "internal" : "external");
7020 }
7021 encoding = Qnil;
7022 }
7023 if (!NIL_OR_UNDEF_P(extenc)) {
7024 extencoding = rb_to_encoding(extenc);
7025 }
7026 if (!UNDEF_P(intenc)) {
7027 if (NIL_P(intenc)) {
7028 /* internal_encoding: nil => no transcoding */
7029 intencoding = (rb_encoding *)Qnil;
7030 }
7031 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
7032 char *p = StringValueCStr(tmp);
7033
7034 if (*p == '-' && *(p+1) == '\0') {
7035 /* Special case - "-" => no transcoding */
7036 intencoding = (rb_encoding *)Qnil;
7037 }
7038 else {
7039 intencoding = rb_to_encoding(intenc);
7040 }
7041 }
7042 else {
7043 intencoding = rb_to_encoding(intenc);
7044 }
7045 if (extencoding == intencoding) {
7046 intencoding = (rb_encoding *)Qnil;
7047 }
7048 }
7049 if (!NIL_P(encoding)) {
7050 extracted = 1;
7051 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
7052 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
7053 enc_p, enc2_p, fmode_p);
7054 }
7055 else {
7056 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
7057 }
7058 }
7059 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
7060 extracted = 1;
7061 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
7062 }
7063 return extracted;
7064}
7065
7066static void
7067validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
7068{
7069 enum rb_io_mode fmode = *fmode_p;
7070
7071 if ((fmode & FMODE_READABLE) &&
7072 !enc2 &&
7073 !(fmode & FMODE_BINMODE) &&
7074 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
7075 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
7076
7077 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
7078 rb_raise(rb_eArgError, "newline decorator with binary mode");
7079 }
7080 if (!(fmode & FMODE_BINMODE) &&
7081 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
7082 fmode |= FMODE_TEXTMODE;
7083 *fmode_p = fmode;
7084 }
7085#if !DEFAULT_TEXTMODE
7086 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
7087 fmode &= ~FMODE_TEXTMODE;
7088 *fmode_p = fmode;
7089 }
7090#endif
7091}
7092
7093static void
7094extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
7095{
7096 if (!NIL_P(opthash)) {
7097 VALUE v;
7098 v = rb_hash_aref(opthash, sym_textmode);
7099 if (!NIL_P(v)) {
7100 if (*fmode & FMODE_TEXTMODE)
7101 rb_raise(rb_eArgError, "textmode specified twice");
7102 if (*fmode & FMODE_BINMODE)
7103 rb_raise(rb_eArgError, "both textmode and binmode specified");
7104 if (RTEST(v))
7105 *fmode |= FMODE_TEXTMODE;
7106 }
7107 v = rb_hash_aref(opthash, sym_binmode);
7108 if (!NIL_P(v)) {
7109 if (*fmode & FMODE_BINMODE)
7110 rb_raise(rb_eArgError, "binmode specified twice");
7111 if (*fmode & FMODE_TEXTMODE)
7112 rb_raise(rb_eArgError, "both textmode and binmode specified");
7113 if (RTEST(v))
7114 *fmode |= FMODE_BINMODE;
7115 }
7116
7117 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
7118 rb_raise(rb_eArgError, "both textmode and binmode specified");
7119 }
7120}
7121
7122void
7123rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
7124 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
7125{
7126 VALUE vmode;
7127 int oflags;
7128 enum rb_io_mode fmode;
7129 rb_encoding *enc, *enc2;
7130 int ecflags;
7131 VALUE ecopts;
7132 int has_enc = 0, has_vmode = 0;
7133 VALUE intmode;
7134
7135 vmode = *vmode_p;
7136
7137 /* Set to defaults */
7138 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
7139
7140 vmode_handle:
7141 if (NIL_P(vmode)) {
7142 fmode = FMODE_READABLE;
7143 oflags = O_RDONLY;
7144 }
7145 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
7146 vmode = intmode;
7147 oflags = NUM2INT(intmode);
7148 fmode = rb_io_oflags_fmode(oflags);
7149 }
7150 else {
7151 const char *p;
7152
7153 StringValue(vmode);
7154 p = StringValueCStr(vmode);
7155 fmode = rb_io_modestr_fmode(p);
7156 oflags = rb_io_fmode_oflags(fmode);
7157 p = strchr(p, ':');
7158 if (p) {
7159 has_enc = 1;
7160 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
7161 }
7162 else {
7163 rb_encoding *e;
7164
7165 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7166 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
7167 }
7168 }
7169
7170 if (NIL_P(opthash)) {
7171 ecflags = (fmode & FMODE_READABLE) ?
7174#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7175 ecflags |= (fmode & FMODE_WRITABLE) ?
7176 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7177 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7178#endif
7179 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7180 ecopts = Qnil;
7181 if (fmode & FMODE_BINMODE) {
7182#ifdef O_BINARY
7183 oflags |= O_BINARY;
7184#endif
7185 if (!has_enc)
7186 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7187 }
7188#if DEFAULT_TEXTMODE
7189 else if (NIL_P(vmode)) {
7190 fmode |= DEFAULT_TEXTMODE;
7191 }
7192#endif
7193 }
7194 else {
7195 VALUE v;
7196 if (!has_vmode) {
7197 v = rb_hash_aref(opthash, sym_mode);
7198 if (!NIL_P(v)) {
7199 if (!NIL_P(vmode)) {
7200 rb_raise(rb_eArgError, "mode specified twice");
7201 }
7202 has_vmode = 1;
7203 vmode = v;
7204 goto vmode_handle;
7205 }
7206 }
7207 v = rb_hash_aref(opthash, sym_flags);
7208 if (!NIL_P(v)) {
7209 v = rb_to_int(v);
7210 oflags |= NUM2INT(v);
7211 vmode = INT2NUM(oflags);
7212 fmode = rb_io_oflags_fmode(oflags);
7213 }
7214 extract_binmode(opthash, &fmode);
7215 if (fmode & FMODE_BINMODE) {
7216#ifdef O_BINARY
7217 oflags |= O_BINARY;
7218#endif
7219 if (!has_enc)
7220 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7221 }
7222#if DEFAULT_TEXTMODE
7223 else if (NIL_P(vmode)) {
7224 fmode |= DEFAULT_TEXTMODE;
7225 }
7226#endif
7227 v = rb_hash_aref(opthash, sym_perm);
7228 if (!NIL_P(v)) {
7229 if (vperm_p) {
7230 if (!NIL_P(*vperm_p)) {
7231 rb_raise(rb_eArgError, "perm specified twice");
7232 }
7233 *vperm_p = v;
7234 }
7235 else {
7236 /* perm no use, just ignore */
7237 }
7238 }
7239 ecflags = (fmode & FMODE_READABLE) ?
7242#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7243 ecflags |= (fmode & FMODE_WRITABLE) ?
7244 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7245 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7246#endif
7247
7248 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7249 if (has_enc) {
7250 rb_raise(rb_eArgError, "encoding specified twice");
7251 }
7252 }
7253 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7254 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7255 }
7256
7257 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7258
7259 *vmode_p = vmode;
7260
7261 *oflags_p = oflags;
7262 *fmode_p = fmode;
7263 convconfig_p->enc = enc;
7264 convconfig_p->enc2 = enc2;
7265 convconfig_p->ecflags = ecflags;
7266 convconfig_p->ecopts = ecopts;
7267}
7268
7270 VALUE fname;
7271 int oflags;
7272 mode_t perm;
7273};
7274
7275static void *
7276sysopen_func(void *ptr)
7277{
7278 const struct sysopen_struct *data = ptr;
7279 const char *fname = RSTRING_PTR(data->fname);
7280 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7281}
7282
7283static inline int
7284rb_sysopen_internal(struct sysopen_struct *data)
7285{
7286 int fd;
7287 do {
7288 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7289 } while (fd < 0 && errno == EINTR);
7290 if (0 <= fd)
7291 rb_update_max_fd(fd);
7292 return fd;
7293}
7294
7295static int
7296rb_sysopen(VALUE fname, int oflags, mode_t perm)
7297{
7298 int fd = -1;
7299 struct sysopen_struct data;
7300
7301 data.fname = rb_str_encode_ospath(fname);
7302 StringValueCStr(data.fname);
7303 data.oflags = oflags;
7304 data.perm = perm;
7305
7306 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7307 rb_syserr_fail_path(first_errno, fname);
7308 }
7309 return fd;
7310}
7311
7312static inline FILE *
7313fdopen_internal(int fd, const char *modestr)
7314{
7315 FILE *file;
7316
7317#if defined(__sun)
7318 errno = 0;
7319#endif
7320 file = fdopen(fd, modestr);
7321 if (!file) {
7322#ifdef _WIN32
7323 if (errno == 0) errno = EINVAL;
7324#elif defined(__sun)
7325 if (errno == 0) errno = EMFILE;
7326#endif
7327 }
7328 return file;
7329}
7330
7331FILE *
7332rb_fdopen(int fd, const char *modestr)
7333{
7334 FILE *file = 0;
7335
7336 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7337 rb_syserr_fail(first_errno, 0);
7338 }
7339
7340 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7341#ifdef USE_SETVBUF
7342 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7343 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7344#endif
7345 return file;
7346}
7347
7348static int
7349io_check_tty(rb_io_t *fptr)
7350{
7351 int t = isatty(fptr->fd);
7352 if (t)
7353 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7354 return t;
7355}
7356
7357static VALUE rb_io_internal_encoding(VALUE);
7358static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7359
7360static int
7361io_strip_bom(VALUE io)
7362{
7363 VALUE b1, b2, b3, b4;
7364 rb_io_t *fptr;
7365
7366 GetOpenFile(io, fptr);
7367 if (!(fptr->mode & FMODE_READABLE)) return 0;
7368 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7369 switch (b1) {
7370 case INT2FIX(0xEF):
7371 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7372 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7373 if (b3 == INT2FIX(0xBF)) {
7374 return rb_utf8_encindex();
7375 }
7376 rb_io_ungetbyte(io, b3);
7377 }
7378 rb_io_ungetbyte(io, b2);
7379 break;
7380
7381 case INT2FIX(0xFE):
7382 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7383 if (b2 == INT2FIX(0xFF)) {
7384 return ENCINDEX_UTF_16BE;
7385 }
7386 rb_io_ungetbyte(io, b2);
7387 break;
7388
7389 case INT2FIX(0xFF):
7390 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7391 if (b2 == INT2FIX(0xFE)) {
7392 b3 = rb_io_getbyte(io);
7393 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7394 if (b4 == INT2FIX(0)) {
7395 return ENCINDEX_UTF_32LE;
7396 }
7397 rb_io_ungetbyte(io, b4);
7398 }
7399 rb_io_ungetbyte(io, b3);
7400 return ENCINDEX_UTF_16LE;
7401 }
7402 rb_io_ungetbyte(io, b2);
7403 break;
7404
7405 case INT2FIX(0):
7406 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7407 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7408 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7409 if (b4 == INT2FIX(0xFF)) {
7410 return ENCINDEX_UTF_32BE;
7411 }
7412 rb_io_ungetbyte(io, b4);
7413 }
7414 rb_io_ungetbyte(io, b3);
7415 }
7416 rb_io_ungetbyte(io, b2);
7417 break;
7418 }
7419 rb_io_ungetbyte(io, b1);
7420 return 0;
7421}
7422
7423static rb_encoding *
7424io_set_encoding_by_bom(VALUE io)
7425{
7426 int idx = io_strip_bom(io);
7427 rb_io_t *fptr;
7428 rb_encoding *extenc = NULL;
7429
7430 GetOpenFile(io, fptr);
7431 if (idx) {
7432 extenc = rb_enc_from_index(idx);
7433 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7434 rb_io_internal_encoding(io), Qnil);
7435 }
7436 else {
7437 fptr->encs.enc2 = NULL;
7438 }
7439 return extenc;
7440}
7441
7442static VALUE
7443rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7444 const struct rb_io_encoding *convconfig, mode_t perm)
7445{
7446 VALUE pathv;
7447 rb_io_t *fptr;
7448 struct rb_io_encoding cc;
7449 if (!convconfig) {
7450 /* Set to default encodings */
7451 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7452 cc.ecflags = 0;
7453 cc.ecopts = Qnil;
7454 convconfig = &cc;
7455 }
7456 validate_enc_binmode(&fmode, convconfig->ecflags,
7457 convconfig->enc, convconfig->enc2);
7458
7459 MakeOpenFile(io, fptr);
7460 fptr->mode = fmode;
7461 fptr->encs = *convconfig;
7462 pathv = rb_str_new_frozen(filename);
7463#ifdef O_TMPFILE
7464 if (!(oflags & O_TMPFILE)) {
7465 fptr->pathv = pathv;
7466 }
7467#else
7468 fptr->pathv = pathv;
7469#endif
7470 fptr->fd = rb_sysopen(pathv, oflags, perm);
7471 io_check_tty(fptr);
7472 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7473
7474 return io;
7475}
7476
7477static VALUE
7478rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7479{
7480 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7481 const char *p = strchr(modestr, ':');
7482 struct rb_io_encoding convconfig;
7483
7484 if (p) {
7485 parse_mode_enc(p+1, rb_usascii_encoding(),
7486 &convconfig.enc, &convconfig.enc2, &fmode);
7487 }
7488 else {
7489 rb_encoding *e;
7490 /* Set to default encodings */
7491
7492 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7493 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7494 }
7495
7496 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7499#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7500 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7501 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7502 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7503#endif
7504 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7505 convconfig.ecopts = Qnil;
7506
7507 return rb_file_open_generic(io, filename,
7508 rb_io_fmode_oflags(fmode),
7509 fmode,
7510 &convconfig,
7511 0666);
7512}
7513
7514VALUE
7515rb_file_open_str(VALUE fname, const char *modestr)
7516{
7517 FilePathValue(fname);
7518 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7519}
7520
7521VALUE
7522rb_file_open(const char *fname, const char *modestr)
7523{
7524 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7525}
7526
7527#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7528static struct pipe_list {
7529 rb_io_t *fptr;
7530 struct pipe_list *next;
7531} *pipe_list;
7532
7533static void
7534pipe_add_fptr(rb_io_t *fptr)
7535{
7536 struct pipe_list *list;
7537
7538 list = ALLOC(struct pipe_list);
7539 list->fptr = fptr;
7540 list->next = pipe_list;
7541 pipe_list = list;
7542}
7543
7544static void
7545pipe_del_fptr(rb_io_t *fptr)
7546{
7547 struct pipe_list **prev = &pipe_list;
7548 struct pipe_list *tmp;
7549
7550 while ((tmp = *prev) != 0) {
7551 if (tmp->fptr == fptr) {
7552 *prev = tmp->next;
7553 free(tmp);
7554 return;
7555 }
7556 prev = &tmp->next;
7557 }
7558}
7559
7560#if defined (_WIN32) || defined(__CYGWIN__)
7561static void
7562pipe_atexit(void)
7563{
7564 struct pipe_list *list = pipe_list;
7565 struct pipe_list *tmp;
7566
7567 /* The CRT calls this on whichever thread calls ExitProcess, which can be
7568 * one Ruby does not know, e.g. the console control handler on Ctrl+Break. */
7569 if (!rb_current_execution_context(false)) return;
7570
7571 while (list) {
7572 tmp = list->next;
7573 rb_io_fptr_finalize(list->fptr);
7574 list = tmp;
7575 }
7576}
7577#endif
7578
7579static void
7580pipe_finalize(rb_io_t *fptr, int noraise)
7581{
7582#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7583 int status = 0;
7584 if (fptr->stdio_file) {
7585 status = pclose(fptr->stdio_file);
7586 }
7587 fptr->fd = -1;
7588 fptr->stdio_file = 0;
7589 rb_last_status_set(status, fptr->pid);
7590#else
7591 fptr_finalize(fptr, noraise);
7592#endif
7593 pipe_del_fptr(fptr);
7594}
7595#endif
7596
7597static void
7598fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7599{
7600#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7601 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7602
7603 if (old_finalize == orig->finalize) return;
7604#endif
7605
7606 fptr->finalize = orig->finalize;
7607
7608#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7609 if (old_finalize != pipe_finalize) {
7610 struct pipe_list *list;
7611 for (list = pipe_list; list; list = list->next) {
7612 if (list->fptr == fptr) break;
7613 }
7614 if (!list) pipe_add_fptr(fptr);
7615 }
7616 else {
7617 pipe_del_fptr(fptr);
7618 }
7619#endif
7620}
7621
7622void
7624{
7626 fptr->mode |= FMODE_SYNC;
7627}
7628
7629
7630int
7631rb_pipe(int *pipes)
7632{
7633 int ret;
7634 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7635 if (ret == 0) {
7636 rb_update_max_fd(pipes[0]);
7637 rb_update_max_fd(pipes[1]);
7638 }
7639 return ret;
7640}
7641
7642#ifdef _WIN32
7643#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7644#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7645#endif
7646
7647#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7648struct popen_arg {
7649 VALUE execarg_obj;
7650 struct rb_execarg *eargp;
7651 int modef;
7652 int pair[2];
7653 int write_pair[2];
7654};
7655#endif
7656
7657#ifdef HAVE_WORKING_FORK
7658# ifndef __EMSCRIPTEN__
7659static void
7660popen_redirect(struct popen_arg *p)
7661{
7662 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7663 close(p->write_pair[1]);
7664 if (p->write_pair[0] != 0) {
7665 dup2(p->write_pair[0], 0);
7666 close(p->write_pair[0]);
7667 }
7668 close(p->pair[0]);
7669 if (p->pair[1] != 1) {
7670 dup2(p->pair[1], 1);
7671 close(p->pair[1]);
7672 }
7673 }
7674 else if (p->modef & FMODE_READABLE) {
7675 close(p->pair[0]);
7676 if (p->pair[1] != 1) {
7677 dup2(p->pair[1], 1);
7678 close(p->pair[1]);
7679 }
7680 }
7681 else {
7682 close(p->pair[1]);
7683 if (p->pair[0] != 0) {
7684 dup2(p->pair[0], 0);
7685 close(p->pair[0]);
7686 }
7687 }
7688}
7689# endif
7690
7691#if defined(__linux__)
7692/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7693 * Since /proc may not be available, linux_get_maxfd is just a hint.
7694 * This function, linux_get_maxfd, must be async-signal-safe.
7695 * I.e. opendir() is not usable.
7696 *
7697 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7698 * However they are easy to re-implement in async-signal-safe manner.
7699 * (Also note that there is missing/memcmp.c.)
7700 */
7701static int
7702linux_get_maxfd(void)
7703{
7704 int fd;
7705 char buf[4096], *p, *np, *e;
7706 ssize_t ss;
7707 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7708 if (fd < 0) return fd;
7709 ss = read(fd, buf, sizeof(buf));
7710 if (ss < 0) goto err;
7711 p = buf;
7712 e = buf + ss;
7713 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7714 (np = memchr(p, '\n', e-p)) != NULL) {
7715 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7716 int fdsize;
7717 p += sizeof("FDSize:")-1;
7718 *np = '\0';
7719 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7720 close(fd);
7721 return fdsize;
7722 }
7723 p = np+1;
7724 }
7725 /* fall through */
7726
7727 err:
7728 close(fd);
7729 return (int)ss;
7730}
7731#endif
7732
7733/* This function should be async-signal-safe. */
7734void
7735rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7736{
7737#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7738 int fd, ret;
7739 int max = (int)max_file_descriptor;
7740# ifdef F_MAXFD
7741 /* F_MAXFD is available since NetBSD 2.0. */
7742 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7743 if (ret != -1)
7744 maxhint = max = ret;
7745# elif defined(__linux__)
7746 ret = linux_get_maxfd();
7747 if (maxhint < ret)
7748 maxhint = ret;
7749 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7750# endif
7751 if (max < maxhint)
7752 max = maxhint;
7753 for (fd = lowfd; fd <= max; fd++) {
7754 if (!NIL_P(noclose_fds) &&
7755 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7756 continue;
7757 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7758 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7759 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7760 }
7761# define CONTIGUOUS_CLOSED_FDS 20
7762 if (ret != -1) {
7763 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7764 max = fd + CONTIGUOUS_CLOSED_FDS;
7765 }
7766 }
7767#endif
7768}
7769
7770# ifndef __EMSCRIPTEN__
7771static int
7772popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7773{
7774 struct popen_arg *p = (struct popen_arg*)pp;
7775
7776 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7777}
7778# endif
7779#endif
7780
7781#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7782static VALUE
7783rb_execarg_fixup_v(VALUE execarg_obj)
7784{
7785 rb_execarg_parent_start(execarg_obj);
7786 return Qnil;
7787}
7788#else
7789char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7790#endif
7791
7792#ifndef __EMSCRIPTEN__
7793static VALUE
7794pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7795 const struct rb_io_encoding *convconfig)
7796{
7797 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7798 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7799 rb_pid_t pid = 0;
7800 rb_io_t *fptr;
7801 VALUE port;
7802 rb_io_t *write_fptr;
7803 VALUE write_port;
7804#if defined(HAVE_WORKING_FORK)
7805 int status;
7806 char errmsg[80] = { '\0' };
7807#endif
7808#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7809 int state;
7810 struct popen_arg arg;
7811#endif
7812 int e = 0;
7813#if defined(HAVE_SPAWNV)
7814# define DO_SPAWN(cmd, args) ((args) ? \
7815 spawnv(P_NOWAIT, (cmd), (args)) : \
7816 spawn(P_NOWAIT, (cmd)))
7817# if !defined(HAVE_WORKING_FORK)
7818 char **args = NULL;
7819# endif
7820#endif
7821#if !defined(HAVE_WORKING_FORK)
7822 struct rb_execarg sarg, *sargp = &sarg;
7823#endif
7824 FILE *fp = 0;
7825 int fd = -1;
7826 int write_fd = -1;
7827#if !defined(HAVE_WORKING_FORK)
7828 const char *cmd = 0;
7829
7830 if (prog)
7831 cmd = StringValueCStr(prog);
7832#endif
7833
7834#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7835 arg.execarg_obj = execarg_obj;
7836 arg.eargp = eargp;
7837 arg.modef = fmode;
7838 arg.pair[0] = arg.pair[1] = -1;
7839 arg.write_pair[0] = arg.write_pair[1] = -1;
7840# if !defined(HAVE_WORKING_FORK)
7841 if (eargp && !eargp->use_shell) {
7842 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7843 }
7844# endif
7845 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7847 if (rb_pipe(arg.write_pair) < 0)
7848 rb_sys_fail_str(prog);
7849 if (rb_pipe(arg.pair) < 0) {
7850 e = errno;
7851 close(arg.write_pair[0]);
7852 close(arg.write_pair[1]);
7853 rb_syserr_fail_str(e, prog);
7854 }
7855 if (eargp) {
7856 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7857 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7858 }
7859 break;
7860 case FMODE_READABLE:
7861 if (rb_pipe(arg.pair) < 0)
7862 rb_sys_fail_str(prog);
7863 if (eargp)
7864 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7865 break;
7866 case FMODE_WRITABLE:
7867 if (rb_pipe(arg.pair) < 0)
7868 rb_sys_fail_str(prog);
7869 if (eargp)
7870 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7871 break;
7872 default:
7873 rb_sys_fail_str(prog);
7874 }
7875 if (!NIL_P(execarg_obj)) {
7876 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7877 if (state) {
7878 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7879 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7880 if (0 <= arg.pair[0]) close(arg.pair[0]);
7881 if (0 <= arg.pair[1]) close(arg.pair[1]);
7882 rb_execarg_parent_end(execarg_obj);
7883 rb_jump_tag(state);
7884 }
7885
7886# if defined(HAVE_WORKING_FORK)
7887 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7888# else
7889 rb_execarg_run_options(eargp, sargp, NULL, 0);
7890 while ((pid = DO_SPAWN(cmd, args)) < 0) {
7891 /* exec failed */
7892 switch (e = errno) {
7893 case EAGAIN:
7894# if EWOULDBLOCK != EAGAIN
7895 case EWOULDBLOCK:
7896# endif
7897 rb_thread_sleep(1);
7898 continue;
7899 }
7900 break;
7901 }
7902 if (eargp)
7903 rb_execarg_run_options(sargp, NULL, NULL, 0);
7904# endif
7905 rb_execarg_parent_end(execarg_obj);
7906 }
7907 else {
7908# if defined(HAVE_WORKING_FORK)
7909 pid = rb_call_proc__fork();
7910 if (pid == 0) { /* child */
7911 popen_redirect(&arg);
7912 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7913 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7914 return Qnil;
7915 }
7916# else
7917 rb_notimplement();
7918# endif
7919 }
7920
7921 /* parent */
7922 if (pid < 0) {
7923# if defined(HAVE_WORKING_FORK)
7924 e = errno;
7925# endif
7926 close(arg.pair[0]);
7927 close(arg.pair[1]);
7929 close(arg.write_pair[0]);
7930 close(arg.write_pair[1]);
7931 }
7932# if defined(HAVE_WORKING_FORK)
7933 if (errmsg[0])
7934 rb_syserr_fail(e, errmsg);
7935# endif
7936 rb_syserr_fail_str(e, prog);
7937 }
7938 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7939 close(arg.pair[1]);
7940 fd = arg.pair[0];
7941 close(arg.write_pair[0]);
7942 write_fd = arg.write_pair[1];
7943 }
7944 else if (fmode & FMODE_READABLE) {
7945 close(arg.pair[1]);
7946 fd = arg.pair[0];
7947 }
7948 else {
7949 close(arg.pair[0]);
7950 fd = arg.pair[1];
7951 }
7952#else
7953 cmd = rb_execarg_commandline(eargp, &prog);
7954 if (!NIL_P(execarg_obj)) {
7955 rb_execarg_parent_start(execarg_obj);
7956 rb_execarg_run_options(eargp, sargp, NULL, 0);
7957 }
7958 fp = popen(cmd, modestr);
7959 e = errno;
7960 if (eargp) {
7961 rb_execarg_parent_end(execarg_obj);
7962 rb_execarg_run_options(sargp, NULL, NULL, 0);
7963 }
7964 if (!fp) rb_syserr_fail_path(e, prog);
7965 fd = fileno(fp);
7966#endif
7967
7968 port = io_alloc(rb_cIO);
7969 MakeOpenFile(port, fptr);
7970 fptr->fd = fd;
7971 fptr->stdio_file = fp;
7972 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7973 if (convconfig) {
7974 fptr->encs = *convconfig;
7975#if RUBY_CRLF_ENVIRONMENT
7978 }
7979#endif
7980 }
7981 else {
7982 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7984 }
7985#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7986 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7987 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7988 }
7989#endif
7990 }
7991 fptr->pid = pid;
7992
7993 if (0 <= write_fd) {
7994 write_port = io_alloc(rb_cIO);
7995 MakeOpenFile(write_port, write_fptr);
7996 write_fptr->fd = write_fd;
7997 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7998 fptr->mode &= ~FMODE_WRITABLE;
7999 fptr->tied_io_for_writing = write_port;
8000 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
8001 }
8002
8003#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
8004 fptr->finalize = pipe_finalize;
8005 pipe_add_fptr(fptr);
8006#endif
8007 return port;
8008}
8009#else
8010static VALUE
8011pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
8012 const struct rb_io_encoding *convconfig)
8013{
8014 rb_raise(rb_eNotImpError, "popen() is not available");
8015}
8016#endif
8017
8018static int
8019is_popen_fork(VALUE prog)
8020{
8021 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
8022#if !defined(HAVE_WORKING_FORK)
8023 rb_raise(rb_eNotImpError,
8024 "fork() function is unimplemented on this machine");
8025#else
8026 return TRUE;
8027#endif
8028 }
8029 return FALSE;
8030}
8031
8032static VALUE
8033pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
8034 const struct rb_io_encoding *convconfig)
8035{
8036 int argc = 1;
8037 VALUE *argv = &prog;
8038 VALUE execarg_obj = Qnil;
8039
8040 if (!is_popen_fork(prog))
8041 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
8042 return pipe_open(execarg_obj, modestr, fmode, convconfig);
8043}
8044
8045static VALUE
8046pipe_close(VALUE io)
8047{
8048 rb_io_t *fptr = io_close_fptr(io);
8049 if (fptr) {
8050 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
8051 }
8052 return Qnil;
8053}
8054
8055static VALUE popen_finish(VALUE port, VALUE klass);
8056
8057/*
8058 * call-seq:
8059 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
8060 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
8061 *
8062 * Executes the given command +cmd+ as a subprocess
8063 * whose $stdin and $stdout are connected to a new stream +io+.
8064 *
8065 * This method has potential security vulnerabilities if called with untrusted input;
8066 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
8067 *
8068 * If no block is given, returns the new stream,
8069 * which depending on given +mode+ may be open for reading, writing, or both.
8070 * The stream should be explicitly closed (eventually) to avoid resource leaks.
8071 *
8072 * If a block is given, the stream is passed to the block
8073 * (again, open for reading, writing, or both);
8074 * when the block exits, the stream is closed,
8075 * the block's value is returned,
8076 * and the global variable <tt>$?</tt> is set to the child's exit status.
8077 *
8078 * Optional argument +mode+ may be any valid \IO mode.
8079 * See {Access Modes}[rdoc-ref:File@Access+Modes].
8080 *
8081 * Required argument +cmd+ determines which of the following occurs:
8082 *
8083 * - The process forks.
8084 * - A specified program runs in a shell.
8085 * - A specified program runs with specified arguments.
8086 * - A specified program runs with specified arguments and a specified +argv0+.
8087 *
8088 * Each of these is detailed below.
8089 *
8090 * The optional hash argument +env+ specifies name/value pairs that are to be added
8091 * to the environment variables for the subprocess:
8092 *
8093 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
8094 * pipe.puts 'puts ENV["FOO"]'
8095 * pipe.close_write
8096 * pipe.gets
8097 * end => "bar\n"
8098 *
8099 * Optional keyword arguments +opts+ specify:
8100 *
8101 * - {Open options}[rdoc-ref:IO@Open+Options].
8102 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8103 * - Options for Kernel#spawn.
8104 *
8105 * <b>Forked Process</b>
8106 *
8107 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
8108 * IO.popen('-') do |pipe|
8109 * if pipe
8110 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
8111 * else
8112 * $stderr.puts "In child, pid is #{$$}\n"
8113 * end
8114 * end
8115 *
8116 * Output:
8117 *
8118 * In parent, child pid is 26253
8119 * In child, pid is 26253
8120 *
8121 * Note that this is not supported on all platforms.
8122 *
8123 * <b>Shell Subprocess</b>
8124 *
8125 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
8126 * the program named +cmd+ is run as a shell command:
8127 *
8128 * IO.popen('uname') do |pipe|
8129 * pipe.readlines
8130 * end
8131 *
8132 * Output:
8133 *
8134 * ["Linux\n"]
8135 *
8136 * Another example:
8137 *
8138 * IO.popen('/bin/sh', 'r+') do |pipe|
8139 * pipe.puts('ls')
8140 * pipe.close_write
8141 * $stderr.puts pipe.readlines.size
8142 * end
8143 *
8144 * Output:
8145 *
8146 * 213
8147 *
8148 * <b>Program Subprocess</b>
8149 *
8150 * When argument +cmd+ is an array of strings,
8151 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
8152 *
8153 * IO.popen(['du', '..', '.']) do |pipe|
8154 * $stderr.puts pipe.readlines.size
8155 * end
8156 *
8157 * Output:
8158 *
8159 * 1111
8160 *
8161 * <b>Program Subprocess with <tt>argv0</tt></b>
8162 *
8163 * When argument +cmd+ is an array whose first element is a 2-element string array
8164 * and whose remaining elements (if any) are strings:
8165 *
8166 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
8167 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
8168 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
8169 *
8170 * Example (sets <tt>$0</tt> to 'foo'):
8171 *
8172 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
8173 *
8174 * <b>Some Special Examples</b>
8175 *
8176 * # Set IO encoding.
8177 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
8178 * euc_jp_string = nkf_io.read
8179 * }
8180 *
8181 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
8182 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
8183 * ls_result_with_error = io.read
8184 * end
8185 *
8186 * # Use mixture of spawn options and IO options.
8187 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
8188 * ls_result_with_error = io.read
8189 * end
8190 *
8191 * f = IO.popen("uname")
8192 * p f.readlines
8193 * f.close
8194 * puts "Parent is #{Process.pid}"
8195 * IO.popen("date") {|f| puts f.gets }
8196 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
8197 * p $?
8198 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
8199 * f.puts "bar"; f.close_write; puts f.gets
8200 * }
8201 *
8202 * Output (from last section):
8203 *
8204 * ["Linux\n"]
8205 * Parent is 21346
8206 * Thu Jan 15 22:41:19 JST 2009
8207 * 21346 is here, f is #<IO:fd 3>
8208 * 21352 is here, f is nil
8209 * #<Process::Status: pid 21352 exit 0>
8210 * <foo>bar;zot;
8211 *
8212 * Raises exceptions that IO.pipe and Kernel.spawn raise.
8213 *
8214 */
8215
8216static VALUE
8217rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
8218{
8219 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
8220
8221 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8222 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8223 switch (argc) {
8224 case 2:
8225 pmode = argv[1];
8226 case 1:
8227 pname = argv[0];
8228 break;
8229 default:
8230 {
8231 int ex = !NIL_P(opt);
8232 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8233 }
8234 }
8235 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8236}
8237
8238VALUE
8239rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8240{
8241 const char *modestr;
8242 VALUE tmp, execarg_obj = Qnil;
8243 int oflags;
8244 enum rb_io_mode fmode;
8245 struct rb_io_encoding convconfig;
8246
8247 tmp = rb_check_array_type(pname);
8248 if (!NIL_P(tmp)) {
8249 rb_len_t len = RARRAY_LEN(tmp);
8250#if SIZEOF_RB_LEN_T > SIZEOF_INT
8251 if (len > INT_MAX) {
8252 rb_raise(rb_eArgError, "too many arguments");
8253 }
8254#endif
8255 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8256 RB_GC_GUARD(tmp);
8257 }
8258 else {
8259 StringValue(pname);
8260 execarg_obj = Qnil;
8261 if (!is_popen_fork(pname))
8262 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8263 }
8264 if (!NIL_P(execarg_obj)) {
8265 if (!NIL_P(opt))
8266 opt = rb_execarg_extract_options(execarg_obj, opt);
8267 if (!NIL_P(env))
8268 rb_execarg_setenv(execarg_obj, env);
8269 }
8270 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8271 modestr = rb_io_oflags_modestr(oflags);
8272
8273 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8274}
8275
8276static VALUE
8277popen_finish(VALUE port, VALUE klass)
8278{
8279 if (NIL_P(port)) {
8280 /* child */
8281 if (rb_block_given_p()) {
8282 rb_protect(rb_yield, Qnil, NULL);
8283 rb_io_flush(rb_ractor_stdout());
8284 rb_io_flush(rb_ractor_stderr());
8285 _exit(EXIT_SUCCESS);
8286 }
8287 return Qnil;
8288 }
8289 RBASIC_SET_CLASS(port, klass);
8290 if (rb_block_given_p()) {
8291 return rb_ensure(rb_yield, port, pipe_close, port);
8292 }
8293 return port;
8294}
8295
8296#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8297struct popen_writer_arg {
8298 char *const *argv;
8299 struct popen_arg popen;
8300};
8301
8302static int
8303exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8304{
8305 struct popen_writer_arg *pw = arg;
8306 pw->popen.modef = FMODE_WRITABLE;
8307 popen_redirect(&pw->popen);
8308 execv(pw->argv[0], pw->argv);
8309 strlcpy(errmsg, strerror(errno), buflen);
8310 return -1;
8311}
8312#endif
8313
8314FILE *
8315ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8316{
8317#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8318# ifdef HAVE_WORKING_FORK
8319 struct popen_writer_arg pw;
8320 int *const write_pair = pw.popen.pair;
8321# else
8322 int write_pair[2];
8323# endif
8324
8325 *pid = -1;
8326 if (cloexec_pipe(write_pair, 0, false) == 0) {
8327# ifdef HAVE_WORKING_FORK
8328 pw.argv = argv;
8329 int status;
8330 char errmsg[80] = {'\0'};
8331 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8332# else
8333 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8334 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8335# endif
8336 close(write_pair[0]);
8337 if (*pid < 0) {
8338 close(write_pair[1]);
8339 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8340 }
8341 else {
8342 return fdopen(write_pair[1], "w");
8343 }
8344 }
8345#endif
8346 return NULL;
8347}
8348
8349static VALUE
8350rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8351{
8352 int oflags;
8353 enum rb_io_mode fmode;
8354 struct rb_io_encoding convconfig;
8355 mode_t perm;
8356
8357 FilePathValue(fname);
8358
8359 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8360 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8361
8362 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8363
8364 return io;
8365}
8366
8367/*
8368 * Document-method: File::open
8369 *
8370 * :markup: markdown
8371 *
8372 * call-seq:
8373 * File.open(path, mode = 'r', permissions = 0666, **options) -> file
8374 * File.open(path, mode = 'r', permissions = 0666, **options) {|file| ... } -> object
8375 *
8376 * Creates a new \File object via File.new with the given arguments.
8377 *
8378 * With no block given, returns the \File object.
8379 *
8380 * With a block given, calls the block with the \File object,
8381 * closes the \File object, and returns the block's value:
8382 *
8383 * ```ruby
8384 * File.open('doc/maintainers.md') {|file| file.size } # => 14900
8385 * ```
8386 *
8387 * Note that the \File object is automatically closed
8388 * even if the block raises an exception.
8389 */
8390
8391/*
8392 * Document-method: IO::open
8393 *
8394 * :markup: markdown
8395 *
8396 * call-seq:
8397 * IO.open(fd, mode = 'r', **options) -> io
8398 * IO.open(fd, mode = 'r', **options) {|io| ... } -> object
8399 *
8400 * Creates a new \IO object via IO.new with the given arguments.
8401 *
8402 * With no block given, returns the \IO object.
8403 *
8404 * With a block given, calls the block with the \IO object,
8405 * closes the \IO object, and returns the block’s value:
8406 *
8407 * ```ruby
8408 * fd = File.sysopen('doc/maintainers.md') # => 6
8409 * IO.open(fd) {|io| io.read.size } # => 14897
8410 * ```
8411 */
8412
8413static VALUE
8414rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8415{
8417
8418 if (rb_block_given_p()) {
8419 return rb_ensure(rb_yield, io, io_close, io);
8420 }
8421
8422 return io;
8423}
8424
8425/*
8426 * call-seq:
8427 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8428 *
8429 * Opens the file at the given path with the given mode and permissions;
8430 * returns the integer file descriptor.
8431 *
8432 * If the file is to be readable, it must exist;
8433 * if the file is to be writable and does not exist,
8434 * it is created with the given permissions:
8435 *
8436 * File.write('t.tmp', '') # => 0
8437 * IO.sysopen('t.tmp') # => 8
8438 * IO.sysopen('t.tmp', 'w') # => 9
8439 *
8440 *
8441 */
8442
8443static VALUE
8444rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8445{
8446 VALUE fname, vmode, vperm;
8447 VALUE intmode;
8448 int oflags, fd;
8449 mode_t perm;
8450
8451 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8452 FilePathValue(fname);
8453
8454 if (NIL_P(vmode))
8455 oflags = O_RDONLY;
8456 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8457 oflags = NUM2INT(intmode);
8458 else {
8459 StringValue(vmode);
8460 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8461 }
8462 if (NIL_P(vperm)) perm = 0666;
8463 else perm = NUM2MODET(vperm);
8464
8465 RB_GC_GUARD(fname) = rb_str_new4(fname);
8466 fd = rb_sysopen(fname, oflags, perm);
8467 return INT2NUM(fd);
8468}
8469
8470/*
8471 * call-seq:
8472 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8473 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8474 *
8475 * Creates an IO object connected to the given file.
8476 *
8477 * With no block given, file stream is returned:
8478 *
8479 * open('t.txt') # => #<File:t.txt>
8480 *
8481 * With a block given, calls the block with the open file stream,
8482 * then closes the stream:
8483 *
8484 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8485 *
8486 * Output:
8487 *
8488 * #<File:t.txt>
8489 *
8490 * See File.open for details.
8491 *
8492 */
8493
8494static VALUE
8495rb_f_open(int argc, VALUE *argv, VALUE _)
8496{
8497 ID to_open = 0;
8498 int redirect = FALSE;
8499
8500 if (argc >= 1) {
8501 CONST_ID(to_open, "to_open");
8502 if (rb_respond_to(argv[0], to_open)) {
8503 redirect = TRUE;
8504 }
8505 else {
8506 VALUE tmp = argv[0];
8507 FilePathValue(tmp);
8508 if (NIL_P(tmp)) {
8509 redirect = TRUE;
8510 }
8511 else {
8512 argv[0] = tmp;
8513 }
8514 }
8515 }
8516 if (redirect) {
8517 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8518
8519 if (rb_block_given_p()) {
8520 return rb_ensure(rb_yield, io, io_close, io);
8521 }
8522 return io;
8523 }
8524 return rb_io_s_open(argc, argv, rb_cFile);
8525}
8526
8527static VALUE
8528rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8529 const struct rb_io_encoding *convconfig, mode_t perm)
8530{
8531 return rb_file_open_generic(io_alloc(klass), filename,
8532 oflags, fmode, convconfig, perm);
8533}
8534
8535static VALUE
8536rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8537{
8538 int oflags;
8539 enum rb_io_mode fmode;
8540 struct rb_io_encoding convconfig;
8541 mode_t perm;
8542
8543 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8544 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8545 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8546}
8547
8548static VALUE
8549io_reopen(VALUE io, VALUE nfile)
8550{
8551 rb_io_t *fptr, *orig;
8552 int fd, fd2;
8553 rb_off_t pos = 0;
8554
8555 nfile = rb_io_get_io(nfile);
8556 GetOpenFile(io, fptr);
8557 GetOpenFile(nfile, orig);
8558
8559 if (fptr == orig) return io;
8560 if (RUBY_IO_EXTERNAL_P(fptr)) {
8561 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8562 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8563 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8564 rb_raise(rb_eArgError,
8565 "%s can't change access mode from \"%s\" to \"%s\"",
8566 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8567 rb_io_fmode_modestr(orig->mode));
8568 }
8569 }
8570 flush_before_seek(fptr, true);
8571 /* in flush_before_seek, clear_codeconv called only if rbuf is filled */
8572 clear_codeconv(fptr);
8573 if (orig->mode & FMODE_READABLE) {
8574 pos = io_tell(orig);
8575 }
8576 if (orig->mode & FMODE_WRITABLE) {
8577 if (io_fflush(orig) < 0)
8578 rb_sys_fail_on_write(fptr);
8579 }
8580
8581 /* copy rb_io_t structure */
8582 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8583 fptr->encs = orig->encs;
8584 fptr->pid = orig->pid;
8585 fptr->lineno = orig->lineno;
8586 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8587 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8588 fptr_copy_finalizer(fptr, orig);
8589
8590 fd = fptr->fd;
8591 fd2 = orig->fd;
8592 if (fd != fd2) {
8593 // Interrupt all usage of the old file descriptor:
8594 rb_thread_io_close_interrupt(fptr);
8595 rb_thread_io_close_wait(fptr);
8596
8597 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8598 /* need to keep FILE objects of stdin, stdout and stderr */
8599 if (rb_cloexec_dup2(fd2, fd) < 0)
8600 rb_sys_fail_path(orig->pathv);
8601 rb_update_max_fd(fd);
8602 }
8603 else {
8604 fclose(fptr->stdio_file);
8605 fptr->stdio_file = 0;
8606 fptr->fd = -1;
8607 if (rb_cloexec_dup2(fd2, fd) < 0)
8608 rb_sys_fail_path(orig->pathv);
8609 rb_update_max_fd(fd);
8610 fptr->fd = fd;
8611 }
8612
8613 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8614 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8615 rb_sys_fail_path(fptr->pathv);
8616 }
8617 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8618 rb_sys_fail_path(orig->pathv);
8619 }
8620 }
8621 }
8622
8623 if (fptr->mode & FMODE_BINMODE) {
8624 rb_io_binmode(io);
8625 }
8626
8627 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8628 return io;
8629}
8630
8631#ifdef _WIN32
8632int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8633#else
8634static int
8635rb_freopen(VALUE fname, const char *mode, FILE *fp)
8636{
8637 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8638 RB_GC_GUARD(fname);
8639 return errno;
8640 }
8641 return 0;
8642}
8643#endif
8644
8645/*
8646 * call-seq:
8647 * reopen(other_io) -> self
8648 * reopen(path, mode = 'r', **opts) -> self
8649 *
8650 * Reassociates the stream with another stream,
8651 * which may be of a different class.
8652 * This method may be used to redirect an existing stream
8653 * to a new destination.
8654 *
8655 * With argument +other_io+ given, reassociates with that stream:
8656 *
8657 * # Redirect $stdin from a file.
8658 * f = File.open('t.txt')
8659 * $stdin.reopen(f)
8660 * f.close
8661 *
8662 * # Redirect $stdout to a file.
8663 * f = File.open('t.tmp', 'w')
8664 * $stdout.reopen(f)
8665 * f.close
8666 *
8667 * With argument +path+ given, reassociates with a new stream to that file path:
8668 *
8669 * $stdin.reopen('t.txt')
8670 * $stdout.reopen('t.tmp', 'w')
8671 *
8672 * Optional keyword arguments +opts+ specify:
8673 *
8674 * - {Open Options}[rdoc-ref:IO@Open+Options].
8675 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8676 *
8677 */
8678
8679static VALUE
8680rb_io_reopen(int argc, VALUE *argv, VALUE file)
8681{
8682 VALUE fname, nmode, opt;
8683 int oflags;
8684 rb_io_t *fptr;
8685
8686 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8687 VALUE tmp = rb_io_check_io(fname);
8688 if (!NIL_P(tmp)) {
8689 return io_reopen(file, tmp);
8690 }
8691 }
8692
8693 FilePathValue(fname);
8694 rb_io_taint_check(file);
8695 fptr = RFILE(file)->fptr;
8697
8698 if (!NIL_P(nmode) || !NIL_P(opt)) {
8699 enum rb_io_mode fmode;
8700 struct rb_io_encoding convconfig;
8701
8702 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8703 if (RUBY_IO_EXTERNAL_P(fptr) &&
8704 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8705 (fptr->mode & FMODE_READWRITE)) {
8706 rb_raise(rb_eArgError,
8707 "%s can't change access mode from \"%s\" to \"%s\"",
8708 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8709 rb_io_fmode_modestr(fmode));
8710 }
8711 fptr->mode = fmode;
8712 fptr->encs = convconfig;
8713 }
8714 else {
8715 oflags = rb_io_fmode_oflags(fptr->mode);
8716 }
8717
8718 fptr->pathv = fname;
8719 if (fptr->fd < 0) {
8720 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8721 fptr->stdio_file = 0;
8722 return file;
8723 }
8724
8725 if (fptr->mode & FMODE_WRITABLE) {
8726 if (io_fflush(fptr) < 0)
8727 rb_sys_fail_on_write(fptr);
8728 }
8729 fptr->rbuf.off = fptr->rbuf.len = 0;
8730 clear_codeconv(fptr);
8731
8732 if (fptr->stdio_file) {
8733 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8734 rb_io_oflags_modestr(oflags),
8735 fptr->stdio_file);
8736 if (e) rb_syserr_fail_path(e, fptr->pathv);
8737 fptr->fd = fileno(fptr->stdio_file);
8738 rb_fd_fix_cloexec(fptr->fd);
8739#ifdef USE_SETVBUF
8740 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8741 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8742#endif
8743 if (fptr->stdio_file == stderr) {
8744 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8745 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8746 }
8747 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8748 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8749 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8750 }
8751 }
8752 else {
8753 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8754 int err = 0;
8755 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8756 err = errno;
8757 (void)close(tmpfd);
8758 if (err) {
8759 rb_syserr_fail_path(err, fptr->pathv);
8760 }
8761 }
8762
8763 return file;
8764}
8765
8766/* :nodoc: */
8767static VALUE
8768rb_io_init_copy(VALUE dest, VALUE io)
8769{
8770 rb_io_t *fptr, *orig;
8771 int fd;
8772 VALUE write_io;
8773 rb_off_t pos;
8774
8775 io = rb_io_get_io(io);
8776 if (!OBJ_INIT_COPY(dest, io)) return dest;
8777 GetOpenFile(io, orig);
8778 MakeOpenFile(dest, fptr);
8779
8780 rb_io_flush(io);
8781
8782 /* copy rb_io_t structure */
8783 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8784 fptr->encs = orig->encs;
8785 fptr->pid = orig->pid;
8786 fptr->lineno = orig->lineno;
8787 fptr->timeout = orig->timeout;
8788
8789 ccan_list_head_init(&fptr->blocking_operations);
8790 fptr->closing_ec = NULL;
8791 fptr->wakeup_mutex = Qnil;
8792 fptr->fork_generation = GET_VM()->fork_gen;
8793
8794 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8795 fptr_copy_finalizer(fptr, orig);
8796
8797 fd = ruby_dup(orig->fd);
8798 fptr->fd = fd;
8799 pos = io_tell(orig);
8800 if (0 <= pos)
8801 io_seek(fptr, pos, SEEK_SET);
8802 if (fptr->mode & FMODE_BINMODE) {
8803 rb_io_binmode(dest);
8804 }
8805
8806 write_io = GetWriteIO(io);
8807 if (io != write_io) {
8808 write_io = rb_obj_dup(write_io);
8809 fptr->tied_io_for_writing = write_io;
8810 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8811 }
8812
8813 return dest;
8814}
8815
8816/*
8817 * call-seq:
8818 * printf(format_string, *objects) -> nil
8819 *
8820 * Formats and writes +objects+ to the stream.
8821 *
8822 * For details on +format_string+, see
8823 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8824 *
8825 */
8826
8827VALUE
8828rb_io_printf(int argc, const VALUE *argv, VALUE out)
8829{
8830 rb_io_write(out, rb_f_sprintf(argc, argv));
8831 return Qnil;
8832}
8833
8834/*
8835 * call-seq:
8836 * printf(format_string, *objects) -> nil
8837 * printf(io, format_string, *objects) -> nil
8838 *
8839 * Equivalent to:
8840 *
8841 * io.write(sprintf(format_string, *objects))
8842 *
8843 * For details on +format_string+, see
8844 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8845 *
8846 * With the single argument +format_string+, formats +objects+ into the string,
8847 * then writes the formatted string to $stdout:
8848 *
8849 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8850 *
8851 * Output (on $stdout):
8852 *
8853 * 0024 24 24.00#
8854 *
8855 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8856 * then writes the formatted string to +io+:
8857 *
8858 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8859 *
8860 * Output (on $stderr):
8861 *
8862 * 0024 24 24.00# => nil
8863 *
8864 * With no arguments, does nothing.
8865 *
8866 */
8867
8868static VALUE
8869rb_f_printf(int argc, VALUE *argv, VALUE _)
8870{
8871 VALUE out;
8872
8873 if (argc == 0) return Qnil;
8874 if (RB_TYPE_P(argv[0], T_STRING)) {
8875 out = rb_ractor_stdout();
8876 }
8877 else {
8878 out = argv[0];
8879 argv++;
8880 argc--;
8881 }
8882 rb_io_write(out, rb_f_sprintf(argc, argv));
8883
8884 return Qnil;
8885}
8886
8887extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
8888
8889static void
8890deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8891{
8892 rb_deprecated_str_setter(val, id, &val);
8893 if (!NIL_P(val)) {
8894 if (rb_str_equal(val, rb_default_rs)) {
8895 val = rb_default_rs;
8896 }
8897 else {
8898 val = rb_str_frozen_bare_string(val);
8899 }
8900 }
8901 *var = val;
8902}
8903
8904/*
8905 * call-seq:
8906 * print(*objects) -> nil
8907 *
8908 * Writes the given objects to the stream; returns +nil+.
8909 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8910 * (<tt>$\</tt>), if it is not +nil+.
8911 * See {Line IO}[rdoc-ref:IO@Line+IO].
8912 *
8913 * With argument +objects+ given, for each object:
8914 *
8915 * - Converts via its method +to_s+ if not a string.
8916 * - Writes to the stream.
8917 * - If not the last object, writes the output field separator
8918 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8919 *
8920 * With default separators:
8921 *
8922 * f = File.open('t.tmp', 'w+')
8923 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8924 * p $OUTPUT_RECORD_SEPARATOR
8925 * p $OUTPUT_FIELD_SEPARATOR
8926 * f.print(*objects)
8927 * f.rewind
8928 * p f.read
8929 * f.close
8930 *
8931 * Output:
8932 *
8933 * nil
8934 * nil
8935 * "00.00/10+0izerozero"
8936 *
8937 * With specified separators:
8938 *
8939 * $\ = "\n"
8940 * $, = ','
8941 * f.rewind
8942 * f.print(*objects)
8943 * f.rewind
8944 * p f.read
8945 *
8946 * Output:
8947 *
8948 * "0,0.0,0/1,0+0i,zero,zero\n"
8949 *
8950 * With no argument given, writes the content of <tt>$_</tt>
8951 * (which is usually the most recent user input):
8952 *
8953 * f = File.open('t.tmp', 'w+')
8954 * gets # Sets $_ to the most recent user input.
8955 * f.print
8956 * f.close
8957 *
8958 */
8959
8960VALUE
8961rb_io_print(int argc, const VALUE *argv, VALUE out)
8962{
8963 int i;
8964 VALUE line;
8965
8966 /* if no argument given, print `$_' */
8967 if (argc == 0) {
8968 argc = 1;
8969 line = rb_lastline_get();
8970 argv = &line;
8971 }
8972 if (argc > 1 && !NIL_P(rb_output_fs)) {
8973 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8974 }
8975 for (i=0; i<argc; i++) {
8976 if (!NIL_P(rb_output_fs) && i>0) {
8977 rb_io_write(out, rb_output_fs);
8978 }
8979 rb_io_write(out, argv[i]);
8980 }
8981 if (argc > 0 && !NIL_P(rb_output_rs)) {
8982 rb_io_write(out, rb_output_rs);
8983 }
8984
8985 return Qnil;
8986}
8987
8988/*
8989 * call-seq:
8990 * print(*objects) -> nil
8991 *
8992 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8993 * this method is the straightforward way to write to <tt>$stdout</tt>.
8994 *
8995 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8996 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8997 * (<tt>$\</tt>), if it is not +nil+.
8998 *
8999 * With argument +objects+ given, for each object:
9000 *
9001 * - Converts via its method +to_s+ if not a string.
9002 * - Writes to <tt>stdout</tt>.
9003 * - If not the last object, writes the output field separator
9004 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
9005 *
9006 * With default separators:
9007 *
9008 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
9009 * $OUTPUT_RECORD_SEPARATOR
9010 * $OUTPUT_FIELD_SEPARATOR
9011 * print(*objects)
9012 *
9013 * Output:
9014 *
9015 * nil
9016 * nil
9017 * 00.00/10+0izerozero
9018 *
9019 * With specified separators:
9020 *
9021 * $OUTPUT_RECORD_SEPARATOR = "\n"
9022 * $OUTPUT_FIELD_SEPARATOR = ','
9023 * print(*objects)
9024 *
9025 * Output:
9026 *
9027 * 0,0.0,0/1,0+0i,zero,zero
9028 *
9029 * With no argument given, writes the content of <tt>$_</tt>
9030 * (which is usually the most recent user input):
9031 *
9032 * gets # Sets $_ to the most recent user input.
9033 * print # Prints $_.
9034 *
9035 */
9036
9037static VALUE
9038rb_f_print(int argc, const VALUE *argv, VALUE _)
9039{
9040 rb_io_print(argc, argv, rb_ractor_stdout());
9041 return Qnil;
9042}
9043
9044/*
9045 * call-seq:
9046 * putc(object) -> object
9047 *
9048 * Writes a character to the stream.
9049 * See {Character IO}[rdoc-ref:IO@Character+IO].
9050 *
9051 * If +object+ is numeric, converts to integer if necessary,
9052 * then writes the character whose code is the
9053 * least significant byte;
9054 * if +object+ is a string, writes the first character:
9055 *
9056 * $stdout.putc "A"
9057 * $stdout.putc 65
9058 *
9059 * Output:
9060 *
9061 * AA
9062 *
9063 */
9064
9065static VALUE
9066rb_io_putc(VALUE io, VALUE ch)
9067{
9068 VALUE str;
9069 if (RB_TYPE_P(ch, T_STRING)) {
9070 str = rb_str_substr(ch, 0, 1);
9071 }
9072 else {
9073 char c = NUM2CHR(ch);
9074 str = rb_str_new(&c, 1);
9075 }
9076 rb_io_write(io, str);
9077 return ch;
9078}
9079
9080#define forward(obj, id, argc, argv) \
9081 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9082#define forward_public(obj, id, argc, argv) \
9083 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9084#define forward_current(id, argc, argv) \
9085 forward_public(ARGF.current_file, id, argc, argv)
9086
9087/*
9088 * call-seq:
9089 * putc(int) -> int
9090 *
9091 * Equivalent to:
9092 *
9093 * $stdout.putc(int)
9094 *
9095 * See IO#putc for important information regarding multi-byte characters.
9096 *
9097 */
9098
9099static VALUE
9100rb_f_putc(VALUE recv, VALUE ch)
9101{
9102 VALUE r_stdout = rb_ractor_stdout();
9103 if (recv == r_stdout) {
9104 return rb_io_putc(recv, ch);
9105 }
9106 return forward(r_stdout, rb_intern("putc"), 1, &ch);
9107}
9108
9109
9110int
9111rb_str_end_with_asciichar(VALUE str, int c)
9112{
9113 rb_len_t len = RSTRING_LEN(str);
9114 const char *ptr = RSTRING_PTR(str);
9115 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
9116 int n;
9117
9118 if (len == 0) return 0;
9119 if ((n = rb_enc_mbminlen(enc)) == 1) {
9120 return ptr[len - 1] == c;
9121 }
9122 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
9123}
9124
9125static VALUE
9126io_puts_ary(VALUE ary, VALUE out, int recur)
9127{
9128 VALUE tmp;
9129 rb_len_t i;
9130
9131 if (recur) {
9132 tmp = rb_str_new2("[...]");
9133 rb_io_puts(1, &tmp, out);
9134 return Qtrue;
9135 }
9136 ary = rb_check_array_type(ary);
9137 if (NIL_P(ary)) return Qfalse;
9138 for (i=0; i<RARRAY_LEN(ary); i++) {
9139 tmp = RARRAY_AREF(ary, i);
9140 rb_io_puts(1, &tmp, out);
9141 }
9142 return Qtrue;
9143}
9144
9145/*
9146 * call-seq:
9147 * puts(*objects) -> nil
9148 *
9149 * Writes the given +objects+ to the stream, which must be open for writing;
9150 * returns +nil+.\
9151 * Writes a newline after each that does not already end with a newline sequence.
9152 * If called without arguments, writes a newline.
9153 * See {Line IO}[rdoc-ref:IO@Line+IO].
9154 *
9155 * Note that each added newline is the character <tt>"\n"</tt>,
9156 * not the output record separator (<tt>$\</tt>).
9157 *
9158 * Treatment for each object:
9159 *
9160 * - String: writes the string.
9161 * - Neither string nor array: writes <tt>object.to_s</tt>.
9162 * - Array: writes each element of the array; arrays may be nested.
9163 *
9164 * To keep these examples brief, we define this helper method:
9165 *
9166 * def show(*objects)
9167 * # Puts objects to file.
9168 * f = File.new('t.tmp', 'w+')
9169 * f.puts(objects)
9170 * # Return file content.
9171 * f.rewind
9172 * p f.read
9173 * f.close
9174 * end
9175 *
9176 * # Strings without newlines.
9177 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
9178 * # Strings, some with newlines.
9179 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
9180 *
9181 * # Neither strings nor arrays:
9182 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
9183 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
9184 *
9185 * # Array of strings.
9186 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
9187 * # Nested arrays.
9188 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
9189 *
9190 */
9191
9192VALUE
9193rb_io_puts(int argc, const VALUE *argv, VALUE out)
9194{
9195 VALUE line, args[2];
9196
9197 /* if no argument given, print newline. */
9198 if (argc == 0) {
9199 rb_io_write(out, rb_default_rs);
9200 return Qnil;
9201 }
9202 for (int i = 0; i < argc; i++) {
9203 // Convert the argument to a string:
9204 if (RB_TYPE_P(argv[i], T_STRING)) {
9205 line = argv[i];
9206 }
9207 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9208 continue;
9209 }
9210 else {
9211 line = rb_obj_as_string(argv[i]);
9212 }
9213
9214 // Write the line:
9215 int n = 0;
9216 if (RSTRING_LEN(line) == 0) {
9217 args[n++] = rb_default_rs;
9218 }
9219 else {
9220 args[n++] = line;
9221 if (!rb_str_end_with_asciichar(line, '\n')) {
9222 args[n++] = rb_default_rs;
9223 }
9224 }
9225
9226 rb_io_writev(out, n, args);
9227 }
9228
9229 return Qnil;
9230}
9231
9232/*
9233 * call-seq:
9234 * puts(*objects) -> nil
9235 *
9236 * Equivalent to
9237 *
9238 * $stdout.puts(objects)
9239 */
9240
9241static VALUE
9242rb_f_puts(int argc, VALUE *argv, VALUE recv)
9243{
9244 VALUE r_stdout = rb_ractor_stdout();
9245 if (recv == r_stdout) {
9246 return rb_io_puts(argc, argv, recv);
9247 }
9248 return forward(r_stdout, rb_intern("puts"), argc, argv);
9249}
9250
9251static VALUE
9252rb_p_write(VALUE str)
9253{
9254 VALUE args[2];
9255 args[0] = str;
9256 args[1] = rb_default_rs;
9257 VALUE r_stdout = rb_ractor_stdout();
9258 if (RB_TYPE_P(r_stdout, T_FILE) &&
9259 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9260 io_writev(2, args, r_stdout);
9261 }
9262 else {
9263 rb_io_writev(r_stdout, 2, args);
9264 }
9265 return Qnil;
9266}
9267
9268void
9269rb_p(VALUE obj) /* for debug print within C code */
9270{
9271 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9272}
9273
9274static VALUE
9275rb_p_result(int argc, const VALUE *argv)
9276{
9277 VALUE ret = Qnil;
9278
9279 if (argc == 1) {
9280 ret = argv[0];
9281 }
9282 else if (argc > 1) {
9283 ret = rb_ary_new4(argc, argv);
9284 }
9285 VALUE r_stdout = rb_ractor_stdout();
9286 if (RB_TYPE_P(r_stdout, T_FILE)) {
9287 rb_uninterruptible(rb_io_flush, r_stdout);
9288 }
9289 return ret;
9290}
9291
9292/*
9293 * call-seq:
9294 * p(object) -> obj
9295 * p(*objects) -> array of objects
9296 * p -> nil
9297 *
9298 * For each object +obj+, executes:
9299 *
9300 * $stdout.write(obj.inspect, "\n")
9301 *
9302 * With one object given, returns the object;
9303 * with multiple objects given, returns an array containing the objects;
9304 * with no object given, returns +nil+.
9305 *
9306 * Examples:
9307 *
9308 * r = Range.new(0, 4)
9309 * p r # => 0..4
9310 * p [r, r, r] # => [0..4, 0..4, 0..4]
9311 * p # => nil
9312 *
9313 * Output:
9314 *
9315 * 0..4
9316 * [0..4, 0..4, 0..4]
9317 *
9318 * Kernel#p is designed for debugging purposes.
9319 * Ruby implementations may define Kernel#p to be uninterruptible
9320 * in whole or in part.
9321 * On CRuby, Kernel#p's writing of data is uninterruptible.
9322 */
9323
9324static VALUE
9325rb_f_p(int argc, VALUE *argv, VALUE self)
9326{
9327 int i;
9328 for (i=0; i<argc; i++) {
9329 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9330 rb_uninterruptible(rb_p_write, inspected);
9331 }
9332 return rb_p_result(argc, argv);
9333}
9334
9335/*
9336 * call-seq:
9337 * display(port = $>) -> nil
9338 *
9339 * Writes +self+ on the given port:
9340 *
9341 * 1.display
9342 * "cat".display
9343 * [ 4, 5, 6 ].display
9344 * puts
9345 *
9346 * Output:
9347 *
9348 * 1cat[4, 5, 6]
9349 *
9350 */
9351
9352static VALUE
9353rb_obj_display(int argc, VALUE *argv, VALUE self)
9354{
9355 VALUE out;
9356
9357 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9358 rb_io_write(out, self);
9359
9360 return Qnil;
9361}
9362
9363static int
9364rb_stderr_to_original_p(VALUE err)
9365{
9366 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9367}
9368
9369void
9370rb_write_error2(const char *mesg, rb_len_t len)
9371{
9372 VALUE out = rb_ractor_stderr();
9373 if (rb_stderr_to_original_p(out)) {
9374#ifdef _WIN32
9375 if (isatty(fileno(stderr))) {
9376 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9377 }
9378#endif
9379 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9380 /* failed to write to stderr, what can we do? */
9381 return;
9382 }
9383 }
9384 else {
9385 rb_io_write(out, rb_str_new(mesg, len));
9386 }
9387}
9388
9389void
9390rb_write_error(const char *mesg)
9391{
9392 rb_write_error2(mesg, strlen(mesg));
9393}
9394
9395void
9396rb_write_error_str(VALUE mesg)
9397{
9398 VALUE out = rb_ractor_stderr();
9399 /* a stopgap measure for the time being */
9400 if (rb_stderr_to_original_p(out)) {
9401 size_t len = (size_t)RSTRING_LEN(mesg);
9402#ifdef _WIN32
9403 if (isatty(fileno(stderr))) {
9404 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9405 }
9406#endif
9407 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9408 RB_GC_GUARD(mesg);
9409 return;
9410 }
9411 }
9412 else {
9413 /* may unlock GVL, and */
9414 rb_io_write(out, mesg);
9415 }
9416}
9417
9418int
9419rb_stderr_tty_p(void)
9420{
9421 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9422 return isatty(fileno(stderr));
9423 return 0;
9424}
9425
9426static void
9427must_respond_to(ID mid, VALUE val, ID id)
9428{
9429 if (!rb_respond_to(val, mid)) {
9430 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9431 rb_id2str(id), rb_id2str(mid),
9432 rb_obj_class(val));
9433 }
9434}
9435
9436static void
9437stdin_setter(VALUE val, ID id, VALUE *ptr)
9438{
9440}
9441
9442static VALUE
9443stdin_getter(ID id, VALUE *ptr)
9444{
9445 return rb_ractor_stdin();
9446}
9447
9448static void
9449stdout_setter(VALUE val, ID id, VALUE *ptr)
9450{
9451 must_respond_to(id_write, val, id);
9453}
9454
9455static VALUE
9456stdout_getter(ID id, VALUE *ptr)
9457{
9458 return rb_ractor_stdout();
9459}
9460
9461static void
9462stderr_setter(VALUE val, ID id, VALUE *ptr)
9463{
9464 must_respond_to(id_write, val, id);
9466}
9467
9468static VALUE
9469stderr_getter(ID id, VALUE *ptr)
9470{
9471 return rb_ractor_stderr();
9472}
9473
9474static VALUE
9475allocate_and_open_new_file(VALUE klass)
9476{
9477 VALUE self = io_alloc(klass);
9478 rb_io_make_open_file(self);
9479 return self;
9480}
9481
9482VALUE
9483rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9484{
9485 int state;
9486 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9487 if (state) {
9488 /* if we raised an exception allocating an IO object, but the caller
9489 intended to transfer ownership of this FD to us, close the fd before
9490 raising the exception. Otherwise, we would leak a FD - the caller
9491 expects GC to close the file, but we never got around to assigning
9492 it to a rb_io. */
9493 if (!(mode & FMODE_EXTERNAL)) {
9494 maygvl_close(descriptor, 0);
9495 }
9496 rb_jump_tag(state);
9497 }
9498
9499
9500 rb_io_t *io = RFILE(self)->fptr;
9501 io->self = self;
9502 io->fd = descriptor;
9503 io->mode = mode;
9504
9505 /* At this point, Ruby fully owns the descriptor, and will close it when
9506 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9507 in the rest of this method. */
9508
9509 if (NIL_P(path)) {
9510 io->pathv = Qnil;
9511 }
9512 else {
9513 StringValue(path);
9514 io->pathv = rb_str_new_frozen(path);
9515 }
9516
9517 io->timeout = timeout;
9518
9519 ccan_list_head_init(&io->blocking_operations);
9520 io->closing_ec = NULL;
9521 io->wakeup_mutex = Qnil;
9522 io->fork_generation = GET_VM()->fork_gen;
9523
9524 if (encoding) {
9525 io->encs = *encoding;
9526 }
9527
9528 rb_update_max_fd(descriptor);
9529
9530 return self;
9531}
9532
9533static VALUE
9534prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9535{
9536 VALUE path_value = Qnil;
9537 rb_encoding *e;
9538 struct rb_io_encoding convconfig;
9539
9540 if (path) {
9541 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9542 }
9543
9544 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9545 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9546 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9549#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9550 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9551 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9552 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9553#endif
9554 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9555 convconfig.ecopts = Qnil;
9556
9557 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9558 rb_io_t*io = RFILE(self)->fptr;
9559
9560 if (!io_check_tty(io)) {
9561#ifdef __CYGWIN__
9562 io->mode |= FMODE_BINMODE;
9563 setmode(fd, O_BINARY);
9564#endif
9565 }
9566
9567 return self;
9568}
9569
9570VALUE
9571rb_io_fdopen(int fd, int oflags, const char *path)
9572{
9573 VALUE klass = rb_cIO;
9574
9575 if (path && strcmp(path, "-")) klass = rb_cFile;
9576 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9577}
9578
9579static VALUE
9580prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9581{
9582 rb_io_t *fptr;
9583 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9584
9585 GetOpenFile(io, fptr);
9587#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9588 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9589 if (fmode & FMODE_READABLE) {
9591 }
9592#endif
9593 fptr->stdio_file = f;
9594
9595 return io;
9596}
9597
9598VALUE
9599rb_io_prep_stdin(void)
9600{
9601 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9602}
9603
9604VALUE
9605rb_io_prep_stdout(void)
9606{
9607 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9608}
9609
9610VALUE
9611rb_io_prep_stderr(void)
9612{
9613 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9614}
9615
9616FILE *
9618{
9619 if (!fptr->stdio_file) {
9620 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9621 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9622 }
9623 return fptr->stdio_file;
9624}
9625
9626static inline void
9627rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9628{
9629 buf->ptr = NULL;
9630 buf->off = 0;
9631 buf->len = 0;
9632 buf->capa = 0;
9633}
9634
9635static inline rb_io_t *
9636rb_io_fptr_new(void)
9637{
9638 rb_io_t *fp = ALLOC(rb_io_t);
9639 fp->self = Qnil;
9640 fp->fd = -1;
9641 fp->stdio_file = NULL;
9642 fp->mode = 0;
9643 fp->pid = 0;
9644 fp->lineno = 0;
9645 fp->pathv = Qnil;
9646 fp->finalize = 0;
9647 rb_io_buffer_init(&fp->wbuf);
9648 rb_io_buffer_init(&fp->rbuf);
9649 rb_io_buffer_init(&fp->cbuf);
9650 fp->readconv = NULL;
9651 fp->writeconv = NULL;
9653 fp->writeconv_pre_ecflags = 0;
9655 fp->writeconv_initialized = 0;
9656 fp->tied_io_for_writing = 0;
9657 fp->encs.enc = NULL;
9658 fp->encs.enc2 = NULL;
9659 fp->encs.ecflags = 0;
9660 fp->encs.ecopts = Qnil;
9661 fp->write_lock = Qnil;
9662 fp->timeout = Qnil;
9663 ccan_list_head_init(&fp->blocking_operations);
9664 fp->closing_ec = NULL;
9665 fp->wakeup_mutex = Qnil;
9666 fp->fork_generation = GET_VM()->fork_gen;
9667 return fp;
9668}
9669
9670rb_io_t *
9671rb_io_make_open_file(VALUE obj)
9672{
9673 rb_io_t *fp = 0;
9674
9675 Check_Type(obj, T_FILE);
9676 if (RFILE(obj)->fptr) {
9677 rb_io_close(obj);
9678 rb_io_fptr_finalize(RFILE(obj)->fptr);
9679 RFILE(obj)->fptr = 0;
9680 }
9681 fp = rb_io_fptr_new();
9682 fp->self = obj;
9683 RFILE(obj)->fptr = fp;
9684 return fp;
9685}
9686
9687static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9688
9689/*
9690 * call-seq:
9691 * IO.new(fd, mode = 'r', **opts) -> io
9692 *
9693 * Creates and returns a new \IO object (file stream) from a file descriptor.
9694 *
9695 * \IO.new may be useful for interaction with low-level libraries.
9696 * For higher-level interactions, it may be simpler to create
9697 * the file stream using File.open.
9698 *
9699 * Argument +fd+ must be a valid file descriptor (integer):
9700 *
9701 * path = 't.tmp'
9702 * fd = IO.sysopen(path) # => 3
9703 * IO.new(fd) # => #<IO:fd 3>
9704 *
9705 * The new \IO object does not inherit encoding
9706 * (because the integer file descriptor does not have an encoding):
9707 *
9708 * File.read('t.ja') # => "こんにちは"
9709 * fd = IO.sysopen('t.ja', 'rb')
9710 * io = IO.new(fd)
9711 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9712 *
9713 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9714 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9715 *
9716 * IO.new(fd, 'w') # => #<IO:fd 3>
9717 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9718 *
9719 * Optional keyword arguments +opts+ specify:
9720 *
9721 * - {Open Options}[rdoc-ref:IO@Open+Options].
9722 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9723 *
9724 * Examples:
9725 *
9726 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9727 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9728 *
9729 */
9730
9731static VALUE
9732rb_io_initialize(int argc, VALUE *argv, VALUE io)
9733{
9734 VALUE fnum, vmode;
9735 VALUE opt;
9736
9737 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9738 return io_initialize(io, fnum, vmode, opt);
9739}
9740
9741static VALUE
9742io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9743{
9744 rb_io_t *fp;
9745 int fd, oflags = O_RDONLY;
9746 enum rb_io_mode fmode;
9747 struct rb_io_encoding convconfig;
9748#if defined(HAVE_FCNTL) && defined(F_GETFL)
9749 int ofmode;
9750#else
9751 struct stat st;
9752#endif
9753
9754 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9755
9756 fd = NUM2INT(fnum);
9757 if (rb_reserved_fd_p(fd)) {
9758 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9759 }
9760#if defined(HAVE_FCNTL) && defined(F_GETFL)
9761 oflags = fcntl(fd, F_GETFL);
9762 if (oflags == -1) rb_sys_fail(0);
9763#else
9764 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9765#endif
9766 rb_update_max_fd(fd);
9767#if defined(HAVE_FCNTL) && defined(F_GETFL)
9768 ofmode = rb_io_oflags_fmode(oflags);
9769 if (NIL_P(vmode)) {
9770 fmode = ofmode;
9771 }
9772 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9773 VALUE error = INT2FIX(EINVAL);
9775 }
9776#endif
9777 VALUE path = Qnil;
9778
9779 if (!NIL_P(opt)) {
9780 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9781 fmode |= FMODE_EXTERNAL;
9782 }
9783
9784 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9785 if (!NIL_P(path)) {
9786 StringValue(path);
9787 path = rb_str_new_frozen(path);
9788 }
9789 }
9790
9791 MakeOpenFile(io, fp);
9792 fp->self = io;
9793 fp->fd = fd;
9794 fp->mode = fmode;
9795 fp->encs = convconfig;
9796 fp->pathv = path;
9797 fp->timeout = Qnil;
9798 ccan_list_head_init(&fp->blocking_operations);
9799 fp->closing_ec = NULL;
9800 fp->wakeup_mutex = Qnil;
9801 fp->fork_generation = GET_VM()->fork_gen;
9802 clear_codeconv(fp);
9803 io_check_tty(fp);
9804 if (fileno(stdin) == fd)
9805 fp->stdio_file = stdin;
9806 else if (fileno(stdout) == fd)
9807 fp->stdio_file = stdout;
9808 else if (fileno(stderr) == fd)
9809 fp->stdio_file = stderr;
9810
9811 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9812 return io;
9813}
9814
9815/*
9816 * call-seq:
9817 * set_encoding_by_bom -> encoding or nil
9818 *
9819 * If the stream begins with a BOM
9820 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9821 * consumes the BOM and sets the external encoding accordingly;
9822 * returns the result encoding if found, or +nil+ otherwise:
9823 *
9824 * File.write('t.tmp', "\u{FEFF}abc")
9825 * io = File.open('t.tmp', 'rb')
9826 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9827 * io.close
9828 *
9829 * File.write('t.tmp', 'abc')
9830 * io = File.open('t.tmp', 'rb')
9831 * io.set_encoding_by_bom # => nil
9832 * io.close
9833 *
9834 * Raises an exception if the stream is not binmode
9835 * or its encoding has already been set.
9836 *
9837 */
9838
9839static VALUE
9840rb_io_set_encoding_by_bom(VALUE io)
9841{
9842 rb_io_t *fptr;
9843
9844 GetOpenFile(io, fptr);
9845 if (!(fptr->mode & FMODE_BINMODE)) {
9846 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9847 }
9848 if (fptr->encs.enc2) {
9849 rb_raise(rb_eArgError, "encoding conversion is set");
9850 }
9851 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9852 rb_raise(rb_eArgError, "encoding is set to %s already",
9853 rb_enc_name(fptr->encs.enc));
9854 }
9855 if (!io_set_encoding_by_bom(io)) return Qnil;
9856 return rb_enc_from_encoding(fptr->encs.enc);
9857}
9858
9859/*
9860 * :markup: markdown
9861 *
9862 * call-seq:
9863 * File.new(path, mode = 'r', permissions = 0666, **options) -> file
9864 *
9865 * Opens the file as specified by the given arguments.
9866 * Creates and returns a new open \File object for that file;
9867 * the opened file is in non-synchronous mode.
9868 *
9869 * Argument `path` must the string path to an existing filesystem entry:
9870 *
9871 * ```ruby
9872 * file = File.new('doc/maintainers.md') # => #<File:doc/maintainers.md>
9873 * file.close # Clean up.
9874 * tty = File.new('/dev/tty') # => #<File:/dev/tty>
9875 * tty.close # Clean up.
9876 * ```
9877 *
9878 * Note that the caller is responsible for closing the file;
9879 * see File.open for automatic closing.
9880 *
9881 * Optional argument `mode` (defaults to `'r'`) must specify a valid mode;
9882 * see [Access Modes](rdoc-ref:File@Access+Modes):
9883 *
9884 * ```ruby
9885 * file = File.new('t.tmp', 'w') # => #<File:t.tmp>
9886 * file.close # Clean up.
9887 * file = File.new('t.tmp', File::RDONLY) # => #<File:t.tmp>
9888 * file.close # Clean up.
9889 * ```
9890 *
9891 * Optional argument `permissions` (defaults to `0666`) must specify valid permissions;
9892 * see [File Permissions](rdoc-ref:File@File+Permissions):
9893 *
9894 * ```ruby
9895 * file = File.new('t.tmp', 'w', 0644) # => #<File:t.tmp>
9896 * file.close # Clean up.
9897 * file = File.new('t.tmp', 'w', 0444) # => #<File:t.tmp>
9898 * file.close # Clean up.
9899 * ```
9900 *
9901 * Optional keyword arguments `options` specify:
9902 *
9903 * - [Open Options](rdoc-ref:IO@Open+Options).
9904 * - [Encoding options](rdoc-ref:encodings.rdoc@Encoding+Options).
9905 *
9906 */
9907
9908static VALUE
9909rb_file_initialize(int argc, VALUE *argv, VALUE io)
9910{
9911 if (RFILE(io)->fptr) {
9912 rb_raise(rb_eRuntimeError, "reinitializing File");
9913 }
9914 VALUE fname, vmode, vperm, opt;
9915 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9916 if (posargc < 3) { /* perm is File only */
9917 VALUE fd = rb_check_to_int(fname);
9918
9919 if (!NIL_P(fd)) {
9920 return io_initialize(io, fd, vmode, opt);
9921 }
9922 }
9923 return rb_open_file(io, fname, vmode, vperm, opt);
9924}
9925
9926/* :nodoc: */
9927static VALUE
9928rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9929{
9930 if (rb_block_given_p()) {
9931 VALUE cname = rb_obj_as_string(klass);
9932
9933 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9934 cname, cname);
9935 }
9936 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9937}
9938
9939
9940/*
9941 * call-seq:
9942 * IO.for_fd(fd, mode = 'r', **opts) -> io
9943 *
9944 * Synonym for IO.new.
9945 *
9946 */
9947
9948static VALUE
9949rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9950{
9951 VALUE io = rb_obj_alloc(klass);
9952 rb_io_initialize(argc, argv, io);
9953 return io;
9954}
9955
9956/*
9957 * call-seq:
9958 * ios.autoclose? -> true or false
9959 *
9960 * Returns +true+ if the underlying file descriptor of _ios_ will be
9961 * closed at its finalization or at calling #close, otherwise +false+.
9962 */
9963
9964static VALUE
9965rb_io_autoclose_p(VALUE io)
9966{
9967 rb_io_t *fptr = RFILE(io)->fptr;
9968 rb_io_check_closed(fptr);
9969 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9970}
9971
9972/*
9973 * call-seq:
9974 * io.autoclose = bool -> true or false
9975 *
9976 * Sets auto-close flag.
9977 *
9978 * f = File.open(File::NULL)
9979 * IO.for_fd(f.fileno).close
9980 * f.gets # raises Errno::EBADF
9981 *
9982 * f = File.open(File::NULL)
9983 * g = IO.for_fd(f.fileno)
9984 * g.autoclose = false
9985 * g.close
9986 * f.gets # won't cause Errno::EBADF
9987 */
9988
9989static VALUE
9990rb_io_set_autoclose(VALUE io, VALUE autoclose)
9991{
9992 rb_io_t *fptr;
9993 GetOpenFile(io, fptr);
9994 if (!RTEST(autoclose))
9995 fptr->mode |= FMODE_EXTERNAL;
9996 else
9997 fptr->mode &= ~FMODE_EXTERNAL;
9998 return autoclose;
9999}
10000
10001static VALUE
10002io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
10003{
10004 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
10005
10006 if (!RB_TEST(result)) {
10007 return Qnil;
10008 }
10009
10010 int mask = RB_NUM2INT(result);
10011
10012 if (mask & event) {
10013 if (return_io)
10014 return io;
10015 else
10016 return result;
10017 }
10018 else {
10019 return Qfalse;
10020 }
10021}
10022
10023/*
10024 * call-seq:
10025 * io.wait_readable -> truthy or falsy
10026 * io.wait_readable(timeout) -> truthy or falsy
10027 *
10028 * Waits until IO is readable and returns a truthy value, or a falsy
10029 * value when times out. Returns a truthy value immediately when
10030 * buffered data is available.
10031 */
10032
10033static VALUE
10034io_wait_readable(int argc, VALUE *argv, VALUE io)
10035{
10036 rb_io_t *fptr;
10037
10038 RB_IO_POINTER(io, fptr);
10040
10041 if (rb_io_read_pending(fptr)) return Qtrue;
10042
10043 rb_check_arity(argc, 0, 1);
10044 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
10045
10046 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
10047}
10048
10049/*
10050 * call-seq:
10051 * io.wait_writable -> truthy or falsy
10052 * io.wait_writable(timeout) -> truthy or falsy
10053 *
10054 * Waits until IO is writable and returns a truthy value or a falsy
10055 * value when times out.
10056 */
10057static VALUE
10058io_wait_writable(int argc, VALUE *argv, VALUE io)
10059{
10060 rb_io_t *fptr;
10061
10062 RB_IO_POINTER(io, fptr);
10064
10065 rb_check_arity(argc, 0, 1);
10066 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
10067
10068 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
10069}
10070
10071/*
10072 * call-seq:
10073 * io.wait_priority -> truthy or falsy
10074 * io.wait_priority(timeout) -> truthy or falsy
10075 *
10076 * Waits until IO is priority and returns a truthy value or a falsy
10077 * value when times out. Priority data is sent and received using
10078 * the Socket::MSG_OOB flag and is typically limited to streams.
10079 */
10080static VALUE
10081io_wait_priority(int argc, VALUE *argv, VALUE io)
10082{
10083 rb_io_t *fptr = NULL;
10084
10085 RB_IO_POINTER(io, fptr);
10087
10088 if (rb_io_read_pending(fptr)) return Qtrue;
10089
10090 rb_check_arity(argc, 0, 1);
10091 VALUE timeout = argc == 1 ? argv[0] : Qnil;
10092
10093 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
10094}
10095
10096static int
10097wait_mode_sym(VALUE mode)
10098{
10099 if (mode == ID2SYM(rb_intern("r"))) {
10100 return RB_WAITFD_IN;
10101 }
10102 if (mode == ID2SYM(rb_intern("read"))) {
10103 return RB_WAITFD_IN;
10104 }
10105 if (mode == ID2SYM(rb_intern("readable"))) {
10106 return RB_WAITFD_IN;
10107 }
10108 if (mode == ID2SYM(rb_intern("w"))) {
10109 return RB_WAITFD_OUT;
10110 }
10111 if (mode == ID2SYM(rb_intern("write"))) {
10112 return RB_WAITFD_OUT;
10113 }
10114 if (mode == ID2SYM(rb_intern("writable"))) {
10115 return RB_WAITFD_OUT;
10116 }
10117 if (mode == ID2SYM(rb_intern("rw"))) {
10118 return RB_WAITFD_IN|RB_WAITFD_OUT;
10119 }
10120 if (mode == ID2SYM(rb_intern("read_write"))) {
10121 return RB_WAITFD_IN|RB_WAITFD_OUT;
10122 }
10123 if (mode == ID2SYM(rb_intern("readable_writable"))) {
10124 return RB_WAITFD_IN|RB_WAITFD_OUT;
10125 }
10126
10127 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
10128}
10129
10130static inline enum rb_io_event
10131io_event_from_value(VALUE value)
10132{
10133 int events = RB_NUM2INT(value);
10134
10135 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
10136
10137 return events;
10138}
10139
10140/*
10141 * call-seq:
10142 * io.wait(events, timeout) -> event mask, false or nil
10143 * io.wait(*event_symbols[, timeout]) -> self, true, or false
10144 *
10145 * Waits until the IO becomes ready for the specified events and returns the
10146 * subset of events that become ready, or a falsy value when times out.
10147 *
10148 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
10149 * +IO::PRIORITY+.
10150 *
10151 * Returns an event mask (truthy value) immediately when buffered data is
10152 * available.
10153 *
10154 * The second form: if one or more event symbols (+:read+, +:write+, or
10155 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
10156 * corresponding to those symbols. In this form, +timeout+ is optional, the
10157 * order of the arguments is arbitrary, and returns +io+ if any of the
10158 * events is ready.
10159 */
10160
10161static VALUE
10162io_wait(int argc, VALUE *argv, VALUE io)
10163{
10164 VALUE timeout = Qundef;
10165 enum rb_io_event events = 0;
10166 int return_io = 0;
10167
10168 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
10169 // We'd prefer to return the actual mask, but this form would return the io itself:
10170 return_io = 1;
10171
10172 // Slow/messy path:
10173 for (int i = 0; i < argc; i += 1) {
10174 if (RB_SYMBOL_P(argv[i])) {
10175 events |= wait_mode_sym(argv[i]);
10176 }
10177 else if (UNDEF_P(timeout)) {
10178 rb_time_interval(timeout = argv[i]);
10179 }
10180 else {
10181 rb_raise(rb_eArgError, "timeout given more than once");
10182 }
10183 }
10184
10185 if (UNDEF_P(timeout)) timeout = Qnil;
10186
10187 if (events == 0) {
10188 events = RUBY_IO_READABLE;
10189 }
10190 }
10191 else /* argc == 2 and neither are symbols */ {
10192 // This is the fast path:
10193 events = io_event_from_value(argv[0]);
10194 timeout = argv[1];
10195 }
10196
10197 if (events & RUBY_IO_READABLE) {
10198 rb_io_t *fptr = NULL;
10199 RB_IO_POINTER(io, fptr);
10200
10201 if (rb_io_read_pending(fptr)) {
10202 // This was the original behaviour:
10203 if (return_io) return Qtrue;
10204 // New behaviour always returns an event mask:
10205 else return RB_INT2NUM(RUBY_IO_READABLE);
10206 }
10207 }
10208
10209 return io_wait_event(io, events, timeout, return_io);
10210}
10211
10212static void
10213argf_mark_and_move(void *ptr)
10214{
10215 struct argf *p = ptr;
10216 rb_gc_mark_and_move(&p->filename);
10217 rb_gc_mark_and_move(&p->current_file);
10218 rb_gc_mark_and_move(&p->argv);
10219 rb_gc_mark_and_move(&p->inplace);
10220 rb_gc_mark_and_move(&p->encs.ecopts);
10221}
10222
10223static size_t
10224argf_memsize(const void *ptr)
10225{
10226 const struct argf *p = ptr;
10227 size_t size = sizeof(*p);
10228 return size;
10229}
10230
10231static const rb_data_type_t argf_type = {
10232 "ARGF",
10233 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10234 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10235};
10236
10237static inline void
10238argf_init(VALUE argf, struct argf *p, VALUE v)
10239{
10240 p->filename = Qnil;
10241 p->current_file = Qnil;
10242 p->lineno = 0;
10243 RB_OBJ_WRITE(argf, &p->argv, v);
10244}
10245
10246static VALUE
10247argf_alloc(VALUE klass)
10248{
10249 struct argf *p;
10250 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10251
10252 argf_init(argf, p, Qnil);
10253 return argf;
10254}
10255
10256#undef rb_argv
10257
10258/* :nodoc: */
10259static VALUE
10260argf_initialize(VALUE argf, VALUE argv)
10261{
10262 memset(&ARGF, 0, sizeof(ARGF));
10263 argf_init(argf, &ARGF, argv);
10264
10265 return argf;
10266}
10267
10268/* :nodoc: */
10269static VALUE
10270argf_initialize_copy(VALUE argf, VALUE orig)
10271{
10272 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10273 ARGF = argf_of(orig);
10274 rb_gc_writebarrier_remember(argf);
10275 ARGF_SET(argv, rb_obj_dup(ARGF.argv));
10276 return argf;
10277}
10278
10279/*
10280 * call-seq:
10281 * ARGF.lineno = integer -> integer
10282 *
10283 * Sets the line number of ARGF as a whole to the given Integer.
10284 *
10285 * ARGF sets the line number automatically as you read data, so normally
10286 * you will not need to set it explicitly. To access the current line number
10287 * use ARGF.lineno.
10288 *
10289 * For example:
10290 *
10291 * ARGF.lineno #=> 0
10292 * ARGF.readline #=> "This is line 1\n"
10293 * ARGF.lineno #=> 1
10294 * ARGF.lineno = 0 #=> 0
10295 * ARGF.lineno #=> 0
10296 */
10297static VALUE
10298argf_set_lineno(VALUE argf, VALUE val)
10299{
10300 ARGF.lineno = NUM2INT(val);
10301 ARGF.last_lineno = ARGF.lineno;
10302 return val;
10303}
10304
10305/*
10306 * call-seq:
10307 * ARGF.lineno -> integer
10308 *
10309 * Returns the current line number of ARGF as a whole. This value
10310 * can be set manually with ARGF.lineno=.
10311 *
10312 * For example:
10313 *
10314 * ARGF.lineno #=> 0
10315 * ARGF.readline #=> "This is line 1\n"
10316 * ARGF.lineno #=> 1
10317 */
10318static VALUE
10319argf_lineno(VALUE argf)
10320{
10321 return INT2FIX(ARGF.lineno);
10322}
10323
10324static VALUE
10325argf_forward(int argc, VALUE *argv, VALUE argf)
10326{
10327 return forward_current(rb_frame_this_func(), argc, argv);
10328}
10329
10330#define next_argv() argf_next_argv(argf)
10331#define ARGF_GENERIC_INPUT_P() \
10332 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10333#define ARGF_FORWARD(argc, argv) do {\
10334 if (ARGF_GENERIC_INPUT_P())\
10335 return argf_forward((argc), (argv), argf);\
10336} while (0)
10337#define NEXT_ARGF_FORWARD(argc, argv) do {\
10338 if (!next_argv()) return Qnil;\
10339 ARGF_FORWARD((argc), (argv));\
10340} while (0)
10341
10342static void
10343argf_close(VALUE argf)
10344{
10345 VALUE file = ARGF.current_file;
10346 if (file == rb_stdin) return;
10347 if (RB_TYPE_P(file, T_FILE)) {
10348 rb_io_set_write_io(file, Qnil);
10349 }
10350 io_close(file);
10351 ARGF.init_p = -1;
10352}
10353
10354static int
10355argf_next_argv(VALUE argf)
10356{
10357 char *fn;
10358 rb_io_t *fptr;
10359 int stdout_binmode = 0;
10360 enum rb_io_mode fmode;
10361
10362 VALUE r_stdout = rb_ractor_stdout();
10363
10364 if (RB_TYPE_P(r_stdout, T_FILE)) {
10365 GetOpenFile(r_stdout, fptr);
10366 if (fptr->mode & FMODE_BINMODE)
10367 stdout_binmode = 1;
10368 }
10369
10370 if (ARGF.init_p == 0) {
10371 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10372 ARGF.next_p = 1;
10373 }
10374 else {
10375 ARGF.next_p = -1;
10376 }
10377 ARGF.init_p = 1;
10378 }
10379 else {
10380 if (NIL_P(ARGF.argv)) {
10381 ARGF.next_p = -1;
10382 }
10383 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10384 ARGF.next_p = 1;
10385 }
10386 }
10387
10388 if (ARGF.next_p == 1) {
10389 if (ARGF.init_p == 1) argf_close(argf);
10390 retry:
10391 if (RARRAY_LEN(ARGF.argv) > 0) {
10392 VALUE filename = rb_ary_shift(ARGF.argv);
10393 FilePathValue(filename);
10394 ARGF_SET(filename, filename);
10395 filename = rb_str_encode_ospath(filename);
10396 fn = StringValueCStr(filename);
10397 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10398 ARGF_SET(current_file, rb_stdin);
10399 if (ARGF.inplace) {
10400 rb_warn("Can't do inplace edit for stdio; skipping");
10401 goto retry;
10402 }
10403 }
10404 else {
10405 VALUE write_io = Qnil;
10406 int fr = rb_sysopen(filename, O_RDONLY, 0);
10407
10408 if (ARGF.inplace) {
10409 struct stat st;
10410#ifndef NO_SAFE_RENAME
10411 struct stat st2;
10412#endif
10413 VALUE str;
10414 int fw;
10415
10416 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10417 rb_io_close(r_stdout);
10418 }
10419 fstat(fr, &st);
10420 str = filename;
10421 if (!NIL_P(ARGF.inplace)) {
10422 VALUE suffix = ARGF.inplace;
10423 str = rb_str_dup(str);
10424 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10425 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10426 rb_enc_get(suffix), 0, Qnil))) {
10427 rb_str_append(str, suffix);
10428 }
10429#ifdef NO_SAFE_RENAME
10430 (void)close(fr);
10431 (void)unlink(RSTRING_PTR(str));
10432 if (rename(fn, RSTRING_PTR(str)) < 0) {
10433 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10434 filename, str, strerror(errno));
10435 goto retry;
10436 }
10437 fr = rb_sysopen(str, O_RDONLY, 0);
10438#else
10439 if (rename(fn, RSTRING_PTR(str)) < 0) {
10440 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10441 filename, str, strerror(errno));
10442 close(fr);
10443 goto retry;
10444 }
10445#endif
10446 }
10447 else {
10448#ifdef NO_SAFE_RENAME
10449 rb_fatal("Can't do inplace edit without backup");
10450#else
10451 if (unlink(fn) < 0) {
10452 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10453 filename, strerror(errno));
10454 close(fr);
10455 goto retry;
10456 }
10457#endif
10458 }
10459 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10460#ifndef NO_SAFE_RENAME
10461 fstat(fw, &st2);
10462#ifdef HAVE_FCHMOD
10463 fchmod(fw, st.st_mode);
10464#else
10465 chmod(fn, st.st_mode);
10466#endif
10467 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10468 int err;
10469#ifdef HAVE_FCHOWN
10470 err = fchown(fw, st.st_uid, st.st_gid);
10471#else
10472 err = chown(fn, st.st_uid, st.st_gid);
10473#endif
10474 if (err && getuid() == 0 && st2.st_uid == 0) {
10475 const char *wkfn = RSTRING_PTR(filename);
10476 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10477 filename, str, strerror(errno));
10478 (void)close(fr);
10479 (void)close(fw);
10480 (void)unlink(wkfn);
10481 goto retry;
10482 }
10483 }
10484#endif
10485 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10486 rb_ractor_stdout_set(write_io);
10487 if (stdout_binmode) rb_io_binmode(rb_stdout);
10488 }
10489 fmode = FMODE_READABLE;
10490 if (!ARGF.binmode) {
10491 fmode |= DEFAULT_TEXTMODE;
10492 }
10493 ARGF_SET(current_file, prep_io(fr, fmode, rb_cFile, fn));
10494 if (!NIL_P(write_io)) {
10495 rb_io_set_write_io(ARGF.current_file, write_io);
10496 }
10497 RB_GC_GUARD(filename);
10498 }
10499 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10500 GetOpenFile(ARGF.current_file, fptr);
10501 if (ARGF.encs.enc) {
10502 fptr->encs = ARGF.encs;
10503 clear_codeconv(fptr);
10504 }
10505 else {
10506 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10507 if (!ARGF.binmode) {
10509#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10510 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10511#endif
10512 }
10513 }
10514 ARGF.next_p = 0;
10515 }
10516 else {
10517 ARGF.next_p = 1;
10518 return FALSE;
10519 }
10520 }
10521 else if (ARGF.next_p == -1) {
10522 ARGF_SET(current_file, rb_stdin);
10523 ARGF_SET(filename, rb_str_new2("-"));
10524 if (ARGF.inplace) {
10525 rb_warn("Can't do inplace edit for stdio");
10526 rb_ractor_stdout_set(orig_stdout);
10527 }
10528 }
10529 if (ARGF.init_p == -1) ARGF.init_p = 1;
10530 return TRUE;
10531}
10532
10533static VALUE
10534argf_getline(int argc, VALUE *argv, VALUE argf)
10535{
10536 VALUE line;
10537 long lineno = ARGF.lineno;
10538
10539 retry:
10540 if (!next_argv()) return Qnil;
10541 if (ARGF_GENERIC_INPUT_P()) {
10542 line = forward_current(idGets, argc, argv);
10543 }
10544 else {
10545 if (argc == 0 && rb_rs == rb_default_rs) {
10546 line = rb_io_gets(ARGF.current_file);
10547 }
10548 else {
10549 line = rb_io_getline(argc, argv, ARGF.current_file);
10550 }
10551 if (NIL_P(line) && ARGF.next_p != -1) {
10552 argf_close(argf);
10553 ARGF.next_p = 1;
10554 goto retry;
10555 }
10556 }
10557 if (!NIL_P(line)) {
10558 ARGF.lineno = ++lineno;
10559 ARGF.last_lineno = ARGF.lineno;
10560 }
10561 return line;
10562}
10563
10564static VALUE
10565argf_lineno_getter(ID id, VALUE *var)
10566{
10567 VALUE argf = *var;
10568 return INT2FIX(ARGF.last_lineno);
10569}
10570
10571static void
10572argf_lineno_setter(VALUE val, ID id, VALUE *var)
10573{
10574 VALUE argf = *var;
10575 int n = NUM2INT(val);
10576 ARGF.last_lineno = ARGF.lineno = n;
10577}
10578
10579void
10580rb_reset_argf_lineno(long n)
10581{
10582 ARGF.last_lineno = ARGF.lineno = n;
10583}
10584
10585static VALUE argf_gets(int, VALUE *, VALUE);
10586
10587/*
10588 * call-seq:
10589 * gets(sep=$/ [, getline_args]) -> string or nil
10590 * gets(limit [, getline_args]) -> string or nil
10591 * gets(sep, limit [, getline_args]) -> string or nil
10592 *
10593 * Returns (and assigns to <code>$_</code>) the next line from the list
10594 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10595 * no files are present on the command line. Returns +nil+ at end of
10596 * file. The optional argument specifies the record separator. The
10597 * separator is included with the contents of each record. A separator
10598 * of +nil+ reads the entire contents, and a zero-length separator
10599 * reads the input one paragraph at a time, where paragraphs are
10600 * divided by two consecutive newlines. If the first argument is an
10601 * integer, or optional second argument is given, the returning string
10602 * would not be longer than the given value in bytes. If multiple
10603 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10604 * the contents one file at a time.
10605 *
10606 * ARGV << "testfile"
10607 * print while gets
10608 *
10609 * <em>produces:</em>
10610 *
10611 * This is line one
10612 * This is line two
10613 * This is line three
10614 * And so on...
10615 *
10616 * The style of programming using <code>$_</code> as an implicit
10617 * parameter is gradually losing favor in the Ruby community.
10618 */
10619
10620static VALUE
10621rb_f_gets(int argc, VALUE *argv, VALUE recv)
10622{
10623 if (recv == argf) {
10624 return argf_gets(argc, argv, argf);
10625 }
10626 return forward(argf, idGets, argc, argv);
10627}
10628
10629/*
10630 * call-seq:
10631 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10632 * ARGF.gets(limit [, getline_args]) -> string or nil
10633 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10634 *
10635 * Returns the next line from the current file in ARGF.
10636 *
10637 * By default lines are assumed to be separated by <code>$/</code>;
10638 * to use a different character as a separator, supply it as a String
10639 * for the _sep_ argument.
10640 *
10641 * The optional _limit_ argument specifies how many characters of each line
10642 * to return. By default all characters are returned.
10643 *
10644 * See IO.readlines for details about getline_args.
10645 *
10646 */
10647static VALUE
10648argf_gets(int argc, VALUE *argv, VALUE argf)
10649{
10650 VALUE line;
10651
10652 line = argf_getline(argc, argv, argf);
10653 rb_lastline_set(line);
10654
10655 return line;
10656}
10657
10658VALUE
10660{
10661 VALUE line;
10662
10663 if (rb_rs != rb_default_rs) {
10664 return rb_f_gets(0, 0, argf);
10665 }
10666
10667 retry:
10668 if (!next_argv()) return Qnil;
10669 line = rb_io_gets(ARGF.current_file);
10670 if (NIL_P(line) && ARGF.next_p != -1) {
10671 rb_io_close(ARGF.current_file);
10672 ARGF.next_p = 1;
10673 goto retry;
10674 }
10675 rb_lastline_set(line);
10676 if (!NIL_P(line)) {
10677 ARGF.lineno++;
10678 ARGF.last_lineno = ARGF.lineno;
10679 }
10680
10681 return line;
10682}
10683
10684static VALUE argf_readline(int, VALUE *, VALUE);
10685
10686/*
10687 * call-seq:
10688 * readline(sep = $/, chomp: false) -> string
10689 * readline(limit, chomp: false) -> string
10690 * readline(sep, limit, chomp: false) -> string
10691 *
10692 * Equivalent to method Kernel#gets, except that it raises an exception
10693 * if called at end-of-stream:
10694 *
10695 * $ cat t.txt | ruby -e "p readlines; readline"
10696 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10697 * in `readline': end of file reached (EOFError)
10698 *
10699 * Optional keyword argument +chomp+ specifies whether line separators
10700 * are to be omitted.
10701 */
10702
10703static VALUE
10704rb_f_readline(int argc, VALUE *argv, VALUE recv)
10705{
10706 if (recv == argf) {
10707 return argf_readline(argc, argv, argf);
10708 }
10709 return forward(argf, rb_intern("readline"), argc, argv);
10710}
10711
10712
10713/*
10714 * call-seq:
10715 * ARGF.readline(sep=$/) -> string
10716 * ARGF.readline(limit) -> string
10717 * ARGF.readline(sep, limit) -> string
10718 *
10719 * Returns the next line from the current file in ARGF.
10720 *
10721 * By default lines are assumed to be separated by <code>$/</code>;
10722 * to use a different character as a separator, supply it as a String
10723 * for the _sep_ argument.
10724 *
10725 * The optional _limit_ argument specifies how many characters of each line
10726 * to return. By default all characters are returned.
10727 *
10728 * An EOFError is raised at the end of the file.
10729 */
10730static VALUE
10731argf_readline(int argc, VALUE *argv, VALUE argf)
10732{
10733 VALUE line;
10734
10735 if (!next_argv()) rb_eof_error();
10736 ARGF_FORWARD(argc, argv);
10737 line = argf_gets(argc, argv, argf);
10738 if (NIL_P(line)) {
10739 rb_eof_error();
10740 }
10741
10742 return line;
10743}
10744
10745static VALUE argf_readlines(int, VALUE *, VALUE);
10746
10747/*
10748 * call-seq:
10749 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10750 * readlines(limit, chomp: false, **enc_opts) -> array
10751 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10752 *
10753 * Returns an array containing the lines returned by calling
10754 * Kernel#gets until the end-of-stream is reached;
10755 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10756 *
10757 * With only string argument +sep+ given,
10758 * returns the remaining lines as determined by line separator +sep+,
10759 * or +nil+ if none;
10760 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10761 *
10762 * # Default separator.
10763 * $ cat t.txt | ruby -e "p readlines"
10764 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10765 *
10766 * # Specified separator.
10767 * $ cat t.txt | ruby -e "p readlines 'li'"
10768 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10769 *
10770 * # Get-all separator.
10771 * $ cat t.txt | ruby -e "p readlines nil"
10772 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10773 *
10774 * # Get-paragraph separator.
10775 * $ cat t.txt | ruby -e "p readlines ''"
10776 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10777 *
10778 * With only integer argument +limit+ given,
10779 * limits the number of bytes in the line;
10780 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10781 *
10782 * $cat t.txt | ruby -e "p readlines 10"
10783 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10784 *
10785 * $cat t.txt | ruby -e "p readlines 11"
10786 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10787 *
10788 * $cat t.txt | ruby -e "p readlines 12"
10789 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10790 *
10791 * With arguments +sep+ and +limit+ given,
10792 * combines the two behaviors
10793 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10794 *
10795 * Optional keyword argument +chomp+ specifies whether line separators
10796 * are to be omitted:
10797 *
10798 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10799 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10800 *
10801 * Optional keyword arguments +enc_opts+ specify encoding options;
10802 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10803 *
10804 */
10805
10806static VALUE
10807rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10808{
10809 if (recv == argf) {
10810 return argf_readlines(argc, argv, argf);
10811 }
10812 return forward(argf, rb_intern("readlines"), argc, argv);
10813}
10814
10815/*
10816 * call-seq:
10817 * ARGF.readlines(sep = $/, chomp: false) -> array
10818 * ARGF.readlines(limit, chomp: false) -> array
10819 * ARGF.readlines(sep, limit, chomp: false) -> array
10820 *
10821 * ARGF.to_a(sep = $/, chomp: false) -> array
10822 * ARGF.to_a(limit, chomp: false) -> array
10823 * ARGF.to_a(sep, limit, chomp: false) -> array
10824 *
10825 * Reads each file in ARGF in its entirety, returning an Array containing
10826 * lines from the files. Lines are assumed to be separated by _sep_.
10827 *
10828 * lines = ARGF.readlines
10829 * lines[0] #=> "This is line one\n"
10830 *
10831 * See +IO.readlines+ for a full description of all options.
10832 */
10833static VALUE
10834argf_readlines(int argc, VALUE *argv, VALUE argf)
10835{
10836 long lineno = ARGF.lineno;
10837 VALUE lines, ary;
10838
10839 ary = rb_ary_new();
10840 while (next_argv()) {
10841 if (ARGF_GENERIC_INPUT_P()) {
10842 lines = forward_current(rb_intern("readlines"), argc, argv);
10843 }
10844 else {
10845 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10846 argf_close(argf);
10847 }
10848 ARGF.next_p = 1;
10849 rb_ary_concat(ary, lines);
10850 ARGF.lineno = lineno + RARRAY_LEN(ary);
10851 ARGF.last_lineno = ARGF.lineno;
10852 }
10853 ARGF.init_p = 0;
10854 return ary;
10855}
10856
10857/*
10858 * call-seq:
10859 * `command` -> string
10860 *
10861 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10862 * sets global variable <tt>$?</tt> to the process status.
10863 *
10864 * This method has potential security vulnerabilities if called with untrusted input;
10865 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
10866 *
10867 * Examples:
10868 *
10869 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10870 * $ `echo oops && exit 99` # => "oops\n"
10871 * $ $? # => #<Process::Status: pid 17088 exit 99>
10872 * $ $?.exitstatus # => 99
10873 *
10874 * The built-in syntax <tt>%x{...}</tt> uses this method.
10875 *
10876 */
10877
10878static VALUE
10879rb_f_backquote(VALUE obj, VALUE str)
10880{
10881 VALUE port;
10882 VALUE result;
10883 rb_io_t *fptr;
10884
10885 StringValue(str);
10886 rb_last_status_clear();
10887 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10888 if (NIL_P(port)) return rb_str_new(0,0);
10889
10890 GetOpenFile(port, fptr);
10891 result = read_all(fptr, remain_size(fptr), Qnil);
10892 rb_io_close(port);
10893 rb_io_fptr_cleanup_all(fptr);
10894 RB_GC_GUARD(port);
10895
10896 return result;
10897}
10898
10899#ifdef HAVE_SYS_SELECT_H
10900#include <sys/select.h>
10901#endif
10902
10903static VALUE
10904select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10905{
10906 VALUE res, list;
10907 rb_fdset_t *rp, *wp, *ep;
10908 rb_io_t *fptr;
10909 rb_len_t i;
10910 int max = 0, n;
10911 int pending = 0;
10912 struct timeval timerec;
10913
10914 if (!NIL_P(read)) {
10915 Check_Type(read, T_ARRAY);
10916 for (i=0; i<RARRAY_LEN(read); i++) {
10917 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10918 rb_fd_set(fptr->fd, &fds[0]);
10919 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10920 pending++;
10921 rb_fd_set(fptr->fd, &fds[3]);
10922 }
10923 if (max < fptr->fd) max = fptr->fd;
10924 }
10925 if (pending) { /* no blocking if there's buffered data */
10926 timerec.tv_sec = timerec.tv_usec = 0;
10927 tp = &timerec;
10928 }
10929 rp = &fds[0];
10930 }
10931 else
10932 rp = 0;
10933
10934 if (!NIL_P(write)) {
10935 Check_Type(write, T_ARRAY);
10936 for (i=0; i<RARRAY_LEN(write); i++) {
10937 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10938 GetOpenFile(write_io, fptr);
10939 rb_fd_set(fptr->fd, &fds[1]);
10940 if (max < fptr->fd) max = fptr->fd;
10941 }
10942 wp = &fds[1];
10943 }
10944 else
10945 wp = 0;
10946
10947 if (!NIL_P(except)) {
10948 Check_Type(except, T_ARRAY);
10949 for (i=0; i<RARRAY_LEN(except); i++) {
10950 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10951 VALUE write_io = GetWriteIO(io);
10952 GetOpenFile(io, fptr);
10953 rb_fd_set(fptr->fd, &fds[2]);
10954 if (max < fptr->fd) max = fptr->fd;
10955 if (io != write_io) {
10956 GetOpenFile(write_io, fptr);
10957 rb_fd_set(fptr->fd, &fds[2]);
10958 if (max < fptr->fd) max = fptr->fd;
10959 }
10960 }
10961 ep = &fds[2];
10962 }
10963 else {
10964 ep = 0;
10965 }
10966
10967 max++;
10968
10969 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10970 if (n < 0) {
10971 rb_sys_fail(0);
10972 }
10973 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10974
10975 res = rb_ary_new2(3);
10976 rb_ary_push(res, rp ? rb_ary_new_capa(RARRAY_LEN(read)) : rb_ary_new());
10977 rb_ary_push(res, wp ? rb_ary_new_capa(RARRAY_LEN(write)) : rb_ary_new());
10978 rb_ary_push(res, ep ? rb_ary_new_capa(RARRAY_LEN(except)) : rb_ary_new());
10979
10980 if (rp) {
10981 list = RARRAY_AREF(res, 0);
10982 for (i=0; i< RARRAY_LEN(read); i++) {
10983 VALUE obj = rb_ary_entry(read, i);
10984 VALUE io = rb_io_get_io(obj);
10985 GetOpenFile(io, fptr);
10986 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10987 rb_fd_isset(fptr->fd, &fds[3])) {
10988 rb_ary_push(list, obj);
10989 }
10990 }
10991 }
10992
10993 if (wp) {
10994 list = RARRAY_AREF(res, 1);
10995 for (i=0; i< RARRAY_LEN(write); i++) {
10996 VALUE obj = rb_ary_entry(write, i);
10997 VALUE io = rb_io_get_io(obj);
10998 VALUE write_io = GetWriteIO(io);
10999 GetOpenFile(write_io, fptr);
11000 if (rb_fd_isset(fptr->fd, &fds[1])) {
11001 rb_ary_push(list, obj);
11002 }
11003 }
11004 }
11005
11006 if (ep) {
11007 list = RARRAY_AREF(res, 2);
11008 for (i=0; i< RARRAY_LEN(except); i++) {
11009 VALUE obj = rb_ary_entry(except, i);
11010 VALUE io = rb_io_get_io(obj);
11011 VALUE write_io = GetWriteIO(io);
11012 GetOpenFile(io, fptr);
11013 if (rb_fd_isset(fptr->fd, &fds[2])) {
11014 rb_ary_push(list, obj);
11015 }
11016 else if (io != write_io) {
11017 GetOpenFile(write_io, fptr);
11018 if (rb_fd_isset(fptr->fd, &fds[2])) {
11019 rb_ary_push(list, obj);
11020 }
11021 }
11022 }
11023 }
11024
11025 return res; /* returns an empty array on interrupt */
11026}
11027
11029 VALUE read, write, except;
11030 struct timeval *timeout;
11031 rb_fdset_t fdsets[4];
11032};
11033
11034static VALUE
11035select_call(VALUE arg)
11036{
11037 struct select_args *p = (struct select_args *)arg;
11038
11039 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
11040}
11041
11042static VALUE
11043select_end(VALUE arg)
11044{
11045 struct select_args *p = (struct select_args *)arg;
11046 int i;
11047
11048 for (i = 0; i < numberof(p->fdsets); ++i)
11049 rb_fd_term(&p->fdsets[i]);
11050 return Qnil;
11051}
11052
11053static VALUE sym_normal, sym_sequential, sym_random,
11054 sym_willneed, sym_dontneed, sym_noreuse;
11055
11056#ifdef HAVE_POSIX_FADVISE
11057struct io_advise_struct {
11058 int fd;
11059 int advice;
11060 rb_off_t offset;
11061 rb_off_t len;
11062};
11063
11064static VALUE
11065io_advise_internal(void *arg)
11066{
11067 struct io_advise_struct *ptr = arg;
11068 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
11069}
11070
11071static VALUE
11072io_advise_sym_to_const(VALUE sym)
11073{
11074#ifdef POSIX_FADV_NORMAL
11075 if (sym == sym_normal)
11076 return INT2NUM(POSIX_FADV_NORMAL);
11077#endif
11078
11079#ifdef POSIX_FADV_RANDOM
11080 if (sym == sym_random)
11081 return INT2NUM(POSIX_FADV_RANDOM);
11082#endif
11083
11084#ifdef POSIX_FADV_SEQUENTIAL
11085 if (sym == sym_sequential)
11086 return INT2NUM(POSIX_FADV_SEQUENTIAL);
11087#endif
11088
11089#ifdef POSIX_FADV_WILLNEED
11090 if (sym == sym_willneed)
11091 return INT2NUM(POSIX_FADV_WILLNEED);
11092#endif
11093
11094#ifdef POSIX_FADV_DONTNEED
11095 if (sym == sym_dontneed)
11096 return INT2NUM(POSIX_FADV_DONTNEED);
11097#endif
11098
11099#ifdef POSIX_FADV_NOREUSE
11100 if (sym == sym_noreuse)
11101 return INT2NUM(POSIX_FADV_NOREUSE);
11102#endif
11103
11104 return Qnil;
11105}
11106
11107static VALUE
11108do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
11109{
11110 int rv;
11111 struct io_advise_struct ias;
11112 VALUE num_adv;
11113
11114 num_adv = io_advise_sym_to_const(advice);
11115
11116 /*
11117 * The platform doesn't support this hint. We don't raise exception, instead
11118 * silently ignore it. Because IO::advise is only hint.
11119 */
11120 if (NIL_P(num_adv))
11121 return Qnil;
11122
11123 ias.fd = fptr->fd;
11124 ias.advice = NUM2INT(num_adv);
11125 ias.offset = offset;
11126 ias.len = len;
11127
11128 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
11129 if (rv && rv != ENOSYS) {
11130 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
11131 it returns the error code. */
11132 VALUE message = rb_sprintf("%"PRIsVALUE" "
11133 "(%"PRI_OFFT_PREFIX"d, "
11134 "%"PRI_OFFT_PREFIX"d, "
11135 "%"PRIsVALUE")",
11136 fptr->pathv, offset, len, advice);
11137 rb_syserr_fail_str(rv, message);
11138 }
11139
11140 return Qnil;
11141}
11142
11143#endif /* HAVE_POSIX_FADVISE */
11144
11145static void
11146advice_arg_check(VALUE advice)
11147{
11148 if (!SYMBOL_P(advice))
11149 rb_raise(rb_eTypeError, "advice must be a Symbol");
11150
11151 if (advice != sym_normal &&
11152 advice != sym_sequential &&
11153 advice != sym_random &&
11154 advice != sym_willneed &&
11155 advice != sym_dontneed &&
11156 advice != sym_noreuse) {
11157 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
11158 }
11159}
11160
11161/*
11162 * call-seq:
11163 * advise(advice, offset = 0, len = 0) -> nil
11164 *
11165 * Invokes Posix system call
11166 * {posix_fadvise(2)}[https://man7.org/linux/man-pages/man2/posix_fadvise.2.html],
11167 * which announces an intention to access data from the current file
11168 * in a particular manner.
11169 *
11170 * The arguments and results are platform-dependent.
11171 *
11172 * The relevant data is specified by:
11173 *
11174 * - +offset+: The offset of the first byte of data.
11175 * - +len+: The number of bytes to be accessed;
11176 * if +len+ is zero, or is larger than the number of bytes remaining,
11177 * all remaining bytes will be accessed.
11178 *
11179 * Argument +advice+ is one of the following symbols:
11180 *
11181 * - +:normal+: The application has no advice to give
11182 * about its access pattern for the specified data.
11183 * If no advice is given for an open file, this is the default assumption.
11184 * - +:sequential+: The application expects to access the specified data sequentially
11185 * (with lower offsets read before higher ones).
11186 * - +:random+: The specified data will be accessed in random order.
11187 * - +:noreuse+: The specified data will be accessed only once.
11188 * - +:willneed+: The specified data will be accessed in the near future.
11189 * - +:dontneed+: The specified data will not be accessed in the near future.
11190 *
11191 * Not implemented on all platforms.
11192 *
11193 */
11194static VALUE
11195rb_io_advise(int argc, VALUE *argv, VALUE io)
11196{
11197 VALUE advice, offset, len;
11198 rb_off_t off, l;
11199 rb_io_t *fptr;
11200
11201 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
11202 advice_arg_check(advice);
11203
11204 io = GetWriteIO(io);
11205 GetOpenFile(io, fptr);
11206
11207 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
11208 l = NIL_P(len) ? 0 : NUM2OFFT(len);
11209
11210#ifdef HAVE_POSIX_FADVISE
11211 return do_io_advise(fptr, advice, off, l);
11212#else
11213 ((void)off, (void)l); /* Ignore all hint */
11214 return Qnil;
11215#endif
11216}
11217
11218static int
11219is_pos_inf(VALUE x)
11220{
11221 double f;
11222 if (!RB_FLOAT_TYPE_P(x))
11223 return 0;
11224 f = RFLOAT_VALUE(x);
11225 return isinf(f) && 0 < f;
11226}
11227
11228/*
11229 * call-seq:
11230 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11231 *
11232 * Invokes system call {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html],
11233 * which monitors multiple file descriptors,
11234 * waiting until one or more of the file descriptors
11235 * becomes ready for some class of I/O operation.
11236 *
11237 * Not implemented on all platforms.
11238 *
11239 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11240 * is an array of IO objects.
11241 *
11242 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11243 * interval in seconds.
11244 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11245 * +nil+ and +Float::INFINITY+ means no timeout.
11246 *
11247 * The method monitors the \IO objects given in all three arrays,
11248 * waiting for some to be ready;
11249 * returns a 3-element array whose elements are:
11250 *
11251 * - An array of the objects in +read_ios+ that are ready for reading.
11252 * - An array of the objects in +write_ios+ that are ready for writing.
11253 * - An array of the objects in +error_ios+ have pending exceptions.
11254 *
11255 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11256 *
11257 * \IO.select peeks the buffer of \IO objects for testing readability.
11258 * If the \IO buffer is not empty, \IO.select immediately notifies
11259 * readability. This "peek" only happens for \IO objects. It does not
11260 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11261 *
11262 * The best way to use \IO.select is invoking it after non-blocking
11263 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11264 * raise an exception which is extended by IO::WaitReadable or
11265 * IO::WaitWritable. The modules notify how the caller should wait
11266 * with \IO.select. If IO::WaitReadable is raised, the caller should
11267 * wait for reading. If IO::WaitWritable is raised, the caller should
11268 * wait for writing.
11269 *
11270 * So, blocking read (#readpartial) can be emulated using
11271 * #read_nonblock and \IO.select as follows:
11272 *
11273 * begin
11274 * result = io_like.read_nonblock(maxlen)
11275 * rescue IO::WaitReadable
11276 * IO.select([io_like])
11277 * retry
11278 * rescue IO::WaitWritable
11279 * IO.select(nil, [io_like])
11280 * retry
11281 * end
11282 *
11283 * Especially, the combination of non-blocking methods and \IO.select is
11284 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11285 * has #to_io method to return underlying IO object. IO.select calls
11286 * #to_io to obtain the file descriptor to wait.
11287 *
11288 * This means that readability notified by \IO.select doesn't mean
11289 * readability from OpenSSL::SSL::SSLSocket object.
11290 *
11291 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11292 * some data. \IO.select doesn't see the buffer. So \IO.select can
11293 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11294 *
11295 * However, several more complicated situations exist.
11296 *
11297 * SSL is a protocol which is sequence of records.
11298 * The record consists of multiple bytes.
11299 * So, the remote side of SSL sends a partial record, IO.select
11300 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11301 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11302 *
11303 * Also, the remote side can request SSL renegotiation which forces
11304 * the local SSL engine to write some data.
11305 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11306 * system call and it can block.
11307 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11308 * IO::WaitWritable instead of blocking.
11309 * So, the caller should wait for ready for writability as above
11310 * example.
11311 *
11312 * The combination of non-blocking methods and \IO.select is also useful
11313 * for streams such as tty, pipe socket socket when multiple processes
11314 * read from a stream.
11315 *
11316 * Finally, Linux kernel developers don't guarantee that
11317 * readability of select(2) means readability of following read(2) even
11318 * for a single process;
11319 * see {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html]
11320 *
11321 * Invoking \IO.select before IO#readpartial works well as usual.
11322 * However it is not the best way to use \IO.select.
11323 *
11324 * The writability notified by select(2) doesn't show
11325 * how many bytes are writable.
11326 * IO#write method blocks until given whole string is written.
11327 * So, <tt>IO#write(two or more bytes)</tt> can block after
11328 * writability is notified by \IO.select. IO#write_nonblock is required
11329 * to avoid the blocking.
11330 *
11331 * Blocking write (#write) can be emulated using #write_nonblock and
11332 * IO.select as follows: IO::WaitReadable should also be rescued for
11333 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11334 *
11335 * while 0 < string.bytesize
11336 * begin
11337 * written = io_like.write_nonblock(string)
11338 * rescue IO::WaitReadable
11339 * IO.select([io_like])
11340 * retry
11341 * rescue IO::WaitWritable
11342 * IO.select(nil, [io_like])
11343 * retry
11344 * end
11345 * string = string.byteslice(written..-1)
11346 * end
11347 *
11348 * Example:
11349 *
11350 * rp, wp = IO.pipe
11351 * mesg = "ping "
11352 * 100.times {
11353 * # IO.select follows IO#read. Not the best way to use IO.select.
11354 * rs, ws, = IO.select([rp], [wp])
11355 * if r = rs[0]
11356 * ret = r.read(5)
11357 * print ret
11358 * case ret
11359 * when /ping/
11360 * mesg = "pong\n"
11361 * when /pong/
11362 * mesg = "ping "
11363 * end
11364 * end
11365 * if w = ws[0]
11366 * w.write(mesg)
11367 * end
11368 * }
11369 *
11370 * Output:
11371 *
11372 * ping pong
11373 * ping pong
11374 * ping pong
11375 * (snipped)
11376 * ping
11377 *
11378 */
11379
11380static VALUE
11381rb_f_select(int argc, VALUE *argv, VALUE obj)
11382{
11383 VALUE scheduler = rb_fiber_scheduler_current();
11384 if (scheduler != Qnil) {
11385 // It's optionally supported.
11386 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11387 if (!UNDEF_P(result)) return result;
11388 }
11389
11390 VALUE timeout;
11391 struct select_args args;
11392 struct timeval timerec;
11393 int i;
11394
11395 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11396 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11397 args.timeout = 0;
11398 }
11399 else {
11400 timerec = rb_time_interval(timeout);
11401 args.timeout = &timerec;
11402 }
11403
11404 for (i = 0; i < numberof(args.fdsets); ++i)
11405 rb_fd_init(&args.fdsets[i]);
11406
11407 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11408}
11409
11410#ifdef IOCTL_REQ_TYPE
11411 typedef IOCTL_REQ_TYPE ioctl_req_t;
11412#else
11413 typedef int ioctl_req_t;
11414# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11415#endif
11416
11417#ifdef HAVE_IOCTL
11418struct ioctl_arg {
11419 int fd;
11420 ioctl_req_t cmd;
11421 long narg;
11422};
11423
11424static VALUE
11425nogvl_ioctl(void *ptr)
11426{
11427 struct ioctl_arg *arg = ptr;
11428
11429 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11430}
11431
11432static int
11433do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11434{
11435 int retval;
11436 struct ioctl_arg arg;
11437
11438 arg.fd = io->fd;
11439 arg.cmd = cmd;
11440 arg.narg = narg;
11441
11442 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11443
11444 return retval;
11445}
11446#endif
11447
11448#define DEFAULT_IOCTL_NARG_LEN (256)
11449
11450#if defined(__linux__) && defined(_IOC_SIZE)
11451static long
11452linux_iocparm_len(ioctl_req_t cmd)
11453{
11454 long len;
11455
11456 if ((cmd & 0xFFFF0000) == 0) {
11457 /* legacy and unstructured ioctl number. */
11458 return DEFAULT_IOCTL_NARG_LEN;
11459 }
11460
11461 len = _IOC_SIZE(cmd);
11462
11463 /* paranoia check for silly drivers which don't keep ioctl convention */
11464 if (len < DEFAULT_IOCTL_NARG_LEN)
11465 len = DEFAULT_IOCTL_NARG_LEN;
11466
11467 return len;
11468}
11469#endif
11470
11471#ifdef HAVE_IOCTL
11472static long
11473ioctl_narg_len(ioctl_req_t cmd)
11474{
11475 long len;
11476
11477#ifdef IOCPARM_MASK
11478#ifndef IOCPARM_LEN
11479#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11480#endif
11481#endif
11482#ifdef IOCPARM_LEN
11483 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11484#elif defined(__linux__) && defined(_IOC_SIZE)
11485 len = linux_iocparm_len(cmd);
11486#else
11487 /* otherwise guess at what's safe */
11488 len = DEFAULT_IOCTL_NARG_LEN;
11489#endif
11490
11491 return len;
11492}
11493#endif
11494
11495#ifdef HAVE_FCNTL
11496#ifdef __linux__
11497typedef long fcntl_arg_t;
11498#else
11499/* posix */
11500typedef int fcntl_arg_t;
11501#endif
11502
11503static long
11504fcntl_narg_len(ioctl_req_t cmd)
11505{
11506 long len;
11507
11508 switch (cmd) {
11509#ifdef F_DUPFD
11510 case F_DUPFD:
11511 len = sizeof(fcntl_arg_t);
11512 break;
11513#endif
11514#ifdef F_DUP2FD /* bsd specific */
11515 case F_DUP2FD:
11516 len = sizeof(int);
11517 break;
11518#endif
11519#ifdef F_DUPFD_CLOEXEC /* linux specific */
11520 case F_DUPFD_CLOEXEC:
11521 len = sizeof(fcntl_arg_t);
11522 break;
11523#endif
11524#ifdef F_GETFD
11525 case F_GETFD:
11526 len = 1;
11527 break;
11528#endif
11529#ifdef F_SETFD
11530 case F_SETFD:
11531 len = sizeof(fcntl_arg_t);
11532 break;
11533#endif
11534#ifdef F_GETFL
11535 case F_GETFL:
11536 len = 1;
11537 break;
11538#endif
11539#ifdef F_SETFL
11540 case F_SETFL:
11541 len = sizeof(fcntl_arg_t);
11542 break;
11543#endif
11544#ifdef F_GETOWN
11545 case F_GETOWN:
11546 len = 1;
11547 break;
11548#endif
11549#ifdef F_SETOWN
11550 case F_SETOWN:
11551 len = sizeof(fcntl_arg_t);
11552 break;
11553#endif
11554#ifdef F_GETOWN_EX /* linux specific */
11555 case F_GETOWN_EX:
11556 len = sizeof(struct f_owner_ex);
11557 break;
11558#endif
11559#ifdef F_SETOWN_EX /* linux specific */
11560 case F_SETOWN_EX:
11561 len = sizeof(struct f_owner_ex);
11562 break;
11563#endif
11564#ifdef F_GETLK
11565 case F_GETLK:
11566 len = sizeof(struct flock);
11567 break;
11568#endif
11569#ifdef F_SETLK
11570 case F_SETLK:
11571 len = sizeof(struct flock);
11572 break;
11573#endif
11574#ifdef F_SETLKW
11575 case F_SETLKW:
11576 len = sizeof(struct flock);
11577 break;
11578#endif
11579#ifdef F_READAHEAD /* bsd specific */
11580 case F_READAHEAD:
11581 len = sizeof(int);
11582 break;
11583#endif
11584#ifdef F_RDAHEAD /* Darwin specific */
11585 case F_RDAHEAD:
11586 len = sizeof(int);
11587 break;
11588#endif
11589#ifdef F_GETSIG /* linux specific */
11590 case F_GETSIG:
11591 len = 1;
11592 break;
11593#endif
11594#ifdef F_SETSIG /* linux specific */
11595 case F_SETSIG:
11596 len = sizeof(fcntl_arg_t);
11597 break;
11598#endif
11599#ifdef F_GETLEASE /* linux specific */
11600 case F_GETLEASE:
11601 len = 1;
11602 break;
11603#endif
11604#ifdef F_SETLEASE /* linux specific */
11605 case F_SETLEASE:
11606 len = sizeof(fcntl_arg_t);
11607 break;
11608#endif
11609#ifdef F_NOTIFY /* linux specific */
11610 case F_NOTIFY:
11611 len = sizeof(fcntl_arg_t);
11612 break;
11613#endif
11614
11615 default:
11616 len = 256;
11617 break;
11618 }
11619
11620 return len;
11621}
11622#else /* HAVE_FCNTL */
11623static long
11624fcntl_narg_len(ioctl_req_t cmd)
11625{
11626 return 0;
11627}
11628#endif /* HAVE_FCNTL */
11629
11630#define NARG_SENTINEL 17
11631
11632static long
11633setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11634{
11635 long narg = 0;
11636 VALUE arg = *argp;
11637
11638 if (!RTEST(arg)) {
11639 narg = 0;
11640 }
11641 else if (FIXNUM_P(arg)) {
11642 narg = FIX2LONG(arg);
11643 }
11644 else if (arg == Qtrue) {
11645 narg = 1;
11646 }
11647 else {
11648 VALUE tmp = rb_check_string_type(arg);
11649
11650 if (NIL_P(tmp)) {
11651 narg = NUM2LONG(arg);
11652 }
11653 else {
11654 char *ptr;
11655 long req_len;
11656 rb_len_t slen;
11657
11658 *argp = arg = tmp;
11659 req_len = narg_len(cmd);
11660 rb_str_modify(arg);
11661
11662 slen = RSTRING_LEN(arg);
11663 /* expand for data + sentinel. */
11664 if (slen < req_len+1) {
11665 rb_str_resize(arg, req_len+1);
11666 MEMZERO(RSTRING_PTR(arg)+slen, char, req_len-slen);
11667 slen = req_len+1;
11668 }
11669 /* a little sanity check here */
11670 ptr = RSTRING_PTR(arg);
11671 ptr[slen - 1] = NARG_SENTINEL;
11672 narg = (long)(SIGNED_VALUE)ptr;
11673 }
11674 }
11675
11676 return narg;
11677}
11678
11679static VALUE
11680finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11681{
11682 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11683 if (RB_TYPE_P(arg, T_STRING)) {
11684 char *ptr;
11685 rb_len_t slen;
11686 RSTRING_GETMEM(arg, ptr, slen);
11687 if (ptr[slen-1] != NARG_SENTINEL)
11688 rb_raise(rb_eArgError, "return value overflowed string");
11689 ptr[slen-1] = '\0';
11690 }
11691
11692 return INT2NUM(retval);
11693}
11694
11695#ifdef HAVE_IOCTL
11696static VALUE
11697rb_ioctl(VALUE io, VALUE req, VALUE arg)
11698{
11699 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11700 rb_io_t *fptr;
11701 long narg;
11702 int retval;
11703
11704 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11705 GetOpenFile(io, fptr);
11706 retval = do_ioctl(fptr, cmd, narg);
11707 return finish_narg(retval, arg, fptr);
11708}
11709
11710/*
11711 * call-seq:
11712 * ioctl(integer_cmd, argument) -> integer
11713 *
11714 * Invokes Posix system call {ioctl(2)}[https://man7.org/linux/man-pages/man2/ioctl.2.html],
11715 * which issues a low-level command to an I/O device.
11716 *
11717 * Issues a low-level command to an I/O device.
11718 * The arguments and returned value are platform-dependent.
11719 * The effect of the call is platform-dependent.
11720 *
11721 * If argument +argument+ is an integer, it is passed directly;
11722 * if it is a string, it is interpreted as a binary sequence of bytes.
11723 *
11724 * Not implemented on all platforms.
11725 *
11726 */
11727
11728static VALUE
11729rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11730{
11731 VALUE req, arg;
11732
11733 rb_scan_args(argc, argv, "11", &req, &arg);
11734 return rb_ioctl(io, req, arg);
11735}
11736#else
11737#define rb_io_ioctl rb_f_notimplement
11738#endif
11739
11740#ifdef HAVE_FCNTL
11741struct fcntl_arg {
11742 int fd;
11743 int cmd;
11744 long narg;
11745};
11746
11747static VALUE
11748nogvl_fcntl(void *ptr)
11749{
11750 struct fcntl_arg *arg = ptr;
11751
11752#if defined(F_DUPFD)
11753 if (arg->cmd == F_DUPFD)
11754 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11755#endif
11756 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11757}
11758
11759static int
11760do_fcntl(struct rb_io *io, int cmd, long narg)
11761{
11762 int retval;
11763 struct fcntl_arg arg;
11764
11765 arg.fd = io->fd;
11766 arg.cmd = cmd;
11767 arg.narg = narg;
11768
11769 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11770 if (retval != -1) {
11771 switch (cmd) {
11772#if defined(F_DUPFD)
11773 case F_DUPFD:
11774#endif
11775#if defined(F_DUPFD_CLOEXEC)
11776 case F_DUPFD_CLOEXEC:
11777#endif
11778 rb_update_max_fd(retval);
11779 }
11780 }
11781
11782 return retval;
11783}
11784
11785static VALUE
11786rb_fcntl(VALUE io, VALUE req, VALUE arg)
11787{
11788 int cmd = NUM2INT(req);
11789 rb_io_t *fptr;
11790 long narg;
11791 int retval;
11792
11793 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11794 GetOpenFile(io, fptr);
11795 retval = do_fcntl(fptr, cmd, narg);
11796 return finish_narg(retval, arg, fptr);
11797}
11798
11799/*
11800 * call-seq:
11801 * fcntl(integer_cmd, argument) -> integer
11802 *
11803 * Invokes Posix system call {fcntl(2)}[https://man7.org/linux/man-pages/man2/fcntl.2.html],
11804 * which provides a mechanism for issuing low-level commands to control or query
11805 * a file-oriented I/O stream. Arguments and results are platform
11806 * dependent.
11807 *
11808 * If +argument+ is a number, its value is passed directly;
11809 * if it is a string, it is interpreted as a binary sequence of bytes.
11810 * (Array#pack might be a useful way to build this string.)
11811 *
11812 * Not implemented on all platforms.
11813 *
11814 */
11815
11816static VALUE
11817rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11818{
11819 VALUE req, arg;
11820
11821 rb_scan_args(argc, argv, "11", &req, &arg);
11822 return rb_fcntl(io, req, arg);
11823}
11824#else
11825#define rb_io_fcntl rb_f_notimplement
11826#endif
11827
11828#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11829/*
11830 * call-seq:
11831 * syscall(integer_callno, *arguments) -> integer
11832 *
11833 * Invokes Posix system call {syscall(2)}[https://man7.org/linux/man-pages/man2/syscall.2.html],
11834 * which calls a specified function.
11835 *
11836 * Calls the operating system function identified by +integer_callno+;
11837 * returns the result of the function or raises SystemCallError if it failed.
11838 * The effect of the call is platform-dependent.
11839 * The arguments and returned value are platform-dependent.
11840 *
11841 * For each of +arguments+: if it is an integer, it is passed directly;
11842 * if it is a string, it is interpreted as a binary sequence of bytes.
11843 * There may be as many as nine such arguments.
11844 *
11845 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11846 * are platform-dependent.
11847 *
11848 * Note: Method +syscall+ is essentially unsafe and unportable.
11849 * The DL (Fiddle) library is preferred for safer and a bit
11850 * more portable programming.
11851 *
11852 * Not implemented on all platforms.
11853 *
11854 */
11855
11856static VALUE
11857rb_f_syscall(int argc, VALUE *argv, VALUE _)
11858{
11859 VALUE arg[8];
11860#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11861# define SYSCALL __syscall
11862# define NUM2SYSCALLID(x) NUM2LONG(x)
11863# define RETVAL2NUM(x) LONG2NUM(x)
11864# if SIZEOF_LONG == 8
11865 long num, retval = -1;
11866# elif SIZEOF_LONG_LONG == 8
11867 long long num, retval = -1;
11868# else
11869# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11870# endif
11871#elif defined(__linux__)
11872# define SYSCALL syscall
11873# define NUM2SYSCALLID(x) NUM2LONG(x)
11874# define RETVAL2NUM(x) LONG2NUM(x)
11875 /*
11876 * Linux man page says, syscall(2) function prototype is below.
11877 *
11878 * int syscall(int number, ...);
11879 *
11880 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11881 */
11882 long num, retval = -1;
11883#else
11884# define SYSCALL syscall
11885# define NUM2SYSCALLID(x) NUM2INT(x)
11886# define RETVAL2NUM(x) INT2NUM(x)
11887 int num, retval = -1;
11888#endif
11889 int i;
11890
11891 if (RTEST(ruby_verbose)) {
11893 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11894 }
11895
11896 if (argc == 0)
11897 rb_raise(rb_eArgError, "too few arguments for syscall");
11898 if (argc > numberof(arg))
11899 rb_raise(rb_eArgError, "too many arguments for syscall");
11900 num = NUM2SYSCALLID(argv[0]); ++argv;
11901 for (i = argc - 1; i--; ) {
11902 VALUE v = rb_check_string_type(argv[i]);
11903
11904 if (!NIL_P(v)) {
11905 StringValue(v);
11906 rb_str_modify(v);
11907 arg[i] = (VALUE)StringValueCStr(v);
11908 }
11909 else {
11910 arg[i] = (VALUE)NUM2LONG(argv[i]);
11911 }
11912 }
11913
11914 switch (argc) {
11915 case 1:
11916 retval = SYSCALL(num);
11917 break;
11918 case 2:
11919 retval = SYSCALL(num, arg[0]);
11920 break;
11921 case 3:
11922 retval = SYSCALL(num, arg[0],arg[1]);
11923 break;
11924 case 4:
11925 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11926 break;
11927 case 5:
11928 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11929 break;
11930 case 6:
11931 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11932 break;
11933 case 7:
11934 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11935 break;
11936 case 8:
11937 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11938 break;
11939 }
11940
11941 if (retval == -1)
11942 rb_sys_fail(0);
11943 return RETVAL2NUM(retval);
11944#undef SYSCALL
11945#undef NUM2SYSCALLID
11946#undef RETVAL2NUM
11947}
11948#else
11949#define rb_f_syscall rb_f_notimplement
11950#endif
11951
11952static VALUE
11953io_new_instance(VALUE args)
11954{
11955 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11956}
11957
11958static rb_encoding *
11959find_encoding(VALUE v)
11960{
11961 rb_encoding *enc = rb_find_encoding(v);
11962 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11963 return enc;
11964}
11965
11966static void
11967io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11968{
11969 rb_encoding *enc, *enc2;
11970 int ecflags = fptr->encs.ecflags;
11971 VALUE ecopts, tmp;
11972
11973 if (!NIL_P(v2)) {
11974 enc2 = find_encoding(v1);
11975 tmp = rb_check_string_type(v2);
11976 if (!NIL_P(tmp)) {
11977 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11978 /* Special case - "-" => no transcoding */
11979 enc = enc2;
11980 enc2 = NULL;
11981 }
11982 else
11983 enc = find_encoding(v2);
11984 if (enc == enc2) {
11985 /* Special case - "-" => no transcoding */
11986 enc2 = NULL;
11987 }
11988 }
11989 else {
11990 enc = find_encoding(v2);
11991 if (enc == enc2) {
11992 /* Special case - "-" => no transcoding */
11993 enc2 = NULL;
11994 }
11995 }
11996 if (enc2 == rb_ascii8bit_encoding()) {
11997 /* If external is ASCII-8BIT, no transcoding */
11998 enc = enc2;
11999 enc2 = NULL;
12000 }
12001 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12002 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
12003 }
12004 else {
12005 if (NIL_P(v1)) {
12006 /* Set to default encodings */
12007 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
12008 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12009 ecopts = Qnil;
12010 }
12011 else {
12012 tmp = rb_check_string_type(v1);
12013 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
12014 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
12015 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12016 }
12017 else {
12018 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
12019 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12020 }
12021 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
12022 }
12023 }
12024 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
12025 fptr->encs.enc = enc;
12026 fptr->encs.enc2 = enc2;
12027 fptr->encs.ecflags = ecflags;
12028 fptr->encs.ecopts = ecopts;
12029 clear_codeconv(fptr);
12030
12031}
12032
12034 rb_io_t *fptr;
12035 VALUE v1;
12036 VALUE v2;
12037 VALUE opt;
12038};
12039
12040static VALUE
12041io_encoding_set_v(VALUE v)
12042{
12043 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
12044 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
12045 return Qnil;
12046}
12047
12048static VALUE
12049pipe_pair_close(VALUE rw)
12050{
12051 VALUE *rwp = (VALUE *)rw;
12052 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
12053}
12054
12055/*
12056 * call-seq:
12057 * IO.pipe(**opts) -> [read_io, write_io]
12058 * IO.pipe(enc, **opts) -> [read_io, write_io]
12059 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
12060 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
12061 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
12062 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
12063 *
12064 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
12065 * connected to each other.
12066 *
12067 * If argument +enc_string+ is given, it must be a string containing one of:
12068 *
12069 * - The name of the encoding to be used as the external encoding.
12070 * - The colon-separated names of two encodings to be used as the external
12071 * and internal encodings.
12072 *
12073 * If argument +int_enc+ is given, it must be an Encoding object
12074 * or encoding name string that specifies the internal encoding to be used;
12075 * if argument +ext_enc+ is also given, it must be an Encoding object
12076 * or encoding name string that specifies the external encoding to be used.
12077 *
12078 * The string read from +read_io+ is tagged with the external encoding;
12079 * if an internal encoding is also specified, the string is converted
12080 * to, and tagged with, that encoding.
12081 *
12082 * If any encoding is specified,
12083 * optional hash arguments specify the conversion option.
12084 *
12085 * Optional keyword arguments +opts+ specify:
12086 *
12087 * - {Open Options}[rdoc-ref:IO@Open+Options].
12088 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12089 *
12090 * With no block given, returns the two endpoints in an array:
12091 *
12092 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
12093 *
12094 * With a block given, calls the block with the two endpoints;
12095 * closes both endpoints and returns the value of the block:
12096 *
12097 * IO.pipe {|read_io, write_io| p read_io; p write_io }
12098 *
12099 * Output:
12100 *
12101 * #<IO:fd 6>
12102 * #<IO:fd 7>
12103 *
12104 * Not available on all platforms.
12105 *
12106 * In the example below, the two processes close the ends of the pipe
12107 * that they are not using. This is not just a cosmetic nicety. The
12108 * read end of a pipe will not generate an end of file condition if
12109 * there are any writers with the pipe still open. In the case of the
12110 * parent process, the <tt>rd.read</tt> will never return if it
12111 * does not first issue a <tt>wr.close</tt>:
12112 *
12113 * rd, wr = IO.pipe
12114 *
12115 * if fork
12116 * wr.close
12117 * puts "Parent got: <#{rd.read}>"
12118 * rd.close
12119 * Process.wait
12120 * else
12121 * rd.close
12122 * puts 'Sending message to parent'
12123 * wr.write "Hi Dad"
12124 * wr.close
12125 * end
12126 *
12127 * <em>produces:</em>
12128 *
12129 * Sending message to parent
12130 * Parent got: <Hi Dad>
12131 *
12132 */
12133
12134static VALUE
12135rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
12136{
12137 int pipes[2], state;
12138 VALUE r, w, args[3], v1, v2;
12139 VALUE opt;
12140 rb_io_t *fptr, *fptr2;
12141 struct io_encoding_set_args ies_args;
12142 enum rb_io_mode fmode = 0;
12143 VALUE ret;
12144
12145 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
12146 if (rb_pipe(pipes) < 0)
12147 rb_sys_fail(0);
12148
12149 args[0] = klass;
12150 args[1] = INT2NUM(pipes[0]);
12151 args[2] = INT2FIX(O_RDONLY);
12152 r = rb_protect(io_new_instance, (VALUE)args, &state);
12153 if (state) {
12154 close(pipes[0]);
12155 close(pipes[1]);
12156 rb_jump_tag(state);
12157 }
12158 GetOpenFile(r, fptr);
12159
12160 ies_args.fptr = fptr;
12161 ies_args.v1 = v1;
12162 ies_args.v2 = v2;
12163 ies_args.opt = opt;
12164 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
12165 if (state) {
12166 close(pipes[1]);
12167 io_close(r);
12168 rb_jump_tag(state);
12169 }
12170
12171 args[1] = INT2NUM(pipes[1]);
12172 args[2] = INT2FIX(O_WRONLY);
12173 w = rb_protect(io_new_instance, (VALUE)args, &state);
12174 if (state) {
12175 close(pipes[1]);
12176 if (!NIL_P(r)) rb_io_close(r);
12177 rb_jump_tag(state);
12178 }
12179 GetOpenFile(w, fptr2);
12180 rb_io_synchronized(fptr2);
12181
12182 extract_binmode(opt, &fmode);
12183
12184 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
12187 }
12188
12189#if DEFAULT_TEXTMODE
12190 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12191 fptr->mode &= ~FMODE_TEXTMODE;
12192 setmode(fptr->fd, O_BINARY);
12193 }
12194#if RUBY_CRLF_ENVIRONMENT
12197 }
12198#endif
12199#endif
12200 fptr->mode |= fmode;
12201#if DEFAULT_TEXTMODE
12202 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12203 fptr2->mode &= ~FMODE_TEXTMODE;
12204 setmode(fptr2->fd, O_BINARY);
12205 }
12206#endif
12207 fptr2->mode |= fmode;
12208
12209 ret = rb_assoc_new(r, w);
12210 if (rb_block_given_p()) {
12211 VALUE rw[2];
12212 rw[0] = r;
12213 rw[1] = w;
12214 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12215 }
12216 return ret;
12217}
12218
12220 int argc;
12221 VALUE *argv;
12222 VALUE io;
12223};
12224
12225static void
12226open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12227{
12228 VALUE path, v;
12229 VALUE vmode = Qnil, vperm = Qnil;
12230
12231 path = *argv++;
12232 argc--;
12233 FilePathValue(path);
12234 arg->io = 0;
12235 arg->argc = argc;
12236 arg->argv = argv;
12237 if (NIL_P(opt)) {
12238 vmode = INT2NUM(O_RDONLY);
12239 vperm = INT2FIX(0666);
12240 }
12241 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12242 int n;
12243
12244 v = rb_to_array_type(v);
12245 n = RARRAY_LENINT(v);
12246 rb_check_arity(n, 0, 3); /* rb_io_open */
12247 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12248 }
12249 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12250}
12251
12252static VALUE
12253io_s_foreach(VALUE v)
12254{
12255 struct getline_arg *arg = (void *)v;
12256 VALUE str;
12257
12258 if (arg->limit == 0)
12259 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12260 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12261 rb_lastline_set(str);
12262 rb_yield(str);
12263 }
12265 return Qnil;
12266}
12267
12268/*
12269 * call-seq:
12270 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12271 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12272 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12273 * IO.foreach(...) -> an_enumerator
12274 *
12275 * Calls the block with each successive line read from the stream.
12276 *
12277 * The first argument must be a string that is the path to a file.
12278 *
12279 * With only argument +path+ given, parses lines from the file at the given +path+,
12280 * as determined by the default line separator,
12281 * and calls the block with each successive line:
12282 *
12283 * File.foreach('t.txt') {|line| p line }
12284 *
12285 * Output: the same as above.
12286 *
12287 * For both forms, command and path, the remaining arguments are the same.
12288 *
12289 * With argument +sep+ given, parses lines as determined by that line separator
12290 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12291 *
12292 * File.foreach('t.txt', 'li') {|line| p line }
12293 *
12294 * Output:
12295 *
12296 * "First li"
12297 * "ne\nSecond li"
12298 * "ne\n\nThird li"
12299 * "ne\nFourth li"
12300 * "ne\n"
12301 *
12302 * Each paragraph:
12303 *
12304 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12305 *
12306 * Output:
12307 *
12308 * "First line\nSecond line\n\n"
12309 * "Third line\nFourth line\n"
12310 *
12311 * With argument +limit+ given, parses lines as determined by the default
12312 * line separator and the given line-length limit
12313 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12314 *
12315 * File.foreach('t.txt', 7) {|line| p line }
12316 *
12317 * Output:
12318 *
12319 * "First l"
12320 * "ine\n"
12321 * "Second "
12322 * "line\n"
12323 * "\n"
12324 * "Third l"
12325 * "ine\n"
12326 * "Fourth l"
12327 * "line\n"
12328 *
12329 * With arguments +sep+ and +limit+ given,
12330 * combines the two behaviors
12331 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12332 *
12333 * Optional keyword arguments +opts+ specify:
12334 *
12335 * - {Open Options}[rdoc-ref:IO@Open+Options].
12336 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12337 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12338 *
12339 * Returns an Enumerator if no block is given.
12340 *
12341 */
12342
12343static VALUE
12344rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12345{
12346 VALUE opt;
12347 int orig_argc = argc;
12348 struct foreach_arg arg;
12349 struct getline_arg garg;
12350
12351 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12352 RETURN_ENUMERATOR(self, orig_argc, argv);
12353 extract_getline_args(argc-1, argv+1, &garg);
12354 open_key_args(self, argc, argv, opt, &arg);
12355 if (NIL_P(arg.io)) return Qnil;
12356 extract_getline_opts(opt, &garg);
12357 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12358 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12359}
12360
12361static VALUE
12362io_s_readlines(VALUE v)
12363{
12364 struct getline_arg *arg = (void *)v;
12365 return io_readlines(arg, arg->io);
12366}
12367
12368/*
12369 * call-seq:
12370 * IO.readlines(path, sep = $/, **opts) -> array
12371 * IO.readlines(path, limit, **opts) -> array
12372 * IO.readlines(path, sep, limit, **opts) -> array
12373 *
12374 * Returns an array of all lines read from the stream.
12375 *
12376 * The first argument must be a string that is the path to a file.
12377 *
12378 * With only argument +path+ given, parses lines from the file at the given +path+,
12379 * as determined by the default line separator,
12380 * and returns those lines in an array:
12381 *
12382 * IO.readlines('t.txt')
12383 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12384 *
12385 * With argument +sep+ given, parses lines as determined by that line separator
12386 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12387 *
12388 * # Ordinary separator.
12389 * IO.readlines('t.txt', 'li')
12390 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12391 * # Get-paragraphs separator.
12392 * IO.readlines('t.txt', '')
12393 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12394 * # Get-all separator.
12395 * IO.readlines('t.txt', nil)
12396 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12397 *
12398 * With argument +limit+ given, parses lines as determined by the default
12399 * line separator and the given line-length limit
12400 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12401 *
12402 * IO.readlines('t.txt', 7)
12403 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12404 *
12405 * With arguments +sep+ and +limit+ given,
12406 * combines the two behaviors
12407 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12408 *
12409 * Optional keyword arguments +opts+ specify:
12410 *
12411 * - {Open Options}[rdoc-ref:IO@Open+Options].
12412 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12413 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12414 *
12415 */
12416
12417static VALUE
12418rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12419{
12420 VALUE opt;
12421 struct foreach_arg arg;
12422 struct getline_arg garg;
12423
12424 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12425 extract_getline_args(argc-1, argv+1, &garg);
12426 open_key_args(io, argc, argv, opt, &arg);
12427 if (NIL_P(arg.io)) return Qnil;
12428 extract_getline_opts(opt, &garg);
12429 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12430 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12431}
12432
12433static VALUE
12434io_s_read(VALUE v)
12435{
12436 struct foreach_arg *arg = (void *)v;
12437 return io_read(arg->argc, arg->argv, arg->io);
12438}
12439
12440struct seek_arg {
12441 VALUE io;
12442 VALUE offset;
12443 int mode;
12444};
12445
12446static VALUE
12447seek_before_access(VALUE argp)
12448{
12449 struct seek_arg *arg = (struct seek_arg *)argp;
12450 rb_io_binmode(arg->io);
12451 return rb_io_seek(arg->io, arg->offset, arg->mode);
12452}
12453
12454/*
12455 * call-seq:
12456 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12457 *
12458 * Opens the stream, reads and returns some or all of its content,
12459 * and closes the stream; returns +nil+ if no bytes were read.
12460 *
12461 * The first argument must be a string that is the path to a file.
12462 *
12463 * With only argument +path+ given, reads in text mode and returns the entire content
12464 * of the file at the given path:
12465 *
12466 * File.read('t.txt')
12467 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
12468 * File.read('t.ja')
12469 * # => "こんにちは"
12470 * File.read('t.dat')
12471 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12472 *
12473 * On Windows, text mode can terminate reading and leave bytes in the file
12474 * unread when encountering certain special bytes. Consider using
12475 * IO.binread if all bytes in the file should be read.
12476 *
12477 * With argument +length+, returns +length+ bytes if available:
12478 *
12479 * File.read('t.txt', 7)
12480 * # => "First l"
12481 * File.read('t.ja', 7)
12482 * # => "\xE3\x81\x93\xE3\x82\x93\xE3"
12483 * File.read('t.dat', 7)
12484 * # => "\xFE\xFF\x99\x90\x99\x91\x99"
12485 *
12486 * Returns all bytes if +length+ is larger than the files size:
12487 *
12488 * File.read('t.txt', 700)
12489 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12490 * File.read('t.ja', 700)
12491 * # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
12492 * File.read('t.dat', 700)
12493 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12494 *
12495 * With arguments +length+ and +offset+, returns +length+ bytes
12496 * if available, beginning at the given +offset+:
12497 *
12498 * File.read('t.txt', 10, 2)
12499 * # => "rst line\r\n"
12500 * File.read('t.ja', 10, 2)
12501 * # => "\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1"
12502 * File.read('t.dat', 10, 2)
12503 * # => "\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12504 *
12505 * Returns +nil+ if +offset+ is past the end of the stream:
12506 *
12507 * File.read('t.txt', 10, 200)
12508 * # => nil
12509 *
12510 * Optional keyword arguments +opts+ specify:
12511 *
12512 * - {Open Options}[rdoc-ref:IO@Open+Options].
12513 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12514 *
12515 */
12516
12517static VALUE
12518rb_io_s_read(int argc, VALUE *argv, VALUE io)
12519{
12520 VALUE opt, offset;
12521 rb_len_t off;
12522 struct foreach_arg arg;
12523
12524 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12525 if (!NIL_P(offset) && (off = NUM2LEN(offset)) < 0) {
12526 rb_raise(rb_eArgError, "negative offset %"PRIdLEN" given", off);
12527 }
12528 open_key_args(io, argc, argv, opt, &arg);
12529 if (NIL_P(arg.io)) return Qnil;
12530 if (!NIL_P(offset)) {
12531 struct seek_arg sarg;
12532 int state = 0;
12533 sarg.io = arg.io;
12534 sarg.offset = offset;
12535 sarg.mode = SEEK_SET;
12536 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12537 if (state) {
12538 rb_io_close(arg.io);
12539 rb_jump_tag(state);
12540 }
12541 if (arg.argc == 2) arg.argc = 1;
12542 }
12543 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12544}
12545
12546/*
12547 * call-seq:
12548 * IO.binread(path, length = nil, offset = 0) -> string or nil
12549 *
12550 * Behaves like IO.read, except that the stream is opened in binary mode
12551 * with ASCII-8BIT encoding.
12552 *
12553 */
12554
12555static VALUE
12556rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12557{
12558 VALUE offset;
12559 struct foreach_arg arg;
12560 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12561 enum {
12562 oflags = O_RDONLY
12563#ifdef O_BINARY
12564 |O_BINARY
12565#endif
12566 };
12567 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12568
12569 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12570 FilePathValue(argv[0]);
12571 convconfig.enc = rb_ascii8bit_encoding();
12572 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12573 if (NIL_P(arg.io)) return Qnil;
12574 arg.argv = argv+1;
12575 arg.argc = (argc > 1) ? 1 : 0;
12576 if (!NIL_P(offset)) {
12577 struct seek_arg sarg;
12578 int state = 0;
12579 sarg.io = arg.io;
12580 sarg.offset = offset;
12581 sarg.mode = SEEK_SET;
12582 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12583 if (state) {
12584 rb_io_close(arg.io);
12585 rb_jump_tag(state);
12586 }
12587 }
12588 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12589}
12590
12591static VALUE
12592io_s_write0(VALUE v)
12593{
12594 struct write_arg *arg = (void *)v;
12595 return io_write(arg->io,arg->str,arg->nosync);
12596}
12597
12598static VALUE
12599io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12600{
12601 VALUE string, offset, opt;
12602 struct foreach_arg arg;
12603 struct write_arg warg;
12604
12605 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12606
12607 if (NIL_P(opt)) opt = rb_hash_new();
12608 else opt = rb_hash_dup(opt);
12609
12610
12611 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12612 int mode = O_WRONLY|O_CREAT;
12613#ifdef O_BINARY
12614 if (binary) mode |= O_BINARY;
12615#endif
12616 if (NIL_P(offset)) mode |= O_TRUNC;
12617 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12618 }
12619 open_key_args(klass, argc, argv, opt, &arg);
12620
12621#ifndef O_BINARY
12622 if (binary) rb_io_binmode_m(arg.io);
12623#endif
12624
12625 if (NIL_P(arg.io)) return Qnil;
12626 if (!NIL_P(offset)) {
12627 struct seek_arg sarg;
12628 int state = 0;
12629 sarg.io = arg.io;
12630 sarg.offset = offset;
12631 sarg.mode = SEEK_SET;
12632 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12633 if (state) {
12634 rb_io_close(arg.io);
12635 rb_jump_tag(state);
12636 }
12637 }
12638
12639 warg.io = arg.io;
12640 warg.str = string;
12641 warg.nosync = 0;
12642
12643 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12644}
12645
12646/*
12647 * call-seq:
12648 * IO.write(path, data, offset = 0, **opts) -> nonnegative_integer
12649 *
12650 * Opens the stream, writes the given +data+ to it,
12651 * and closes the stream; returns the number of bytes written.
12652 *
12653 * The first argument must be a string that is the path to a file.
12654 *
12655 * With only arguments +path+ and +data+ given,
12656 * writes the given data to the file at that path:
12657 *
12658 * path = 't.tmp'
12659 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n") # => 47
12660 * File.write(path, 'こんにちは') # => 15
12661 * File.write(path, "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94") # => 12
12662 *
12663 * When +offset+ is zero (the default), the entire file content is overwritten:
12664 *
12665 * File.read(path) # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12666 * File.write(path, 'foo')
12667 * File.read(path) # => "foo"
12668 *
12669 * When +offset+ in within the file content, the file content is partly overwritten,
12670 * beginning at byte +offset+:
12671 *
12672 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12673 * File.write(path, 'LINE', 6)
12674 * File.read(path) # => "First LINE\nSecond line\n\nFourth line\nFifth line\n"
12675 *
12676 * When the file contains multi-byte characters,
12677 * the effect of writing may disturb some characters:
12678 *
12679 * File.write(path, "こんにちは")
12680 * File.write(path, 'FOO', 3) # Replace one 3-byte character.
12681 * File.read(path) # => "こFOOにちは"
12682 * File.write(path, 'BAR', 7) # Replace bytes in two different 3-byte characters.
12683 * File.read(path) # => "こFOO\xE3BAR\x81\xA1は"
12684 *
12685 * If +offset+ is outside the file content,
12686 * the file is padded with null characters <tt>"\u0000"</tt>:
12687 *
12688 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12689 * File.write(path, 'FOO', 55)
12690 * File.read(path)
12691 * # => "First line\nSecond line\n\nFourth line\nFifth line\n\u0000\u0000\u0000FOO"
12692 *
12693 * Optional keyword arguments +opts+ specify:
12694 *
12695 * - {Open Options}[rdoc-ref:IO@Open+Options].
12696 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12697 *
12698 */
12699
12700static VALUE
12701rb_io_s_write(int argc, VALUE *argv, VALUE io)
12702{
12703 return io_s_write(argc, argv, io, 0);
12704}
12705
12706/*
12707 * call-seq:
12708 * IO.binwrite(path, string, offset = 0, **opts) -> integer
12709 *
12710 * Behaves like IO.write, except that the stream is opened in binary mode
12711 * with ASCII-8BIT encoding.
12712 *
12713 */
12714
12715static VALUE
12716rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12717{
12718 return io_s_write(argc, argv, io, 1);
12719}
12720
12722 VALUE src;
12723 VALUE dst;
12724 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12725 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12726
12727 rb_io_t *src_fptr;
12728 rb_io_t *dst_fptr;
12729 unsigned close_src : 1;
12730 unsigned close_dst : 1;
12731 int error_no;
12732 rb_off_t total;
12733 const char *syserr;
12734 const char *notimp;
12735 VALUE th;
12736 struct stat src_stat;
12737 struct stat dst_stat;
12738#ifdef HAVE_FCOPYFILE
12739 copyfile_state_t copyfile_state;
12740#endif
12741};
12742
12743static void *
12744exec_interrupts(void *arg)
12745{
12746 VALUE th = (VALUE)arg;
12747 rb_thread_execute_interrupts(th);
12748 return NULL;
12749}
12750
12751/*
12752 * returns TRUE if the preceding system call was interrupted
12753 * so we can continue. If the thread was interrupted, we
12754 * reacquire the GVL to execute interrupts before continuing.
12755 */
12756static int
12757maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12758{
12759 switch (errno) {
12760 case EINTR:
12761#if defined(ERESTART)
12762 case ERESTART:
12763#endif
12764 if (rb_thread_interrupted(stp->th)) {
12765 if (has_gvl)
12766 rb_thread_execute_interrupts(stp->th);
12767 else
12768 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12769 }
12770 return TRUE;
12771 }
12772 return FALSE;
12773}
12774
12776 VALUE scheduler;
12777
12778 rb_io_t *fptr;
12779 short events;
12780
12781 VALUE result;
12782};
12783
12784static void *
12785fiber_scheduler_wait_for(void * _arguments)
12786{
12787 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12788
12789 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12790
12791 return NULL;
12792}
12793
12794#if USE_POLL
12795# define IOWAIT_SYSCALL "poll"
12796STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12797STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12798static int
12799nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12800{
12802 if (scheduler != Qnil) {
12803 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12804 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12805 return RTEST(args.result);
12806 }
12807
12808 int fd = fptr->fd;
12809 if (fd == -1) return 0;
12810
12811 struct pollfd fds;
12812
12813 fds.fd = fd;
12814 fds.events = events;
12815
12816 int timeout_milliseconds = -1;
12817
12818 if (timeout) {
12819 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12820 }
12821
12822 return poll(&fds, 1, timeout_milliseconds);
12823}
12824#else /* !USE_POLL */
12825# define IOWAIT_SYSCALL "select"
12826static int
12827nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12828{
12830 if (scheduler != Qnil) {
12831 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12832 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12833 return RTEST(args.result);
12834 }
12835
12836 int fd = fptr->fd;
12837
12838 if (fd == -1) {
12839 errno = EBADF;
12840 return -1;
12841 }
12842
12843 rb_fdset_t fds;
12844 int ret;
12845
12846 rb_fd_init(&fds);
12847 rb_fd_set(fd, &fds);
12848
12849 switch (events) {
12850 case RB_WAITFD_IN:
12851 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12852 break;
12853 case RB_WAITFD_OUT:
12854 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12855 break;
12856 default:
12857 VM_UNREACHABLE(nogvl_wait_for);
12858 }
12859
12860 rb_fd_term(&fds);
12861
12862 // On timeout, this returns 0.
12863 return ret;
12864}
12865#endif /* !USE_POLL */
12866
12867static int
12868maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12869{
12870 int ret;
12871
12872 do {
12873 if (has_gvl) {
12875 }
12876 else {
12877 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12878 }
12879 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12880
12881 if (ret < 0) {
12882 stp->syserr = IOWAIT_SYSCALL;
12883 stp->error_no = errno;
12884 return ret;
12885 }
12886 return 0;
12887}
12888
12889static int
12890nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12891{
12892 int ret;
12893
12894 do {
12895 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12896 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12897
12898 if (ret < 0) {
12899 stp->syserr = IOWAIT_SYSCALL;
12900 stp->error_no = errno;
12901 return ret;
12902 }
12903 return 0;
12904}
12905
12906#ifdef USE_COPY_FILE_RANGE
12907
12908static ssize_t
12909simple_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)
12910{
12911#ifdef HAVE_COPY_FILE_RANGE
12912 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12913#else
12914 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12915#endif
12916}
12917
12918static int
12919nogvl_copy_file_range(struct copy_stream_struct *stp)
12920{
12921 ssize_t ss;
12922 rb_off_t src_size;
12923 rb_off_t copy_length, src_offset, *src_offset_ptr;
12924
12925 if (!S_ISREG(stp->src_stat.st_mode))
12926 return 0;
12927
12928 src_size = stp->src_stat.st_size;
12929 src_offset = stp->src_offset;
12930 if (src_offset >= (rb_off_t)0) {
12931 src_offset_ptr = &src_offset;
12932 }
12933 else {
12934 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12935 }
12936
12937 copy_length = stp->copy_length;
12938 if (copy_length < (rb_off_t)0) {
12939 if (src_offset < (rb_off_t)0) {
12940 rb_off_t current_offset;
12941 errno = 0;
12942 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12943 if (current_offset < (rb_off_t)0 && errno) {
12944 stp->syserr = "lseek";
12945 stp->error_no = errno;
12946 return (int)current_offset;
12947 }
12948 copy_length = src_size - current_offset;
12949 }
12950 else {
12951 copy_length = src_size - src_offset;
12952 }
12953 }
12954
12955 retry_copy_file_range:
12956# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12957 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12958 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12959# else
12960 ss = (ssize_t)copy_length;
12961# endif
12962 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12963 if (0 < ss) {
12964 stp->total += ss;
12965 copy_length -= ss;
12966 if (0 < copy_length) {
12967 goto retry_copy_file_range;
12968 }
12969 }
12970 if (ss < 0) {
12971 if (maygvl_copy_stream_continue_p(0, stp)) {
12972 goto retry_copy_file_range;
12973 }
12974 switch (errno) {
12975 case EINVAL:
12976 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12977 docker container) */
12978#ifdef ENOSYS
12979 case ENOSYS:
12980#endif
12981#ifdef EXDEV
12982 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12983#endif
12984 return 0;
12985 case EAGAIN:
12986#if EWOULDBLOCK != EAGAIN
12987 case EWOULDBLOCK:
12988#endif
12989 {
12990 int ret = nogvl_copy_stream_wait_write(stp);
12991 if (ret < 0) return ret;
12992 }
12993 goto retry_copy_file_range;
12994 case EBADF:
12995 {
12996 int e = errno;
12997 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12998
12999 if (flags != -1 && flags & O_APPEND) {
13000 return 0;
13001 }
13002 errno = e;
13003 }
13004 }
13005 stp->syserr = "copy_file_range";
13006 stp->error_no = errno;
13007 return (int)ss;
13008 }
13009 return 1;
13010}
13011#endif
13012
13013#ifdef HAVE_FCOPYFILE
13014static int
13015nogvl_fcopyfile(struct copy_stream_struct *stp)
13016{
13017 rb_off_t cur, ss = 0;
13018 const rb_off_t src_offset = stp->src_offset;
13019 int ret;
13020
13021 if (stp->copy_length >= (rb_off_t)0) {
13022 /* copy_length can't be specified in fcopyfile(3) */
13023 return 0;
13024 }
13025
13026 if (!S_ISREG(stp->src_stat.st_mode))
13027 return 0;
13028
13029 if (!S_ISREG(stp->dst_stat.st_mode))
13030 return 0;
13031 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
13032 return 0;
13033 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
13034 /* fcopyfile(3) appends src IO to dst IO and then truncates
13035 * dst IO to src IO's original size. */
13036 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
13037 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
13038 if (end > (rb_off_t)0) return 0;
13039 }
13040
13041 if (src_offset > (rb_off_t)0) {
13042 rb_off_t r;
13043
13044 /* get current offset */
13045 errno = 0;
13046 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13047 if (cur < (rb_off_t)0 && errno) {
13048 stp->error_no = errno;
13049 return 1;
13050 }
13051
13052 errno = 0;
13053 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13054 if (r < (rb_off_t)0 && errno) {
13055 stp->error_no = errno;
13056 return 1;
13057 }
13058 }
13059
13060 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
13061 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
13062 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
13063
13064 if (ret == 0) { /* success */
13065 stp->total = ss;
13066 if (src_offset > (rb_off_t)0) {
13067 rb_off_t r;
13068 errno = 0;
13069 /* reset offset */
13070 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
13071 if (r < (rb_off_t)0 && errno) {
13072 stp->error_no = errno;
13073 return 1;
13074 }
13075 }
13076 }
13077 else {
13078 switch (errno) {
13079 case ENOTSUP:
13080 case EPERM:
13081 case EINVAL:
13082 return 0;
13083 }
13084 stp->syserr = "fcopyfile";
13085 stp->error_no = errno;
13086 return (int)ret;
13087 }
13088 return 1;
13089}
13090#endif
13091
13092#ifdef HAVE_SENDFILE
13093
13094# ifdef __linux__
13095# define USE_SENDFILE
13096
13097# ifdef HAVE_SYS_SENDFILE_H
13098# include <sys/sendfile.h>
13099# endif
13100
13101static ssize_t
13102simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13103{
13104 return sendfile(out_fd, in_fd, offset, (size_t)count);
13105}
13106
13107# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
13108/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
13109 * without cpuset -l 0.
13110 */
13111# define USE_SENDFILE
13112
13113static ssize_t
13114simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13115{
13116 int r;
13117 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
13118 rb_off_t sbytes;
13119# ifdef __APPLE__
13120 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
13121 sbytes = count;
13122# else
13123 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
13124# endif
13125 if (r != 0 && sbytes == 0) return r;
13126 if (offset) {
13127 *offset += sbytes;
13128 }
13129 else {
13130 lseek(in_fd, sbytes, SEEK_CUR);
13131 }
13132 return (ssize_t)sbytes;
13133}
13134
13135# endif
13136
13137#endif
13138
13139#ifdef USE_SENDFILE
13140static int
13141nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
13142{
13143 ssize_t ss;
13144 rb_off_t src_size;
13145 rb_off_t copy_length;
13146 rb_off_t src_offset;
13147 int use_pread;
13148
13149 if (!S_ISREG(stp->src_stat.st_mode))
13150 return 0;
13151
13152 src_size = stp->src_stat.st_size;
13153#ifndef __linux__
13154 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
13155 return 0;
13156#endif
13157
13158 src_offset = stp->src_offset;
13159 use_pread = src_offset >= (rb_off_t)0;
13160
13161 copy_length = stp->copy_length;
13162 if (copy_length < (rb_off_t)0) {
13163 if (use_pread)
13164 copy_length = src_size - src_offset;
13165 else {
13166 rb_off_t cur;
13167 errno = 0;
13168 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13169 if (cur < (rb_off_t)0 && errno) {
13170 stp->syserr = "lseek";
13171 stp->error_no = errno;
13172 return (int)cur;
13173 }
13174 copy_length = src_size - cur;
13175 }
13176 }
13177
13178 retry_sendfile:
13179# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13180 /* we are limited by the 32-bit ssize_t return value on 32-bit */
13181 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13182# else
13183 ss = (ssize_t)copy_length;
13184# endif
13185 if (use_pread) {
13186 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
13187 }
13188 else {
13189 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
13190 }
13191 if (0 < ss) {
13192 stp->total += ss;
13193 copy_length -= ss;
13194 if (0 < copy_length) {
13195 goto retry_sendfile;
13196 }
13197 }
13198 if (ss < 0) {
13199 if (maygvl_copy_stream_continue_p(0, stp))
13200 goto retry_sendfile;
13201 switch (errno) {
13202 case EINVAL:
13203#ifdef ENOSYS
13204 case ENOSYS:
13205#endif
13206#ifdef EOPNOTSUP
13207 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
13208 see also: [Feature #16965] */
13209 case EOPNOTSUP:
13210#endif
13211 return 0;
13212 case EAGAIN:
13213#if EWOULDBLOCK != EAGAIN
13214 case EWOULDBLOCK:
13215#endif
13216 {
13217 int ret;
13218#ifndef __linux__
13219 /*
13220 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
13221 * select() reports regular files to always be "ready", so
13222 * there is no need to select() on it.
13223 * Other OSes may have the same limitation for sendfile() which
13224 * allow us to bypass maygvl_copy_stream_wait_read()...
13225 */
13226 ret = maygvl_copy_stream_wait_read(0, stp);
13227 if (ret < 0) return ret;
13228#endif
13229 ret = nogvl_copy_stream_wait_write(stp);
13230 if (ret < 0) return ret;
13231 }
13232 goto retry_sendfile;
13233 }
13234 stp->syserr = "sendfile";
13235 stp->error_no = errno;
13236 return (int)ss;
13237 }
13238 return 1;
13239}
13240#endif
13241
13242static ssize_t
13243maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13244{
13245 if (has_gvl)
13246 return rb_io_read_memory(fptr, buf, count);
13247 else
13248 return read(fptr->fd, buf, count);
13249}
13250
13251static ssize_t
13252maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13253{
13254 ssize_t ss;
13255 retry_read:
13256 if (offset < (rb_off_t)0) {
13257 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13258 }
13259 else {
13260 ss = pread(stp->src_fptr->fd, buf, len, offset);
13261 }
13262 if (ss == 0) {
13263 return 0;
13264 }
13265 if (ss < 0) {
13266 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13267 goto retry_read;
13268 switch (errno) {
13269 case EAGAIN:
13270#if EWOULDBLOCK != EAGAIN
13271 case EWOULDBLOCK:
13272#endif
13273 {
13274 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13275 if (ret < 0) return ret;
13276 }
13277 goto retry_read;
13278#ifdef ENOSYS
13279 case ENOSYS:
13280 stp->notimp = "pread";
13281 return ss;
13282#endif
13283 }
13284 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13285 stp->error_no = errno;
13286 }
13287 return ss;
13288}
13289
13290static int
13291nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13292{
13293 ssize_t ss;
13294 int off = 0;
13295 while (len) {
13296 ss = write(stp->dst_fptr->fd, buf+off, len);
13297 if (ss < 0) {
13298 if (maygvl_copy_stream_continue_p(0, stp))
13299 continue;
13300 if (io_again_p(errno)) {
13301 int ret = nogvl_copy_stream_wait_write(stp);
13302 if (ret < 0) return ret;
13303 continue;
13304 }
13305 stp->syserr = "write";
13306 stp->error_no = errno;
13307 return (int)ss;
13308 }
13309 off += (int)ss;
13310 len -= (int)ss;
13311 stp->total += ss;
13312 }
13313 return 0;
13314}
13315
13316static void
13317nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13318{
13319 char buf[1024*16];
13320 size_t len;
13321 ssize_t ss;
13322 int ret;
13323 rb_off_t copy_length;
13324 rb_off_t src_offset;
13325 int use_eof;
13326 int use_pread;
13327
13328 copy_length = stp->copy_length;
13329 use_eof = copy_length < (rb_off_t)0;
13330 src_offset = stp->src_offset;
13331 use_pread = src_offset >= (rb_off_t)0;
13332
13333 if (use_pread && stp->close_src) {
13334 rb_off_t r;
13335 errno = 0;
13336 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13337 if (r < (rb_off_t)0 && errno) {
13338 stp->syserr = "lseek";
13339 stp->error_no = errno;
13340 return;
13341 }
13342 src_offset = (rb_off_t)-1;
13343 use_pread = 0;
13344 }
13345
13346 while (use_eof || 0 < copy_length) {
13347 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13348 len = (size_t)copy_length;
13349 }
13350 else {
13351 len = sizeof(buf);
13352 }
13353 if (use_pread) {
13354 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13355 if (0 < ss)
13356 src_offset += ss;
13357 }
13358 else {
13359 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13360 }
13361 if (ss <= 0) /* EOF or error */
13362 return;
13363
13364 ret = nogvl_copy_stream_write(stp, buf, ss);
13365 if (ret < 0)
13366 return;
13367
13368 if (!use_eof)
13369 copy_length -= ss;
13370 }
13371}
13372
13373static void *
13374nogvl_copy_stream_func(void *arg)
13375{
13376 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13377#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13378 int ret;
13379#endif
13380
13381#ifdef USE_COPY_FILE_RANGE
13382 ret = nogvl_copy_file_range(stp);
13383 if (ret != 0)
13384 goto finish; /* error or success */
13385#endif
13386
13387#ifdef HAVE_FCOPYFILE
13388 ret = nogvl_fcopyfile(stp);
13389 if (ret != 0)
13390 goto finish; /* error or success */
13391#endif
13392
13393#ifdef USE_SENDFILE
13394 ret = nogvl_copy_stream_sendfile(stp);
13395 if (ret != 0)
13396 goto finish; /* error or success */
13397#endif
13398
13399 nogvl_copy_stream_read_write(stp);
13400
13401#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13402 finish:
13403#endif
13404 return 0;
13405}
13406
13407static VALUE
13408copy_stream_fallback_body(VALUE arg)
13409{
13410 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13411 const int buflen = 16*1024;
13412 VALUE n;
13413 VALUE buf = rb_str_buf_new(buflen);
13414 rb_off_t rest = stp->copy_length;
13415 rb_off_t off = stp->src_offset;
13416 ID read_method = id_readpartial;
13417
13418 if (!stp->src_fptr) {
13419 if (!rb_respond_to(stp->src, read_method)) {
13420 read_method = id_read;
13421 }
13422 }
13423
13424 while (1) {
13425 rb_len_t numwrote;
13426 rb_len_t l;
13427 rb_str_make_independent(buf);
13428 if (stp->copy_length < (rb_off_t)0) {
13429 l = buflen;
13430 }
13431 else {
13432 if (rest == 0) {
13433 rb_str_resize(buf, 0);
13434 break;
13435 }
13436 l = buflen < rest ? buflen : (rb_len_t)rest;
13437 }
13438 if (!stp->src_fptr) {
13439 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13440
13441 if (read_method == id_read && NIL_P(rc))
13442 break;
13443 }
13444 else {
13445 ssize_t ss;
13446 rb_str_resize(buf, buflen);
13447 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13448 rb_str_resize(buf, ss > 0 ? ss : 0);
13449 if (ss < 0)
13450 return Qnil;
13451 if (ss == 0)
13452 rb_eof_error();
13453 if (off >= (rb_off_t)0)
13454 off += ss;
13455 }
13456 n = rb_io_write(stp->dst, buf);
13457 numwrote = NUM2LEN(n);
13458 stp->total += numwrote;
13459 rest -= numwrote;
13460 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13461 break;
13462 }
13463 }
13464
13465 return Qnil;
13466}
13467
13468static VALUE
13469copy_stream_fallback(struct copy_stream_struct *stp)
13470{
13471 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13472 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13473 }
13474 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13475 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13476 rb_eEOFError, (VALUE)0);
13477 return Qnil;
13478}
13479
13480static VALUE
13481copy_stream_body(VALUE arg)
13482{
13483 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13484 VALUE src_io = stp->src, dst_io = stp->dst;
13485 const int common_oflags = 0
13486#ifdef O_NOCTTY
13487 | O_NOCTTY
13488#endif
13489 ;
13490
13491 stp->th = rb_thread_current();
13492
13493 stp->total = 0;
13494
13495 if (src_io == argf ||
13496 !(RB_TYPE_P(src_io, T_FILE) ||
13497 RB_TYPE_P(src_io, T_STRING) ||
13498 rb_respond_to(src_io, rb_intern("to_path")))) {
13499 stp->src_fptr = NULL;
13500 }
13501 else {
13502 int stat_ret;
13503 VALUE tmp_io = rb_io_check_io(src_io);
13504 if (!NIL_P(tmp_io)) {
13505 src_io = tmp_io;
13506 }
13507 else if (!RB_TYPE_P(src_io, T_FILE)) {
13508 VALUE args[2];
13509 FilePathValue(src_io);
13510 args[0] = src_io;
13511 args[1] = INT2NUM(O_RDONLY|common_oflags);
13512 src_io = rb_class_new_instance(2, args, rb_cFile);
13513 stp->src = src_io;
13514 stp->close_src = 1;
13515 }
13516 RB_IO_POINTER(src_io, stp->src_fptr);
13517 rb_io_check_byte_readable(stp->src_fptr);
13518
13519 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13520 if (stat_ret < 0) {
13521 stp->syserr = "fstat";
13522 stp->error_no = errno;
13523 return Qnil;
13524 }
13525 }
13526
13527 if (dst_io == argf ||
13528 !(RB_TYPE_P(dst_io, T_FILE) ||
13529 RB_TYPE_P(dst_io, T_STRING) ||
13530 rb_respond_to(dst_io, rb_intern("to_path")))) {
13531 stp->dst_fptr = NULL;
13532 }
13533 else {
13534 int stat_ret;
13535 VALUE tmp_io = rb_io_check_io(dst_io);
13536 if (!NIL_P(tmp_io)) {
13537 dst_io = GetWriteIO(tmp_io);
13538 }
13539 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13540 VALUE args[3];
13541 FilePathValue(dst_io);
13542 args[0] = dst_io;
13543 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13544 args[2] = INT2FIX(0666);
13545 dst_io = rb_class_new_instance(3, args, rb_cFile);
13546 stp->dst = dst_io;
13547 stp->close_dst = 1;
13548 }
13549 else {
13550 dst_io = GetWriteIO(dst_io);
13551 stp->dst = dst_io;
13552 }
13553 RB_IO_POINTER(dst_io, stp->dst_fptr);
13554 rb_io_check_writable(stp->dst_fptr);
13555
13556 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13557 if (stat_ret < 0) {
13558 stp->syserr = "fstat";
13559 stp->error_no = errno;
13560 return Qnil;
13561 }
13562 }
13563
13564#ifdef O_BINARY
13565 if (stp->src_fptr)
13566 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13567#endif
13568 if (stp->dst_fptr)
13569 io_ascii8bit_binmode(stp->dst_fptr);
13570
13571 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13572 size_t len = stp->src_fptr->rbuf.len;
13573 VALUE str;
13574 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13575 len = (size_t)stp->copy_length;
13576 }
13577 str = rb_str_buf_new(len);
13578 rb_str_resize(str,len);
13579 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13580 if (stp->dst_fptr) { /* IO or filename */
13581 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13582 rb_sys_fail_on_write(stp->dst_fptr);
13583 }
13584 else /* others such as StringIO */
13585 rb_io_write(dst_io, str);
13586 rb_str_resize(str, 0);
13587 stp->total += len;
13588 if (stp->copy_length >= (rb_off_t)0)
13589 stp->copy_length -= len;
13590 }
13591
13592 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13593 rb_raise(rb_eIOError, "flush failed");
13594 }
13595
13596 if (stp->copy_length == 0)
13597 return Qnil;
13598
13599 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13600 return copy_stream_fallback(stp);
13601 }
13602
13603 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13604 return Qnil;
13605}
13606
13607static VALUE
13608copy_stream_finalize(VALUE arg)
13609{
13610 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13611
13612#ifdef HAVE_FCOPYFILE
13613 if (stp->copyfile_state) {
13614 copyfile_state_free(stp->copyfile_state);
13615 }
13616#endif
13617
13618 if (stp->close_src) {
13619 rb_io_close_m(stp->src);
13620 }
13621 if (stp->close_dst) {
13622 rb_io_close_m(stp->dst);
13623 }
13624 if (stp->syserr) {
13625 rb_syserr_fail(stp->error_no, stp->syserr);
13626 }
13627 if (stp->notimp) {
13628 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13629 }
13630 return Qnil;
13631}
13632
13633/*
13634 * call-seq:
13635 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13636 *
13637 * Copies from the given +src+ to the given +dst+,
13638 * returning the number of bytes copied.
13639 *
13640 * - The given +src+ must be one of the following:
13641 *
13642 * - The path to a readable file, from which source data is to be read.
13643 * - An \IO-like object, opened for reading and capable of responding
13644 * to method +:readpartial+ or method +:read+.
13645 *
13646 * - The given +dst+ must be one of the following:
13647 *
13648 * - The path to a writable file, to which data is to be written.
13649 * - An \IO-like object, opened for writing and capable of responding
13650 * to method +:write+.
13651 *
13652 * The examples here use file <tt>t.txt</tt> as source:
13653 *
13654 * File.read('t.txt')
13655 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13656 * File.read('t.txt').size # => 47
13657 *
13658 * If only arguments +src+ and +dst+ are given,
13659 * the entire source stream is copied:
13660 *
13661 * # Paths.
13662 * IO.copy_stream('t.txt', 't.tmp') # => 47
13663 *
13664 * # IOs (recall that a File is also an IO).
13665 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13666 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13667 * IO.copy_stream(src_io, dst_io) # => 47
13668 * src_io.close
13669 * dst_io.close
13670 *
13671 * With argument +src_length+ a non-negative integer,
13672 * no more than that many bytes are copied:
13673 *
13674 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13675 * File.read('t.tmp') # => "First line"
13676 *
13677 * With argument +src_offset+ also given,
13678 * the source stream is read beginning at that offset:
13679 *
13680 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13681 * IO.read('t.tmp') # => "Second line"
13682 *
13683 */
13684static VALUE
13685rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13686{
13687 VALUE src, dst, length, src_offset;
13688 struct copy_stream_struct st;
13689
13690 MEMZERO(&st, struct copy_stream_struct, 1);
13691
13692 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13693
13694 st.src = src;
13695 st.dst = dst;
13696
13697 st.src_fptr = NULL;
13698 st.dst_fptr = NULL;
13699
13700 if (NIL_P(length))
13701 st.copy_length = (rb_off_t)-1;
13702 else
13703 st.copy_length = NUM2OFFT(length);
13704
13705 if (NIL_P(src_offset))
13706 st.src_offset = (rb_off_t)-1;
13707 else
13708 st.src_offset = NUM2OFFT(src_offset);
13709
13710 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13711
13712 return OFFT2NUM(st.total);
13713}
13714
13715/*
13716 * call-seq:
13717 * external_encoding -> encoding or nil
13718 *
13719 * Returns the Encoding object that represents the encoding of the stream,
13720 * or +nil+ if the stream is in write mode and no encoding is specified.
13721 *
13722 * See {Encodings}[rdoc-ref:File@Encodings].
13723 *
13724 */
13725
13726static VALUE
13727rb_io_external_encoding(VALUE io)
13728{
13729 rb_io_t *fptr = rb_io_get_fptr(rb_io_taint_check(io));
13730
13731 if (fptr->encs.enc2) {
13732 return rb_enc_from_encoding(fptr->encs.enc2);
13733 }
13734 if (fptr->mode & FMODE_WRITABLE) {
13735 if (fptr->encs.enc)
13736 return rb_enc_from_encoding(fptr->encs.enc);
13737 return Qnil;
13738 }
13739 return rb_enc_from_encoding(io_read_encoding(fptr));
13740}
13741
13742/*
13743 * call-seq:
13744 * internal_encoding -> encoding or nil
13745 *
13746 * Returns the Encoding object that represents the encoding of the internal string,
13747 * if conversion is specified,
13748 * or +nil+ otherwise.
13749 *
13750 * See {Encodings}[rdoc-ref:File@Encodings].
13751 *
13752 */
13753
13754static VALUE
13755rb_io_internal_encoding(VALUE io)
13756{
13757 rb_io_t *fptr = rb_io_get_fptr(rb_io_taint_check(io));
13758
13759 if (!fptr->encs.enc2) return Qnil;
13760 return rb_enc_from_encoding(io_read_encoding(fptr));
13761}
13762
13763/*
13764 * call-seq:
13765 * set_encoding(ext_enc) -> self
13766 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13767 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13768 *
13769 * See {Encodings}[rdoc-ref:File@Encodings].
13770 *
13771 * Argument +ext_enc+, if given, must be an Encoding object
13772 * or a String with the encoding name;
13773 * it is assigned as the encoding for the stream.
13774 *
13775 * Argument +int_enc+, if given, must be an Encoding object
13776 * or a String with the encoding name;
13777 * it is assigned as the encoding for the internal string.
13778 *
13779 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13780 * containing two colon-separated encoding names;
13781 * corresponding Encoding objects are assigned as the external
13782 * and internal encodings for the stream.
13783 *
13784 * If the external encoding of a string is binary/ASCII-8BIT,
13785 * the internal encoding of the string is set to nil, since no
13786 * transcoding is needed.
13787 *
13788 * Optional keyword arguments +enc_opts+ specify
13789 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13790 *
13791 */
13792
13793static VALUE
13794rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13795{
13796 rb_io_t *fptr;
13797 VALUE v1, v2, opt;
13798
13799 if (!RB_TYPE_P(io, T_FILE)) {
13800 return forward(io, id_set_encoding, argc, argv);
13801 }
13802
13803 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13804 GetOpenFile(io, fptr);
13805 io_encoding_set(fptr, v1, v2, opt);
13806 return io;
13807}
13808
13809void
13810rb_stdio_set_default_encoding(void)
13811{
13812 VALUE val = Qnil;
13813
13814#ifdef _WIN32
13815 if (isatty(fileno(stdin))) {
13816 rb_encoding *external = rb_locale_encoding();
13817 rb_encoding *internal = rb_default_internal_encoding();
13818 if (!internal) internal = rb_default_external_encoding();
13819 io_encoding_set(RFILE(rb_stdin)->fptr,
13820 rb_enc_from_encoding(external),
13821 rb_enc_from_encoding(internal),
13822 Qnil);
13823 }
13824 else
13825#endif
13826 rb_io_set_encoding(1, &val, rb_stdin);
13827 rb_io_set_encoding(1, &val, rb_stdout);
13828 rb_io_set_encoding(1, &val, rb_stderr);
13829}
13830
13831static inline int
13832global_argf_p(VALUE arg)
13833{
13834 return arg == argf;
13835}
13836
13837typedef VALUE (*argf_encoding_func)(VALUE io);
13838
13839static VALUE
13840argf_encoding(VALUE argf, argf_encoding_func func)
13841{
13842 if (!RTEST(ARGF.current_file)) {
13843 return rb_enc_default_external();
13844 }
13845 return func(rb_io_check_io(ARGF.current_file));
13846}
13847
13848/*
13849 * call-seq:
13850 * ARGF.external_encoding -> encoding
13851 *
13852 * Returns the external encoding for files read from ARGF as an Encoding
13853 * object. The external encoding is the encoding of the text as stored in a
13854 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13855 * represent this text within Ruby.
13856 *
13857 * To set the external encoding use ARGF.set_encoding.
13858 *
13859 * For example:
13860 *
13861 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13862 *
13863 */
13864static VALUE
13865argf_external_encoding(VALUE argf)
13866{
13867 return argf_encoding(argf, rb_io_external_encoding);
13868}
13869
13870/*
13871 * call-seq:
13872 * ARGF.internal_encoding -> encoding
13873 *
13874 * Returns the internal encoding for strings read from ARGF as an
13875 * Encoding object.
13876 *
13877 * If ARGF.set_encoding has been called with two encoding names, the second
13878 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13879 * value is returned. Failing that, if a default external encoding was
13880 * specified on the command-line, that value is used. If the encoding is
13881 * unknown, +nil+ is returned.
13882 */
13883static VALUE
13884argf_internal_encoding(VALUE argf)
13885{
13886 return argf_encoding(argf, rb_io_internal_encoding);
13887}
13888
13889/*
13890 * call-seq:
13891 * ARGF.set_encoding(ext_enc) -> ARGF
13892 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13893 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13894 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13895 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13896 *
13897 * If single argument is specified, strings read from ARGF are tagged with
13898 * the encoding specified.
13899 *
13900 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13901 * the read string is converted from the first encoding (external encoding)
13902 * to the second encoding (internal encoding), then tagged with the second
13903 * encoding.
13904 *
13905 * If two arguments are specified, they must be encoding objects or encoding
13906 * names. Again, the first specifies the external encoding; the second
13907 * specifies the internal encoding.
13908 *
13909 * If the external encoding and the internal encoding are specified, the
13910 * optional Hash argument can be used to adjust the conversion process. The
13911 * structure of this hash is explained in the String#encode documentation.
13912 *
13913 * For example:
13914 *
13915 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13916 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13917 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13918 * # to UTF-8.
13919 */
13920static VALUE
13921argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13922{
13923 rb_io_t *fptr;
13924
13925 if (!next_argv()) {
13926 rb_raise(rb_eArgError, "no stream to set encoding");
13927 }
13928 rb_io_set_encoding(argc, argv, ARGF.current_file);
13929 GetOpenFile(ARGF.current_file, fptr);
13930 ARGF.encs = fptr->encs;
13931 RB_OBJ_WRITTEN(argf, Qundef, ARGF.encs.ecopts);
13932 return argf;
13933}
13934
13935/*
13936 * call-seq:
13937 * ARGF.tell -> Integer
13938 * ARGF.pos -> Integer
13939 *
13940 * Returns the current offset (in bytes) of the current file in ARGF.
13941 *
13942 * ARGF.pos #=> 0
13943 * ARGF.gets #=> "This is line one\n"
13944 * ARGF.pos #=> 17
13945 *
13946 */
13947static VALUE
13948argf_tell(VALUE argf)
13949{
13950 if (!next_argv()) {
13951 rb_raise(rb_eArgError, "no stream to tell");
13952 }
13953 ARGF_FORWARD(0, 0);
13954 return rb_io_tell(ARGF.current_file);
13955}
13956
13957/*
13958 * call-seq:
13959 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13960 *
13961 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13962 * the value of _whence_. See IO#seek for further details.
13963 */
13964static VALUE
13965argf_seek_m(int argc, VALUE *argv, VALUE argf)
13966{
13967 if (!next_argv()) {
13968 rb_raise(rb_eArgError, "no stream to seek");
13969 }
13970 ARGF_FORWARD(argc, argv);
13971 return rb_io_seek_m(argc, argv, ARGF.current_file);
13972}
13973
13974/*
13975 * call-seq:
13976 * ARGF.pos = position -> Integer
13977 *
13978 * Seeks to the position given by _position_ (in bytes) in ARGF.
13979 *
13980 * For example:
13981 *
13982 * ARGF.pos = 17
13983 * ARGF.gets #=> "This is line two\n"
13984 */
13985static VALUE
13986argf_set_pos(VALUE argf, VALUE offset)
13987{
13988 if (!next_argv()) {
13989 rb_raise(rb_eArgError, "no stream to set position");
13990 }
13991 ARGF_FORWARD(1, &offset);
13992 return rb_io_set_pos(ARGF.current_file, offset);
13993}
13994
13995/*
13996 * call-seq:
13997 * ARGF.rewind -> 0
13998 *
13999 * Positions the current file to the beginning of input, resetting
14000 * ARGF.lineno to zero.
14001 *
14002 * ARGF.readline #=> "This is line one\n"
14003 * ARGF.rewind #=> 0
14004 * ARGF.lineno #=> 0
14005 * ARGF.readline #=> "This is line one\n"
14006 */
14007static VALUE
14008argf_rewind(VALUE argf)
14009{
14010 VALUE ret;
14011 int old_lineno;
14012
14013 if (!next_argv()) {
14014 rb_raise(rb_eArgError, "no stream to rewind");
14015 }
14016 ARGF_FORWARD(0, 0);
14017 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
14018 ret = rb_io_rewind(ARGF.current_file);
14019 if (!global_argf_p(argf)) {
14020 ARGF.last_lineno = ARGF.lineno -= old_lineno;
14021 }
14022 return ret;
14023}
14024
14025/*
14026 * call-seq:
14027 * ARGF.fileno -> integer
14028 * ARGF.to_i -> integer
14029 *
14030 * Returns an integer representing the numeric file descriptor for
14031 * the current file. Raises an ArgumentError if there isn't a current file.
14032 *
14033 * ARGF.fileno #=> 3
14034 */
14035static VALUE
14036argf_fileno(VALUE argf)
14037{
14038 if (!next_argv()) {
14039 rb_raise(rb_eArgError, "no stream");
14040 }
14041 ARGF_FORWARD(0, 0);
14042 return rb_io_fileno(ARGF.current_file);
14043}
14044
14045/*
14046 * call-seq:
14047 * ARGF.to_io -> IO
14048 *
14049 * Returns an IO object representing the current file. This will be a
14050 * File object unless the current file is a stream such as STDIN.
14051 *
14052 * For example:
14053 *
14054 * ARGF.to_io #=> #<File:glark.txt>
14055 * ARGF.to_io #=> #<IO:<STDIN>>
14056 */
14057static VALUE
14058argf_to_io(VALUE argf)
14059{
14060 next_argv();
14061 ARGF_FORWARD(0, 0);
14062 return ARGF.current_file;
14063}
14064
14065/*
14066 * call-seq:
14067 * ARGF.eof? -> true or false
14068 * ARGF.eof -> true or false
14069 *
14070 * Returns true if the current file in ARGF is at end of file, i.e. it has
14071 * no data to read. The stream must be opened for reading or an IOError
14072 * will be raised.
14073 *
14074 * $ echo "eof" | ruby argf.rb
14075 *
14076 * ARGF.eof? #=> false
14077 * 3.times { ARGF.readchar }
14078 * ARGF.eof? #=> false
14079 * ARGF.readchar #=> "\n"
14080 * ARGF.eof? #=> true
14081 */
14082
14083static VALUE
14084argf_eof(VALUE argf)
14085{
14086 next_argv();
14087 if (RTEST(ARGF.current_file)) {
14088 if (ARGF.init_p == 0) return Qtrue;
14089 next_argv();
14090 ARGF_FORWARD(0, 0);
14091 if (rb_io_eof(ARGF.current_file)) {
14092 return Qtrue;
14093 }
14094 }
14095 return Qfalse;
14096}
14097
14098/*
14099 * call-seq:
14100 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
14101 *
14102 * Reads _length_ bytes from ARGF. The files named on the command line
14103 * are concatenated and treated as a single file by this method, so when
14104 * called without arguments the contents of this pseudo file are returned in
14105 * their entirety.
14106 *
14107 * _length_ must be a non-negative integer or +nil+.
14108 *
14109 * If _length_ is a positive integer, +read+ tries to read
14110 * _length_ bytes without any conversion (binary mode).
14111 * It returns +nil+ if an EOF is encountered before anything can be read.
14112 * Fewer than _length_ bytes are returned if an EOF is encountered during
14113 * the read.
14114 * In the case of an integer _length_, the resulting string is always
14115 * in ASCII-8BIT encoding.
14116 *
14117 * If _length_ is omitted or is +nil+, it reads until EOF
14118 * and the encoding conversion is applied, if applicable.
14119 * A string is returned even if EOF is encountered before any data is read.
14120 *
14121 * If _length_ is zero, it returns an empty string (<code>""</code>).
14122 *
14123 * If the optional _outbuf_ argument is present,
14124 * it must reference a String, which will receive the data.
14125 * The _outbuf_ will contain only the received data after the method call
14126 * even if it is not empty at the beginning.
14127 *
14128 * For example:
14129 *
14130 * $ echo "small" > small.txt
14131 * $ echo "large" > large.txt
14132 * $ ./glark.rb small.txt large.txt
14133 *
14134 * ARGF.read #=> "small\nlarge"
14135 * ARGF.read(200) #=> "small\nlarge"
14136 * ARGF.read(2) #=> "sm"
14137 * ARGF.read(0) #=> ""
14138 *
14139 * Note that this method behaves like the fread() function in C.
14140 * This means it retries to invoke read(2) system calls to read data
14141 * with the specified length.
14142 * If you need the behavior like a single read(2) system call,
14143 * consider ARGF#readpartial or ARGF#read_nonblock.
14144 */
14145
14146static VALUE
14147argf_read(int argc, VALUE *argv, VALUE argf)
14148{
14149 VALUE tmp, str, length;
14150 rb_len_t len = 0;
14151
14152 rb_scan_args(argc, argv, "02", &length, &str);
14153 if (!NIL_P(length)) {
14154 len = NUM2LEN(argv[0]);
14155 }
14156 if (!NIL_P(str)) {
14157 StringValue(str);
14158 rb_str_resize(str,0);
14159 argv[1] = Qnil;
14160 }
14161
14162 retry:
14163 if (!next_argv()) {
14164 return str;
14165 }
14166 if (ARGF_GENERIC_INPUT_P()) {
14167 tmp = argf_forward(argc, argv, argf);
14168 }
14169 else {
14170 tmp = io_read(argc, argv, ARGF.current_file);
14171 }
14172 if (NIL_P(str)) str = tmp;
14173 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
14174 if (NIL_P(tmp) || NIL_P(length)) {
14175 if (ARGF.next_p != -1) {
14176 argf_close(argf);
14177 ARGF.next_p = 1;
14178 goto retry;
14179 }
14180 }
14181 else if (argc >= 1) {
14182 rb_len_t slen = RSTRING_LEN(str);
14183 if (slen < len) {
14184 argv[0] = LEN2NUM(len - slen);
14185 goto retry;
14186 }
14187 }
14188 return str;
14189}
14190
14192 int argc;
14193 VALUE *argv;
14194 VALUE argf;
14195};
14196
14197static VALUE
14198argf_forward_call(VALUE arg)
14199{
14200 struct argf_call_arg *p = (struct argf_call_arg *)arg;
14201 argf_forward(p->argc, p->argv, p->argf);
14202 return Qnil;
14203}
14204
14205static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
14206 int nonblock);
14207
14208/*
14209 * call-seq:
14210 * ARGF.readpartial(maxlen) -> string
14211 * ARGF.readpartial(maxlen, outbuf) -> outbuf
14212 *
14213 * Reads at most _maxlen_ bytes from the ARGF stream.
14214 *
14215 * If the optional _outbuf_ argument is present,
14216 * it must reference a String, which will receive the data.
14217 * The _outbuf_ will contain only the received data after the method call
14218 * even if it is not empty at the beginning.
14219 *
14220 * It raises EOFError on end of ARGF stream.
14221 * Since ARGF stream is a concatenation of multiple files,
14222 * internally EOF is occur for each file.
14223 * ARGF.readpartial returns empty strings for EOFs except the last one and
14224 * raises EOFError for the last one.
14225 *
14226 */
14227
14228static VALUE
14229argf_readpartial(int argc, VALUE *argv, VALUE argf)
14230{
14231 return argf_getpartial(argc, argv, argf, Qnil, 0);
14232}
14233
14234/*
14235 * call-seq:
14236 * ARGF.read_nonblock(maxlen[, options]) -> string
14237 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14238 *
14239 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14240 */
14241
14242static VALUE
14243argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14244{
14245 VALUE opts;
14246
14247 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14248
14249 if (!NIL_P(opts))
14250 argc--;
14251
14252 return argf_getpartial(argc, argv, argf, opts, 1);
14253}
14254
14255static VALUE
14256argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14257{
14258 VALUE tmp, str, length;
14259 int no_exception;
14260
14261 rb_scan_args(argc, argv, "11", &length, &str);
14262 if (!NIL_P(str)) {
14263 StringValue(str);
14264 argv[1] = str;
14265 }
14266 no_exception = no_exception_p(opts);
14267
14268 if (!next_argv()) {
14269 if (!NIL_P(str)) {
14270 rb_str_resize(str, 0);
14271 }
14272 rb_eof_error();
14273 }
14274 if (ARGF_GENERIC_INPUT_P()) {
14275 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14276 struct argf_call_arg arg;
14277 arg.argc = argc;
14278 arg.argv = argv;
14279 arg.argf = argf;
14280 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14281 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14282 }
14283 else {
14284 tmp = io_getpartial(ARGF.current_file, length, str, no_exception, nonblock);
14285 }
14286 if (NIL_P(tmp)) {
14287 if (ARGF.next_p == -1) {
14288 return io_nonblock_eof(no_exception);
14289 }
14290 argf_close(argf);
14291 ARGF.next_p = 1;
14292 if (RARRAY_LEN(ARGF.argv) == 0) {
14293 return io_nonblock_eof(no_exception);
14294 }
14295 if (NIL_P(str))
14296 str = rb_str_new(NULL, 0);
14297 return str;
14298 }
14299 return tmp;
14300}
14301
14302/*
14303 * call-seq:
14304 * ARGF.getc -> String or nil
14305 *
14306 * Reads the next character from ARGF and returns it as a String. Returns
14307 * +nil+ at the end of the stream.
14308 *
14309 * ARGF treats the files named on the command line as a single file created
14310 * by concatenating their contents. After returning the last character of the
14311 * first file, it returns the first character of the second file, and so on.
14312 *
14313 * For example:
14314 *
14315 * $ echo "foo" > file
14316 * $ ruby argf.rb file
14317 *
14318 * ARGF.getc #=> "f"
14319 * ARGF.getc #=> "o"
14320 * ARGF.getc #=> "o"
14321 * ARGF.getc #=> "\n"
14322 * ARGF.getc #=> nil
14323 * ARGF.getc #=> nil
14324 */
14325static VALUE
14326argf_getc(VALUE argf)
14327{
14328 VALUE ch;
14329
14330 retry:
14331 if (!next_argv()) return Qnil;
14332 if (ARGF_GENERIC_INPUT_P()) {
14333 ch = forward_current(rb_intern("getc"), 0, 0);
14334 }
14335 else {
14336 ch = rb_io_getc(ARGF.current_file);
14337 }
14338 if (NIL_P(ch) && ARGF.next_p != -1) {
14339 argf_close(argf);
14340 ARGF.next_p = 1;
14341 goto retry;
14342 }
14343
14344 return ch;
14345}
14346
14347/*
14348 * call-seq:
14349 * ARGF.getbyte -> Integer or nil
14350 *
14351 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14352 * the end of the stream.
14353 *
14354 * For example:
14355 *
14356 * $ echo "foo" > file
14357 * $ ruby argf.rb file
14358 *
14359 * ARGF.getbyte #=> 102
14360 * ARGF.getbyte #=> 111
14361 * ARGF.getbyte #=> 111
14362 * ARGF.getbyte #=> 10
14363 * ARGF.getbyte #=> nil
14364 */
14365static VALUE
14366argf_getbyte(VALUE argf)
14367{
14368 VALUE ch;
14369
14370 retry:
14371 if (!next_argv()) return Qnil;
14372 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14373 ch = forward_current(rb_intern("getbyte"), 0, 0);
14374 }
14375 else {
14376 ch = rb_io_getbyte(ARGF.current_file);
14377 }
14378 if (NIL_P(ch) && ARGF.next_p != -1) {
14379 argf_close(argf);
14380 ARGF.next_p = 1;
14381 goto retry;
14382 }
14383
14384 return ch;
14385}
14386
14387/*
14388 * call-seq:
14389 * ARGF.readchar -> String or nil
14390 *
14391 * Reads the next character from ARGF and returns it as a String. Raises
14392 * an EOFError after the last character of the last file has been read.
14393 *
14394 * For example:
14395 *
14396 * $ echo "foo" > file
14397 * $ ruby argf.rb file
14398 *
14399 * ARGF.readchar #=> "f"
14400 * ARGF.readchar #=> "o"
14401 * ARGF.readchar #=> "o"
14402 * ARGF.readchar #=> "\n"
14403 * ARGF.readchar #=> end of file reached (EOFError)
14404 */
14405static VALUE
14406argf_readchar(VALUE argf)
14407{
14408 VALUE ch;
14409
14410 retry:
14411 if (!next_argv()) rb_eof_error();
14412 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14413 ch = forward_current(rb_intern("getc"), 0, 0);
14414 }
14415 else {
14416 ch = rb_io_getc(ARGF.current_file);
14417 }
14418 if (NIL_P(ch) && ARGF.next_p != -1) {
14419 argf_close(argf);
14420 ARGF.next_p = 1;
14421 goto retry;
14422 }
14423
14424 return ch;
14425}
14426
14427/*
14428 * call-seq:
14429 * ARGF.readbyte -> Integer
14430 *
14431 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14432 * an EOFError after the last byte of the last file has been read.
14433 *
14434 * For example:
14435 *
14436 * $ echo "foo" > file
14437 * $ ruby argf.rb file
14438 *
14439 * ARGF.readbyte #=> 102
14440 * ARGF.readbyte #=> 111
14441 * ARGF.readbyte #=> 111
14442 * ARGF.readbyte #=> 10
14443 * ARGF.readbyte #=> end of file reached (EOFError)
14444 */
14445static VALUE
14446argf_readbyte(VALUE argf)
14447{
14448 VALUE c;
14449
14450 NEXT_ARGF_FORWARD(0, 0);
14451 c = argf_getbyte(argf);
14452 if (NIL_P(c)) {
14453 rb_eof_error();
14454 }
14455 return c;
14456}
14457
14458#define FOREACH_ARGF() while (next_argv())
14459
14460static VALUE
14461argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14462{
14463 const VALUE current = ARGF.current_file;
14464 rb_yield_values2(argc, argv);
14465 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14467 }
14468 return Qnil;
14469}
14470
14471#define ARGF_block_call(mid, argc, argv, func, argf) \
14472 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14473 func, argf, rb_keyword_given_p())
14474
14475static void
14476argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14477{
14478 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14479 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14480}
14481
14482static VALUE
14483argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14484{
14485 if (!global_argf_p(argf)) {
14486 ARGF.last_lineno = ++ARGF.lineno;
14487 }
14488 return argf_block_call_i(i, argf, argc, argv, blockarg);
14489}
14490
14491static void
14492argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14493{
14494 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14495 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14496}
14497
14498/*
14499 * call-seq:
14500 * ARGF.each(sep=$/) {|line| block } -> ARGF
14501 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14502 * ARGF.each(...) -> an_enumerator
14503 *
14504 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14505 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14506 * ARGF.each_line(...) -> an_enumerator
14507 *
14508 * Returns an enumerator which iterates over each line (separated by _sep_,
14509 * which defaults to your platform's newline character) of each file in
14510 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14511 * block, otherwise an enumerator is returned.
14512 * The optional _limit_ argument is an Integer specifying the maximum
14513 * length of each line; longer lines will be split according to this limit.
14514 *
14515 * This method allows you to treat the files supplied on the command line as
14516 * a single file consisting of the concatenation of each named file. After
14517 * the last line of the first file has been returned, the first line of the
14518 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14519 * used to determine the filename of the current line and line number of the
14520 * whole input, respectively.
14521 *
14522 * For example, the following code prints out each line of each named file
14523 * prefixed with its line number, displaying the filename once per file:
14524 *
14525 * ARGF.each_line do |line|
14526 * puts ARGF.filename if ARGF.file.lineno == 1
14527 * puts "#{ARGF.file.lineno}: #{line}"
14528 * end
14529 *
14530 * While the following code prints only the first file's name at first, and
14531 * the contents with line number counted through all named files.
14532 *
14533 * ARGF.each_line do |line|
14534 * puts ARGF.filename if ARGF.lineno == 1
14535 * puts "#{ARGF.lineno}: #{line}"
14536 * end
14537 */
14538static VALUE
14539argf_each_line(int argc, VALUE *argv, VALUE argf)
14540{
14541 RETURN_ENUMERATOR(argf, argc, argv);
14542 FOREACH_ARGF() {
14543 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14544 }
14545 return argf;
14546}
14547
14548/*
14549 * call-seq:
14550 * ARGF.each_byte {|byte| block } -> ARGF
14551 * ARGF.each_byte -> an_enumerator
14552 *
14553 * Iterates over each byte of each file in +ARGV+.
14554 * A byte is returned as an Integer in the range 0..255.
14555 *
14556 * This method allows you to treat the files supplied on the command line as
14557 * a single file consisting of the concatenation of each named file. After
14558 * the last byte of the first file has been returned, the first byte of the
14559 * second file is returned. The ARGF.filename method can be used to
14560 * determine the filename of the current byte.
14561 *
14562 * If no block is given, an enumerator is returned instead.
14563 *
14564 * For example:
14565 *
14566 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14567 *
14568 */
14569static VALUE
14570argf_each_byte(VALUE argf)
14571{
14572 RETURN_ENUMERATOR(argf, 0, 0);
14573 FOREACH_ARGF() {
14574 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14575 }
14576 return argf;
14577}
14578
14579/*
14580 * call-seq:
14581 * ARGF.each_char {|char| block } -> ARGF
14582 * ARGF.each_char -> an_enumerator
14583 *
14584 * Iterates over each character of each file in ARGF.
14585 *
14586 * This method allows you to treat the files supplied on the command line as
14587 * a single file consisting of the concatenation of each named file. After
14588 * the last character of the first file has been returned, the first
14589 * character of the second file is returned. The ARGF.filename method can
14590 * be used to determine the name of the file in which the current character
14591 * appears.
14592 *
14593 * If no block is given, an enumerator is returned instead.
14594 */
14595static VALUE
14596argf_each_char(VALUE argf)
14597{
14598 RETURN_ENUMERATOR(argf, 0, 0);
14599 FOREACH_ARGF() {
14600 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14601 }
14602 return argf;
14603}
14604
14605/*
14606 * call-seq:
14607 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14608 * ARGF.each_codepoint -> an_enumerator
14609 *
14610 * Iterates over each codepoint of each file in ARGF.
14611 *
14612 * This method allows you to treat the files supplied on the command line as
14613 * a single file consisting of the concatenation of each named file. After
14614 * the last codepoint of the first file has been returned, the first
14615 * codepoint of the second file is returned. The ARGF.filename method can
14616 * be used to determine the name of the file in which the current codepoint
14617 * appears.
14618 *
14619 * If no block is given, an enumerator is returned instead.
14620 */
14621static VALUE
14622argf_each_codepoint(VALUE argf)
14623{
14624 RETURN_ENUMERATOR(argf, 0, 0);
14625 FOREACH_ARGF() {
14626 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14627 }
14628 return argf;
14629}
14630
14631/*
14632 * call-seq:
14633 * ARGF.filename -> String
14634 * ARGF.path -> String
14635 *
14636 * Returns the current filename. "-" is returned when the current file is
14637 * STDIN.
14638 *
14639 * For example:
14640 *
14641 * $ echo "foo" > foo
14642 * $ echo "bar" > bar
14643 * $ echo "glark" > glark
14644 *
14645 * $ ruby argf.rb foo bar glark
14646 *
14647 * ARGF.filename #=> "foo"
14648 * ARGF.read(5) #=> "foo\nb"
14649 * ARGF.filename #=> "bar"
14650 * ARGF.skip
14651 * ARGF.filename #=> "glark"
14652 */
14653static VALUE
14654argf_filename(VALUE argf)
14655{
14656 next_argv();
14657 return ARGF.filename;
14658}
14659
14660static VALUE
14661argf_filename_getter(ID id, VALUE *var)
14662{
14663 return argf_filename(*var);
14664}
14665
14666/*
14667 * call-seq:
14668 * ARGF.file -> IO or File object
14669 *
14670 * Returns the current file as an IO or File object.
14671 * <code>$stdin</code> is returned when the current file is STDIN.
14672 *
14673 * For example:
14674 *
14675 * $ echo "foo" > foo
14676 * $ echo "bar" > bar
14677 *
14678 * $ ruby argf.rb foo bar
14679 *
14680 * ARGF.file #=> #<File:foo>
14681 * ARGF.read(5) #=> "foo\nb"
14682 * ARGF.file #=> #<File:bar>
14683 */
14684static VALUE
14685argf_file(VALUE argf)
14686{
14687 next_argv();
14688 return ARGF.current_file;
14689}
14690
14691/*
14692 * call-seq:
14693 * ARGF.binmode -> ARGF
14694 *
14695 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14696 * be reset to non-binary mode. This option has the following effects:
14697 *
14698 * * Newline conversion is disabled.
14699 * * Encoding conversion is disabled.
14700 * * Content is treated as ASCII-8BIT.
14701 */
14702static VALUE
14703argf_binmode_m(VALUE argf)
14704{
14705 ARGF.binmode = 1;
14706 next_argv();
14707 ARGF_FORWARD(0, 0);
14708 rb_io_ascii8bit_binmode(ARGF.current_file);
14709 return argf;
14710}
14711
14712/*
14713 * call-seq:
14714 * ARGF.binmode? -> true or false
14715 *
14716 * Returns true if ARGF is being read in binary mode; false otherwise.
14717 * To enable binary mode use ARGF.binmode.
14718 *
14719 * For example:
14720 *
14721 * ARGF.binmode? #=> false
14722 * ARGF.binmode
14723 * ARGF.binmode? #=> true
14724 */
14725static VALUE
14726argf_binmode_p(VALUE argf)
14727{
14728 return RBOOL(ARGF.binmode);
14729}
14730
14731/*
14732 * call-seq:
14733 * ARGF.skip -> ARGF
14734 *
14735 * Sets the current file to the next file in ARGV. If there aren't any more
14736 * files it has no effect.
14737 *
14738 * For example:
14739 *
14740 * $ ruby argf.rb foo bar
14741 * ARGF.filename #=> "foo"
14742 * ARGF.skip
14743 * ARGF.filename #=> "bar"
14744 */
14745static VALUE
14746argf_skip(VALUE argf)
14747{
14748 if (ARGF.init_p && ARGF.next_p == 0) {
14749 argf_close(argf);
14750 ARGF.next_p = 1;
14751 }
14752 return argf;
14753}
14754
14755/*
14756 * call-seq:
14757 * ARGF.close -> ARGF
14758 *
14759 * Closes the current file and skips to the next file in ARGV. If there are
14760 * no more files to open, just closes the current file. STDIN will not be
14761 * closed.
14762 *
14763 * For example:
14764 *
14765 * $ ruby argf.rb foo bar
14766 *
14767 * ARGF.filename #=> "foo"
14768 * ARGF.close
14769 * ARGF.filename #=> "bar"
14770 * ARGF.close
14771 */
14772static VALUE
14773argf_close_m(VALUE argf)
14774{
14775 next_argv();
14776 argf_close(argf);
14777 if (ARGF.next_p != -1) {
14778 ARGF.next_p = 1;
14779 }
14780 ARGF.lineno = 0;
14781 return argf;
14782}
14783
14784/*
14785 * call-seq:
14786 * ARGF.closed? -> true or false
14787 *
14788 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14789 * ARGF.close to actually close the current file.
14790 */
14791static VALUE
14792argf_closed(VALUE argf)
14793{
14794 next_argv();
14795 ARGF_FORWARD(0, 0);
14796 return rb_io_closed_p(ARGF.current_file);
14797}
14798
14799/*
14800 * call-seq:
14801 * ARGF.to_s -> String
14802 *
14803 * Returns "ARGF".
14804 */
14805static VALUE
14806argf_to_s(VALUE argf)
14807{
14808 return rb_str_new2("ARGF");
14809}
14810
14811/*
14812 * call-seq:
14813 * ARGF.inplace_mode -> String
14814 *
14815 * Returns the file extension appended to the names of backup copies of
14816 * modified files under in-place edit mode. This value can be set using
14817 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14818 */
14819static VALUE
14820argf_inplace_mode_get(VALUE argf)
14821{
14822 if (!ARGF.inplace) return Qnil;
14823 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14824 return rb_str_dup(ARGF.inplace);
14825}
14826
14827static VALUE
14828opt_i_get(ID id, VALUE *var)
14829{
14830 return argf_inplace_mode_get(*var);
14831}
14832
14833/*
14834 * call-seq:
14835 * ARGF.inplace_mode = ext -> ARGF
14836 *
14837 * Sets the filename extension for in-place editing mode to the given String.
14838 * The backup copy of each file being edited has this value appended to its
14839 * filename.
14840 *
14841 * For example:
14842 *
14843 * $ ruby argf.rb file.txt
14844 *
14845 * ARGF.inplace_mode = '.bak'
14846 * ARGF.each_line do |line|
14847 * print line.sub("foo","bar")
14848 * end
14849 *
14850 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14851 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14852 * "bar".
14853 */
14854static VALUE
14855argf_inplace_mode_set(VALUE argf, VALUE val)
14856{
14857 if (!RTEST(val)) {
14858 ARGF.inplace = Qfalse;
14859 }
14860 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14861 ARGF.inplace = Qnil;
14862 }
14863 else {
14864 ARGF_SET(inplace, rb_str_new_frozen(val));
14865 }
14866 return argf;
14867}
14868
14869static void
14870opt_i_set(VALUE val, ID id, VALUE *var)
14871{
14872 argf_inplace_mode_set(*var, val);
14873}
14874
14875void
14876ruby_set_inplace_mode(const char *suffix)
14877{
14878 ARGF_SET(inplace, !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix)));
14879}
14880
14881/*
14882 * call-seq:
14883 * ARGF.argv -> ARGV
14884 *
14885 * Returns the +ARGV+ array, which contains the arguments passed to your
14886 * script, one per element.
14887 *
14888 * For example:
14889 *
14890 * $ ruby argf.rb -v glark.txt
14891 *
14892 * ARGF.argv #=> ["-v", "glark.txt"]
14893 *
14894 */
14895static VALUE
14896argf_argv(VALUE argf)
14897{
14898 return ARGF.argv;
14899}
14900
14901static VALUE
14902argf_argv_getter(ID id, VALUE *var)
14903{
14904 return argf_argv(*var);
14905}
14906
14907VALUE
14909{
14910 return ARGF.argv;
14911}
14912
14913/*
14914 * call-seq:
14915 * ARGF.to_write_io -> io
14916 *
14917 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14918 * enabled.
14919 */
14920static VALUE
14921argf_write_io(VALUE argf)
14922{
14923 if (!RTEST(ARGF.current_file)) {
14924 rb_raise(rb_eIOError, "not opened for writing");
14925 }
14926 return GetWriteIO(ARGF.current_file);
14927}
14928
14929/*
14930 * call-seq:
14931 * ARGF.write(*objects) -> integer
14932 *
14933 * Writes each of the given +objects+ if inplace mode.
14934 */
14935static VALUE
14936argf_write(int argc, VALUE *argv, VALUE argf)
14937{
14938 return rb_io_writev(argf_write_io(argf), argc, argv);
14939}
14940
14941void
14942rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14943{
14944 rb_readwrite_syserr_fail(waiting, errno, mesg);
14945}
14946
14947void
14948rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14949{
14950 VALUE arg, c = Qnil;
14951 arg = mesg ? rb_str_new2(mesg) : Qnil;
14952 switch (waiting) {
14953 case RB_IO_WAIT_WRITABLE:
14954 switch (n) {
14955 case EAGAIN:
14956 c = rb_eEAGAINWaitWritable;
14957 break;
14958#if EAGAIN != EWOULDBLOCK
14959 case EWOULDBLOCK:
14960 c = rb_eEWOULDBLOCKWaitWritable;
14961 break;
14962#endif
14963 case EINPROGRESS:
14964 c = rb_eEINPROGRESSWaitWritable;
14965 break;
14966 default:
14968 }
14969 break;
14970 case RB_IO_WAIT_READABLE:
14971 switch (n) {
14972 case EAGAIN:
14973 c = rb_eEAGAINWaitReadable;
14974 break;
14975#if EAGAIN != EWOULDBLOCK
14976 case EWOULDBLOCK:
14977 c = rb_eEWOULDBLOCKWaitReadable;
14978 break;
14979#endif
14980 case EINPROGRESS:
14981 c = rb_eEINPROGRESSWaitReadable;
14982 break;
14983 default:
14985 }
14986 break;
14987 default:
14988 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14989 }
14991}
14992
14993static VALUE
14994get_LAST_READ_LINE(ID _x, VALUE *_y)
14995{
14996 return rb_lastline_get();
14997}
14998
14999static void
15000set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
15001{
15002 rb_lastline_set(val);
15003}
15004
15005/*
15006 * Document-class: IOError
15007 *
15008 * Raised when an IO operation fails.
15009 *
15010 * File.open("/etc/hosts") {|f| f << "example"}
15011 * #=> IOError: not opened for writing
15012 *
15013 * File.open("/etc/hosts") {|f| f.close; f.read }
15014 * #=> IOError: closed stream
15015 *
15016 * Note that some IO failures raise <code>SystemCallError</code>s
15017 * and these are not subclasses of IOError:
15018 *
15019 * File.open("does/not/exist")
15020 * #=> Errno::ENOENT: No such file or directory - does/not/exist
15021 */
15022
15023/*
15024 * Document-class: EOFError
15025 *
15026 * Raised by some IO operations when reaching the end of file. Many IO
15027 * methods exist in two forms,
15028 *
15029 * one that returns +nil+ when the end of file is reached, the other
15030 * raises EOFError.
15031 *
15032 * EOFError is a subclass of IOError.
15033 *
15034 * file = File.open("/etc/hosts")
15035 * file.read
15036 * file.gets #=> nil
15037 * file.readline #=> EOFError: end of file reached
15038 * file.close
15039 */
15040
15041/*
15042 * Document-class: ARGF
15043 *
15044 * == \ARGF and +ARGV+
15045 *
15046 * The \ARGF object works with the array at global variable +ARGV+
15047 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
15048 *
15049 * - **ARGV** may be thought of as the <b>argument vector</b> array.
15050 *
15051 * Initially, it contains the command-line arguments and options
15052 * that are passed to the Ruby program;
15053 * the program can modify that array as it likes.
15054 *
15055 * - **ARGF** may be thought of as the <b>argument files</b> object.
15056 *
15057 * It can access file streams and/or the <tt>$stdin</tt> stream,
15058 * based on what it finds in +ARGV+.
15059 * This provides a convenient way for the command line
15060 * to specify streams for a Ruby program to read.
15061 *
15062 * == Reading
15063 *
15064 * \ARGF may read from _source_ streams,
15065 * which at any particular time are determined by the content of +ARGV+.
15066 *
15067 * === Simplest Case
15068 *
15069 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
15070 * the source is <tt>$stdin</tt>:
15071 *
15072 * - \File +t.rb+:
15073 *
15074 * p ['ARGV', ARGV]
15075 * p ['ARGF.read', ARGF.read]
15076 *
15077 * - Commands and outputs
15078 * (see below for the content of files +foo.txt+ and +bar.txt+):
15079 *
15080 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
15081 * ["ARGV", []]
15082 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15083 *
15084 * $ cat foo.txt bar.txt | ruby t.rb
15085 * ["ARGV", []]
15086 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
15087 *
15088 * === About the Examples
15089 *
15090 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
15091 *
15092 * $ cat foo.txt
15093 * Foo 0
15094 * Foo 1
15095 * $ cat bar.txt
15096 * Bar 0
15097 * Bar 1
15098 * Bar 2
15099 * Bar 3
15100 *
15101 * === Sources in +ARGV+
15102 *
15103 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
15104 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
15105 * the sources are found in +ARGV+.
15106 *
15107 * \ARGF assumes that each element in array +ARGV+ is a potential source,
15108 * and is one of:
15109 *
15110 * - The string path to a file that may be opened as a stream.
15111 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
15112 *
15113 * Each element that is _not_ one of these
15114 * should be removed from +ARGV+ before \ARGF accesses that source.
15115 *
15116 * In the following example:
15117 *
15118 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
15119 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
15120 *
15121 * Example:
15122 *
15123 * - \File +t.rb+:
15124 *
15125 * # Print arguments (and options, if any) found on command line.
15126 * p ['ARGV', ARGV]
15127 *
15128 * - Command and output:
15129 *
15130 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
15131 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
15132 *
15133 * \ARGF's stream access considers the elements of +ARGV+, left to right:
15134 *
15135 * - \File +t.rb+:
15136 *
15137 * p "ARGV: #{ARGV}"
15138 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
15139 *
15140 * - Command and output:
15141 *
15142 * $ ruby t.rb foo.txt bar.txt
15143 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15144 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15145 *
15146 * Because the value at +ARGV+ is an ordinary array,
15147 * you can manipulate it to control which sources \ARGF considers:
15148 *
15149 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
15150 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
15151 *
15152 * Each element in +ARGV+ is removed when its corresponding source is accessed;
15153 * when all sources have been accessed, the array is empty:
15154 *
15155 * - \File +t.rb+:
15156 *
15157 * until ARGV.empty? && ARGF.eof?
15158 * p "ARGV: #{ARGV}"
15159 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
15160 * end
15161 *
15162 * - Command and output:
15163 *
15164 * $ ruby t.rb foo.txt bar.txt
15165 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15166 * "Line: Foo 0\n"
15167 * "ARGV: [\"bar.txt\"]"
15168 * "Line: Foo 1\n"
15169 * "ARGV: [\"bar.txt\"]"
15170 * "Line: Bar 0\n"
15171 * "ARGV: []"
15172 * "Line: Bar 1\n"
15173 * "ARGV: []"
15174 * "Line: Bar 2\n"
15175 * "ARGV: []"
15176 * "Line: Bar 3\n"
15177 *
15178 * ==== Filepaths in +ARGV+
15179 *
15180 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
15181 *
15182 * This program prints what it reads from files at the paths specified
15183 * on the command line:
15184 *
15185 * - \File +t.rb+:
15186 *
15187 * p ['ARGV', ARGV]
15188 * # Read and print all content from the specified sources.
15189 * p ['ARGF.read', ARGF.read]
15190 *
15191 * - Command and output:
15192 *
15193 * $ ruby t.rb foo.txt bar.txt
15194 * ["ARGV", [foo.txt, bar.txt]
15195 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
15196 *
15197 * ==== Specifying <tt>$stdin</tt> in +ARGV+
15198 *
15199 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
15200 *
15201 * - \File +t.rb+:
15202 *
15203 * p ['ARGV', ARGV]
15204 * p ['ARGF.read', ARGF.read]
15205 *
15206 * - Command and output:
15207 *
15208 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
15209 * ["ARGV", ["-"]]
15210 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15211 *
15212 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored.
15213 *
15214 * - Command and output:
15215 *
15216 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
15217 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15218 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15219 *
15220 * ==== Mixtures and Repetitions in +ARGV+
15221 *
15222 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
15223 * and character <tt>'-'</tt>, including repetitions.
15224 *
15225 * ==== Modifications to +ARGV+
15226 *
15227 * The running Ruby program may make any modifications to the +ARGV+ array;
15228 * the current value of +ARGV+ affects \ARGF reading.
15229 *
15230 * ==== Empty +ARGV+
15231 *
15232 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15233 * or raises an exception, depending on the specific method.
15234 *
15235 * === More Read Methods
15236 *
15237 * As seen above, method ARGF#read reads the content of all sources
15238 * into a single string.
15239 * Other \ARGF methods provide other ways to access that content;
15240 * these include:
15241 *
15242 * - Byte access: #each_byte, #getbyte, #readbyte.
15243 * - Character access: #each_char, #getc, #readchar.
15244 * - Codepoint access: #each_codepoint.
15245 * - Line access: #each_line, #gets, #readline, #readlines.
15246 * - Source access: #read, #read_nonblock, #readpartial.
15247 *
15248 * === About \Enumerable
15249 *
15250 * \ARGF includes module Enumerable.
15251 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15252 *
15253 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15254 * _not_ from +ARGV+;
15255 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15256 * not an array of the strings from +ARGV+:
15257 *
15258 * - \File +t.rb+:
15259 *
15260 * p ['ARGV', ARGV]
15261 * p ['ARGF.entries', ARGF.entries]
15262 *
15263 * - Command and output:
15264 *
15265 * $ ruby t.rb foo.txt bar.txt
15266 * ["ARGV", ["foo.txt", "bar.txt"]]
15267 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15268 *
15269 * == Writing
15270 *
15271 * If <i>inplace mode</i> is in effect,
15272 * \ARGF may write to target streams,
15273 * which at any particular time are determined by the content of ARGV.
15274 *
15275 * Methods about inplace mode:
15276 *
15277 * - #inplace_mode
15278 * - #inplace_mode=
15279 * - #to_write_io
15280 *
15281 * Methods for writing:
15282 *
15283 * - #print
15284 * - #printf
15285 * - #putc
15286 * - #puts
15287 * - #write
15288 *
15289 */
15290
15291/*
15292 * An instance of class \IO (commonly called a _stream_)
15293 * represents an input/output stream in the underlying operating system.
15294 * Class \IO is the basis for input and output in Ruby.
15295 *
15296 * Class File is the only class in the Ruby core that is a subclass of \IO.
15297 * Some classes in the Ruby standard library are also subclasses of \IO;
15298 * these include TCPSocket and UDPSocket.
15299 *
15300 * The global constant ARGF (also accessible as <tt>$<</tt>)
15301 * provides an IO-like stream that allows access to all file paths
15302 * found in ARGV (or found in STDIN if ARGV is empty).
15303 * ARGF is not itself a subclass of \IO.
15304 *
15305 * Class StringIO provides an IO-like stream that handles a String.
15306 * StringIO is not itself a subclass of \IO.
15307 *
15308 * Important objects based on \IO include:
15309 *
15310 * - $stdin.
15311 * - $stdout.
15312 * - $stderr.
15313 * - Instances of class File.
15314 *
15315 * An instance of \IO may be created using:
15316 *
15317 * - IO.new: returns a new \IO object for the given integer file descriptor.
15318 * - IO.open: passes a new \IO object to the given block.
15319 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15320 * of a newly-launched subprocess.
15321 * - Kernel#open: Returns a new \IO object connected to a given source:
15322 * stream, file, or subprocess.
15323 *
15324 * Like a File stream, an \IO stream has:
15325 *
15326 * - A read/write mode, which may be read-only, write-only, or read/write;
15327 * see {Read/Write Mode}[rdoc-ref:File@ReadWrite+Mode].
15328 * - A data mode, which may be text-only or binary;
15329 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15330 * - Internal and external encodings;
15331 * see {Encodings}[rdoc-ref:File@Encodings].
15332 *
15333 * And like other \IO streams, it has:
15334 *
15335 * - A position, which determines where in the stream the next
15336 * read or write is to occur;
15337 * see {Position}[rdoc-ref:IO@Position].
15338 * - A line number, which is a special, line-oriented, "position"
15339 * (different from the position mentioned above);
15340 * see {Line Number}[rdoc-ref:IO@Line+Number].
15341 *
15342 * == Extension <tt>io/console</tt>
15343 *
15344 * Extension <tt>io/console</tt> provides numerous methods
15345 * for interacting with the console;
15346 * requiring it adds numerous methods to class \IO.
15347 *
15348 * == Example Files
15349 *
15350 * Many examples here use these variables:
15351 *
15352 * :include: doc/examples/files.rdoc
15353 *
15354 * == Open Options
15355 *
15356 * A number of \IO methods accept optional keyword arguments
15357 * that determine how a new stream is to be opened:
15358 *
15359 * - +:mode+: Stream mode.
15360 * - +:flags+: Integer file open flags;
15361 * If +mode+ is also given, the two are bitwise-ORed.
15362 * - +:external_encoding+: External encoding for the stream.
15363 * - +:internal_encoding+: Internal encoding for the stream.
15364 * <tt>'-'</tt> is a synonym for the default internal encoding.
15365 * If the value is +nil+ no conversion occurs.
15366 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15367 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15368 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15369 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15370 * when the stream closes; otherwise it remains open.
15371 * - +:path+: If a string value is provided, it is used in #inspect and is available as
15372 * #path method.
15373 *
15374 * Also available are the options offered in String#encode,
15375 * which may control conversion between external and internal encoding.
15376 *
15377 * == Basic \IO
15378 *
15379 * You can perform basic stream \IO with these methods,
15380 * which typically operate on multi-byte strings:
15381 *
15382 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15383 * - IO#write: Writes zero or more strings to the stream;
15384 * each given object that is not already a string is converted via +to_s+.
15385 *
15386 * === Position
15387 *
15388 * An \IO stream has a nonnegative integer _position_,
15389 * which is the byte offset at which the next read or write is to occur.
15390 * A new stream has position zero (and line number zero);
15391 * method +rewind+ resets the position (and line number) to zero.
15392 *
15393 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15394 * Encoding::Converter instances used for that \IO.
15395 *
15396 * The relevant methods:
15397 *
15398 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15399 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15400 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15401 * relative to a given position +whence+
15402 * (indicating the beginning, end, or current position).
15403 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15404 *
15405 * === Open and Closed Streams
15406 *
15407 * A new \IO stream may be open for reading, open for writing, or both.
15408 *
15409 * A stream is automatically closed when claimed by the garbage collector.
15410 *
15411 * Attempted reading or writing on a closed stream raises an exception.
15412 *
15413 * The relevant methods:
15414 *
15415 * - IO#close: Closes the stream for both reading and writing.
15416 * - IO#close_read: Closes the stream for reading.
15417 * - IO#close_write: Closes the stream for writing.
15418 * - IO#closed?: Returns whether the stream is closed.
15419 *
15420 * === End-of-Stream
15421 *
15422 * You can query whether a stream is positioned at its end:
15423 *
15424 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15425 *
15426 * You can reposition to end-of-stream by using method IO#seek:
15427 *
15428 * f = File.new('t.txt')
15429 * f.eof? # => false
15430 * f.seek(0, :END)
15431 * f.eof? # => true
15432 * f.close
15433 *
15434 * Or by reading all stream content (which is slower than using IO#seek):
15435 *
15436 * f.rewind
15437 * f.eof? # => false
15438 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15439 * f.eof? # => true
15440 *
15441 * == Line \IO
15442 *
15443 * Class \IO supports line-oriented
15444 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15445 *
15446 * === Line Input
15447 *
15448 * Class \IO supports line-oriented input for
15449 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input].
15450 *
15451 * ==== Line Input Options
15452 *
15453 * Optional keyword argument +chomp+ (default: +false+)
15454 * specifies whether line separators are to be excluded from the result of a read.
15455 *
15456 * ==== \File Line Input
15457 *
15458 * You can read lines from a file using these methods:
15459 *
15460 * - IO.foreach: Reads each line and passes it to the given block.
15461 * - IO.readlines: Reads and returns all lines in an array.
15462 *
15463 * For each of these methods:
15464 *
15465 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15466 * - Line parsing depends on the effective <i>line separator</i>;
15467 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15468 * - The length of each returned line depends on the effective <i>line limit</i>;
15469 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15470 *
15471 * ==== Stream Line Input
15472 *
15473 * You can read lines from an \IO stream using these methods:
15474 *
15475 * - IO#each_line: Reads each remaining line, passing it to the given block.
15476 * - IO#gets: Returns the next line.
15477 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15478 * - IO#readlines: Returns all remaining lines in an array.
15479 *
15480 * For each of these methods:
15481 *
15482 * - Reading may begin mid-line,
15483 * depending on the stream's _position_;
15484 * see {Position}[rdoc-ref:IO@Position].
15485 * - Line parsing depends on the effective <i>line separator</i>;
15486 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15487 * - The length of each returned line depends on the effective <i>line limit</i>;
15488 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15489 *
15490 * ===== Line Separator
15491 *
15492 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15493 * the string that determines what is considered a line;
15494 * it is sometimes called the <i>input record separator</i>.
15495 *
15496 * The default line separator is taken from global variable <tt>$/</tt>,
15497 * whose initial value is <tt>"\n"</tt>.
15498 *
15499 * Generally, the line to be read next is all data
15500 * from the current {position}[rdoc-ref:IO@Position]
15501 * to the next line separator
15502 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15503 *
15504 * f = File.new('t.txt')
15505 * # Method gets with no sep argument returns the next line, according to $/.
15506 * f.gets # => "First line\n"
15507 * f.gets # => "Second line\n"
15508 * f.gets # => "\n"
15509 * f.gets # => "Fourth line\n"
15510 * f.gets # => "Fifth line\n"
15511 * f.close
15512 *
15513 * You can use a different line separator by passing argument +sep+:
15514 *
15515 * f = File.new('t.txt')
15516 * f.gets('l') # => "First l"
15517 * f.gets('li') # => "ine\nSecond li"
15518 * f.gets('lin') # => "ne\n\nFourth lin"
15519 * f.gets # => "e\n"
15520 * f.close
15521 *
15522 * Or by setting global variable <tt>$/</tt>:
15523 *
15524 * f = File.new('t.txt')
15525 * $/ = 'l'
15526 * f.gets # => "First l"
15527 * f.gets # => "ine\nSecond l"
15528 * f.gets # => "ine\n\nFourth l"
15529 * f.close
15530 *
15531 * ===== Special Line Separator Values
15532 *
15533 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15534 * accepts two special values for parameter +sep+:
15535 *
15536 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15537 *
15538 * f = File.new('t.txt')
15539 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15540 * f.close
15541 *
15542 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15543 * (paragraphs being separated by two consecutive line separators):
15544 *
15545 * f = File.new('t.txt')
15546 * f.gets('') # => "First line\nSecond line\n\n"
15547 * f.gets('') # => "Fourth line\nFifth line\n"
15548 * f.close
15549 *
15550 * ===== Line Limit
15551 *
15552 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15553 * uses an integer <i>line limit</i>,
15554 * which restricts the number of bytes that may be returned.
15555 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15556 * than the limit).
15557 *
15558 * The default limit value is <tt>-1</tt>;
15559 * any negative limit value means that there is no limit.
15560 *
15561 * If there is no limit, the line is determined only by +sep+.
15562 *
15563 * # Text with 1-byte characters.
15564 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15565 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15566 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15567 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15568 * # No more than one line.
15569 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15570 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15571 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15572 *
15573 * # Text with 3-byte characters, which will not be split.
15574 * File.read('t.ja') # => "こんにちは"
15575 * File.open('t.ja') {|f| f.gets(1).size } # => 1
15576 * File.open('t.ja') {|f| f.gets(2).size } # => 1
15577 * File.open('t.ja') {|f| f.gets(3).size } # => 1
15578 * File.open('t.ja') {|f| f.gets(4).size } # => 2
15579 * File.open('t.ja') {|f| f.gets(5).size } # => 2
15580 *
15581 * ===== Line Separator and Line Limit
15582 *
15583 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15584 *
15585 * - Returns the next line as determined by line separator +sep+.
15586 * - But returns no more bytes than are allowed by the limit +limit+.
15587 *
15588 * Example:
15589 *
15590 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15591 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15592 *
15593 * ===== Line Number
15594 *
15595 * A readable \IO stream has a non-negative integer <i>line number</i>:
15596 *
15597 * - IO#lineno: Returns the line number.
15598 * - IO#lineno=: Resets and returns the line number.
15599 *
15600 * Unless modified by a call to method IO#lineno=,
15601 * the line number is the number of lines read
15602 * by certain line-oriented methods,
15603 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15604 *
15605 * - IO.foreach: Increments the line number on each call to the block.
15606 * - IO#each_line: Increments the line number on each call to the block.
15607 * - IO#gets: Increments the line number.
15608 * - IO#readline: Increments the line number.
15609 * - IO#readlines: Increments the line number for each line read.
15610 *
15611 * A new stream is initially has line number zero (and position zero);
15612 * method +rewind+ resets the line number (and position) to zero:
15613 *
15614 * f = File.new('t.txt')
15615 * f.lineno # => 0
15616 * f.gets # => "First line\n"
15617 * f.lineno # => 1
15618 * f.rewind
15619 * f.lineno # => 0
15620 * f.close
15621 *
15622 * Reading lines from a stream usually changes its line number:
15623 *
15624 * f = File.new('t.txt', 'r')
15625 * f.lineno # => 0
15626 * f.readline # => "This is line one.\n"
15627 * f.lineno # => 1
15628 * f.readline # => "This is the second line.\n"
15629 * f.lineno # => 2
15630 * f.readline # => "Here's the third line.\n"
15631 * f.lineno # => 3
15632 * f.eof? # => true
15633 * f.close
15634 *
15635 * Iterating over lines in a stream usually changes its line number:
15636 *
15637 * File.open('t.txt') do |f|
15638 * f.each_line do |line|
15639 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15640 * end
15641 * end
15642 *
15643 * Output:
15644 *
15645 * "position=11 eof?=false lineno=1"
15646 * "position=23 eof?=false lineno=2"
15647 * "position=24 eof?=false lineno=3"
15648 * "position=36 eof?=false lineno=4"
15649 * "position=47 eof?=true lineno=5"
15650 *
15651 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15652 * the line number does not affect where the next read or write will occur:
15653 *
15654 * f = File.new('t.txt')
15655 * f.lineno = 1000
15656 * f.lineno # => 1000
15657 * f.gets # => "First line\n"
15658 * f.lineno # => 1001
15659 * f.close
15660 *
15661 * Associated with the line number is the global variable <tt>$.</tt>:
15662 *
15663 * - When a stream is opened, <tt>$.</tt> is not set;
15664 * its value is left over from previous activity in the process:
15665 *
15666 * $. = 41
15667 * f = File.new('t.txt')
15668 * $. = 41
15669 * # => 41
15670 * f.close
15671 *
15672 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15673 *
15674 * f0 = File.new('t.txt')
15675 * f1 = File.new('t.dat')
15676 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15677 * $. # => 5
15678 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15679 * $. # => 1
15680 * f0.close
15681 * f1.close
15682 *
15683 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15684 *
15685 * f = File.new('t.txt')
15686 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15687 * $. # => 5
15688 * f.rewind
15689 * f.seek(0, :SET)
15690 * $. # => 5
15691 * f.close
15692 *
15693 * === Line Output
15694 *
15695 * You can write to an \IO stream line-by-line using this method:
15696 *
15697 * - IO#puts: Writes objects to the stream.
15698 *
15699 * == Character \IO
15700 *
15701 * You can process an \IO stream character-by-character using these methods:
15702 *
15703 * - IO#getc: Reads and returns the next character from the stream.
15704 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15705 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15706 * - IO#putc: Writes a character to the stream.
15707 * - IO#each_char: Reads each remaining character in the stream,
15708 * passing the character to the given block.
15709 *
15710 * == Byte \IO
15711 *
15712 * You can process an \IO stream byte-by-byte using these methods:
15713 *
15714 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15715 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15716 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15717 * - IO#each_byte: Reads each remaining byte in the stream,
15718 * passing the byte to the given block.
15719 *
15720 * == Codepoint \IO
15721 *
15722 * You can process an \IO stream codepoint-by-codepoint:
15723 *
15724 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15725 *
15726 * == What's Here
15727 *
15728 * First, what's elsewhere. Class \IO:
15729 *
15730 * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
15731 * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
15732 * which provides dozens of additional methods.
15733 *
15734 * Here, class \IO provides methods that are useful for:
15735 *
15736 * - {Creating}[rdoc-ref:IO@Creating]
15737 * - {Reading}[rdoc-ref:IO@Reading]
15738 * - {Writing}[rdoc-ref:IO@Writing]
15739 * - {Positioning}[rdoc-ref:IO@Positioning]
15740 * - {Iterating}[rdoc-ref:IO@Iterating]
15741 * - {Settings}[rdoc-ref:IO@Settings]
15742 * - {Querying}[rdoc-ref:IO@Querying]
15743 * - {Buffering}[rdoc-ref:IO@Buffering]
15744 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15745 * - {Other}[rdoc-ref:IO@Other]
15746 *
15747 * === Creating
15748 *
15749 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15750 * integer file descriptor.
15751 * - ::open: Creates a new \IO object.
15752 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15753 * - ::popen: Creates an \IO object to interact with a subprocess.
15754 * - ::select: Selects which given \IO instances are ready for reading,
15755 * writing, or have pending exceptions.
15756 *
15757 * === Reading
15758 *
15759 * - ::binread: Returns a binary string with all or a subset of bytes
15760 * from the given file.
15761 * - ::read: Returns a string with all or a subset of bytes from the given file.
15762 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15763 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15764 * - #getc: Returns the next character read from +self+ as a string.
15765 * - #gets: Returns the line read from +self+.
15766 * - #pread: Returns all or the next _n_ bytes read from +self+,
15767 * not updating the receiver's offset.
15768 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15769 * for a given _n_.
15770 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15771 * in non-block mode.
15772 * - #readbyte: Returns the next byte read from +self+;
15773 * same as #getbyte, but raises an exception on end-of-stream.
15774 * - #readchar: Returns the next character read from +self+;
15775 * same as #getc, but raises an exception on end-of-stream.
15776 * - #readline: Returns the next line read from +self+;
15777 * same as #getline, but raises an exception of end-of-stream.
15778 * - #readlines: Returns an array of all lines read read from +self+.
15779 * - #readpartial: Returns up to the given number of bytes from +self+.
15780 *
15781 * === Writing
15782 *
15783 * - ::binwrite: Writes the given string to the file at the given filepath,
15784 * in binary mode.
15785 * - ::write: Writes the given string to +self+.
15786 * - #<<: Appends the given string to +self+.
15787 * - #print: Prints last read line or given objects to +self+.
15788 * - #printf: Writes to +self+ based on the given format string and objects.
15789 * - #putc: Writes a character to +self+.
15790 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15791 * - #pwrite: Writes the given string at the given offset,
15792 * not updating the receiver's offset.
15793 * - #write: Writes one or more given strings to +self+.
15794 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15795 *
15796 * === Positioning
15797 *
15798 * - #lineno: Returns the current line number in +self+.
15799 * - #lineno=: Sets the line number is +self+.
15800 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15801 * - #pos=: Sets the byte offset in +self+.
15802 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15803 * - #rewind: Positions +self+ to the beginning of input.
15804 * - #seek: Sets the offset for +self+ relative to given position.
15805 *
15806 * === Iterating
15807 *
15808 * - ::foreach: Yields each line of given file to the block.
15809 * - #each (aliased as #each_line): Calls the given block
15810 * with each successive line in +self+.
15811 * - #each_byte: Calls the given block with each successive byte in +self+
15812 * as an integer.
15813 * - #each_char: Calls the given block with each successive character in +self+
15814 * as a string.
15815 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15816 * as an integer.
15817 *
15818 * === Settings
15819 *
15820 * - #autoclose=: Sets whether +self+ auto-closes.
15821 * - #binmode: Sets +self+ to binary mode.
15822 * - #close: Closes +self+.
15823 * - #close_on_exec=: Sets the close-on-exec flag.
15824 * - #close_read: Closes +self+ for reading.
15825 * - #close_write: Closes +self+ for writing.
15826 * - #set_encoding: Sets the encoding for +self+.
15827 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15828 * Unicode byte-order-mark.
15829 * - #sync=: Sets the sync-mode to the given value.
15830 *
15831 * === Querying
15832 *
15833 * - #autoclose?: Returns whether +self+ auto-closes.
15834 * - #binmode?: Returns whether +self+ is in binary mode.
15835 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15836 * - #closed?: Returns whether +self+ is closed.
15837 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15838 * - #external_encoding: Returns the external encoding object for +self+.
15839 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15840 * - #internal_encoding: Returns the internal encoding object for +self+.
15841 * - #pid: Returns the process ID of a child process associated with +self+,
15842 * if +self+ was created by ::popen.
15843 * - #stat: Returns the File::Stat object containing status information for +self+.
15844 * - #sync: Returns whether +self+ is in sync-mode.
15845 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15846 *
15847 * === Buffering
15848 *
15849 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15850 * - #flush: Flushes any buffered data within +self+ to the underlying
15851 * operating system.
15852 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15853 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15854 * - #ungetc: Prepends buffer for +self+ with given string.
15855 *
15856 * === Low-Level Access
15857 *
15858 * - ::sysopen: Opens the file given by its path,
15859 * returning the integer file descriptor.
15860 * - #advise: Announces the intention to access data from +self+ in a specific way.
15861 * - #fcntl: Passes a low-level command to the file specified
15862 * by the given file descriptor.
15863 * - #ioctl: Passes a low-level command to the device specified
15864 * by the given file descriptor.
15865 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15866 * - #sysseek: Sets the offset for +self+.
15867 * - #syswrite: Writes the given string to +self+ using a low-level write.
15868 *
15869 * === Other
15870 *
15871 * - ::copy_stream: Copies data from a source to a destination,
15872 * each of which is a filepath or an \IO-like object.
15873 * - ::try_convert: Returns a new \IO object resulting from converting
15874 * the given object.
15875 * - #inspect: Returns the string representation of +self+.
15876 *
15877 */
15878
15879void
15880Init_IO(void)
15881{
15882 VALUE rb_cARGF;
15883#ifdef __CYGWIN__
15884#include <sys/cygwin.h>
15885 static struct __cygwin_perfile pf[] =
15886 {
15887 {"", O_RDONLY | O_BINARY},
15888 {"", O_WRONLY | O_BINARY},
15889 {"", O_RDWR | O_BINARY},
15890 {"", O_APPEND | O_BINARY},
15891 {NULL, 0}
15892 };
15893 cygwin_internal(CW_PERFILE, pf);
15894#endif
15895
15896 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
15897 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
15898
15899 id_write = rb_intern_const("write");
15900 id_read = rb_intern_const("read");
15901 id_flush = rb_intern_const("flush");
15902 id_readpartial = rb_intern_const("readpartial");
15903 id_set_encoding = rb_intern_const("set_encoding");
15904 id_fileno = rb_intern_const("fileno");
15905
15906 rb_define_global_function("syscall", rb_f_syscall, -1);
15907
15908 rb_define_global_function("open", rb_f_open, -1);
15909 rb_define_global_function("printf", rb_f_printf, -1);
15910 rb_define_global_function("print", rb_f_print, -1);
15911 rb_define_global_function("putc", rb_f_putc, 1);
15912 rb_define_global_function("puts", rb_f_puts, -1);
15913 rb_define_global_function("gets", rb_f_gets, -1);
15914 rb_define_global_function("readline", rb_f_readline, -1);
15915 rb_define_global_function("select", rb_f_select, -1);
15916
15917 rb_define_global_function("readlines", rb_f_readlines, -1);
15918
15919 rb_define_global_function("`", rb_f_backquote, 1);
15920
15921 rb_define_global_function("p", rb_f_p, -1);
15922 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15923
15924 rb_cIO = rb_define_class("IO", rb_cObject);
15926
15927 /* Can be raised by IO operations when IO#timeout= is set. */
15928 rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
15929
15930 /* Readable event mask for IO#wait. */
15931 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15932 /* Writable event mask for IO#wait. */
15933 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15934 /* Priority event mask for IO#wait. */
15935 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15936
15937 /* exception to wait for reading. see IO.select. */
15938 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
15939 /* exception to wait for writing. see IO.select. */
15940 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
15941 /* exception to wait for reading by EAGAIN. see IO.select. */
15942 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15943 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15944 /* exception to wait for writing by EAGAIN. see IO.select. */
15945 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15946 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15947#if EAGAIN == EWOULDBLOCK
15948 /* same as IO::EAGAINWaitReadable */
15949 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15950 /* same as IO::EAGAINWaitWritable */
15951 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15952#else
15953 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15954 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15955 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15956 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15957 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15958 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15959#endif
15960 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15961 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15962 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15963 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15964 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15965 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15966
15967#if 0
15968 /* This is necessary only for forcing rdoc handle File::open */
15969 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15970#endif
15971
15972 rb_define_alloc_func(rb_cIO, io_alloc);
15973 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15974 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15975 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15976 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15977 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15978 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15979 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15980 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15981 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15982 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15983 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15984 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15985 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15986 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15987 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15988
15989 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15990
15992 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
15993
15994 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15995 rb_vm_register_global_object(rb_default_rs);
15996 rb_rs = rb_default_rs;
15998 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15999 rb_gvar_ractor_local("$/"); // not local but ractor safe
16000 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
16001 rb_gvar_ractor_local("$-0"); // not local but ractor safe
16002 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
16003
16004 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
16005 rb_gvar_ractor_local("$_");
16006 rb_gvar_box_dynamic("$_");
16007
16008 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
16009 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
16010
16011 rb_define_method(rb_cIO, "print", rb_io_print, -1);
16012 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
16013 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
16014 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
16015
16016 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
16017 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
16018 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
16019 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
16020 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
16021
16022 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
16023 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
16024
16025 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
16026 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
16027
16028 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
16029 rb_define_alias(rb_cIO, "to_i", "fileno");
16030 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
16031
16032 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
16033 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
16034
16035 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
16036 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
16037 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
16038 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
16039
16040 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
16041 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
16042
16043 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
16044
16045 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
16046 rb_define_method(rb_cIO, "read", io_read, -1);
16047 rb_define_method(rb_cIO, "write", io_write_m, -1);
16048 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
16049 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
16050 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
16051 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
16052 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
16053 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
16054 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
16056 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
16057 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
16058 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
16059 /* Set I/O position from the beginning */
16060 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
16061 /* Set I/O position from the current position */
16062 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
16063 /* Set I/O position from the end */
16064 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
16065#ifdef SEEK_DATA
16066 /* Set I/O position to the next location containing data */
16067 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
16068#endif
16069#ifdef SEEK_HOLE
16070 /* Set I/O position to the next hole */
16071 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
16072#endif
16073 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
16074 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
16075 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
16076 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
16077 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
16078
16079 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
16080 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
16081
16082 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
16083 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
16084 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
16085 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
16086
16087 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
16088 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
16089 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
16090 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
16091 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
16092 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
16093
16094 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
16095 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
16096 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
16097
16098 rb_define_method(rb_cIO, "path", rb_io_path, 0);
16099 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
16100
16101 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
16102
16103 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
16104 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
16105 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
16106 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
16107
16108 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
16109 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
16110
16111 rb_define_method(rb_cIO, "wait", io_wait, -1);
16112
16113 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
16114 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
16115 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
16116
16117 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
16118 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
16119 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
16120 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
16121
16122 rb_gvar_ractor_local("$stdin");
16123 rb_gvar_ractor_local("$stdout");
16124 rb_gvar_ractor_local("$>");
16125 rb_gvar_ractor_local("$stderr");
16126
16127 rb_gvar_box_dynamic("$stdin");
16128 rb_gvar_box_dynamic("$stdout");
16129 rb_gvar_box_dynamic("$>");
16130 rb_gvar_box_dynamic("$stderr");
16131
16133 rb_stdin = rb_io_prep_stdin();
16135 rb_stdout = rb_io_prep_stdout();
16137 rb_stderr = rb_io_prep_stderr();
16138
16139 orig_stdout = rb_stdout;
16140 orig_stderr = rb_stderr;
16141
16142 /* Holds the original stdin */
16144 /* Holds the original stdout */
16146 /* Holds the original stderr */
16148
16149#if 0
16150 /* Hack to get rdoc to regard ARGF as a class: */
16151 rb_cARGF = rb_define_class("ARGF", rb_cObject);
16152#endif
16153
16154 rb_cARGF = rb_class_new(rb_cObject);
16155 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
16156 rb_define_alloc_func(rb_cARGF, argf_alloc);
16157
16159
16160 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
16161 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
16162 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
16163 rb_define_alias(rb_cARGF, "inspect", "to_s");
16164 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
16165
16166 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
16167 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
16168 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
16169 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
16170 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
16171 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
16172 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
16173 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
16174 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
16175
16176 rb_define_method(rb_cARGF, "read", argf_read, -1);
16177 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
16178 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
16179 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
16180 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
16181 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
16182 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
16183 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
16184 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
16185 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
16186 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
16187 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
16188 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
16189 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
16190 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
16191 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
16192 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
16193 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
16194 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
16195 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
16196
16197 rb_define_method(rb_cARGF, "write", argf_write, -1);
16198 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
16199 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
16200 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
16201 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
16202
16203 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
16204 rb_define_method(rb_cARGF, "path", argf_filename, 0);
16205 rb_define_method(rb_cARGF, "file", argf_file, 0);
16206 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
16207 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
16208 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
16209
16210 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
16211 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
16212
16213 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
16214 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
16215
16216 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
16217 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
16218 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
16219
16220 argf = rb_class_new_instance(0, 0, rb_cARGF);
16221
16223 /*
16224 * ARGF is a stream designed for use in scripts that process files given
16225 * as command-line arguments or passed in via STDIN.
16226 *
16227 * See ARGF (the class) for more details.
16228 */
16230
16231 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
16232 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
16233 ARGF_SET(filename, rb_str_new2("-"));
16234
16235 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
16236 rb_gvar_ractor_local("$-i");
16237
16238 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16239
16240#if defined (_WIN32) || defined(__CYGWIN__)
16241 atexit(pipe_atexit);
16242#endif
16243
16244 Init_File();
16245
16246 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16247
16248 sym_mode = ID2SYM(rb_intern_const("mode"));
16249 sym_perm = ID2SYM(rb_intern_const("perm"));
16250 sym_flags = ID2SYM(rb_intern_const("flags"));
16251 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16252 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16253 sym_encoding = ID2SYM(rb_id_encoding());
16254 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16255 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16256 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16257 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16258 sym_normal = ID2SYM(rb_intern_const("normal"));
16259 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16260 sym_random = ID2SYM(rb_intern_const("random"));
16261 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16262 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16263 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16264 sym_SET = ID2SYM(rb_intern_const("SET"));
16265 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16266 sym_END = ID2SYM(rb_intern_const("END"));
16267#ifdef SEEK_DATA
16268 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16269#endif
16270#ifdef SEEK_HOLE
16271 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16272#endif
16273 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16274 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16275}
16276
16277static void init_builtin_io(void);
16278#define Init_builtin_io init_builtin_io
16279#include "io.rbinc"
16280#undef Init_builtin_io
16281
16282void
16283Init_builtin_io(void)
16284{
16285 init_builtin_io();
16286
16287 /* Init_IO is called earlier than `loaded_features` is initialized */
16288 rb_provide("io/wait.rb");
16289 rb_provide("io/wait.so");
16290}
#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:113
#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:1736
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:853
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:3060
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:3363
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:3350
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1035
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:3139
#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:1700
#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 REALLOC_N
Old name of RB_REALLOC_N.
Definition memory.h:403
#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 LEN2NUM
Old name of RB_LEN2NUM.
Definition len_t.h:33
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1708
#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:131
#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 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 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 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 NUM2LEN
Old name of RB_NUM2LEN.
Definition len_t.h:34
#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:1702
#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_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:474
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:506
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1467
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:678
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:4053
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:14948
VALUE rb_eIOError
IOError exception.
Definition io.c:180
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1454
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:4143
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:4059
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:476
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1457
VALUE rb_eEOFError
EOFError exception.
Definition io.c:179
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14942
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2422
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1455
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:464
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1477
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:59
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3353
VALUE rb_cObject
Object class.
Definition object.c:60
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:664
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2274
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2315
VALUE rb_cIO
IO class.
Definition io.c:178
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:2303
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:28
VALUE rb_stdin
STDIN constant.
Definition io.c:194
VALUE rb_stderr
STDERR constant.
Definition io.c:194
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:240
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:562
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:675
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:182
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:183
VALUE rb_obj_freeze(VALUE obj)
Same as RB_OBJ_FREEZE(), but returns the given object.
Definition object.c:1315
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:3334
VALUE rb_cFile
File class.
Definition file.c:175
VALUE rb_stdout
STDOUT constant.
Definition io.c:194
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3347
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:504
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:492
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:581
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:632
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:866
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:856
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:74
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size)
Non-blocking pread from the passed IO using a native buffer.
Definition scheduler.c:1127
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:896
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size)
Non-blocking read from the passed IO using a native buffer.
Definition scheduler.c:1079
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:589
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size)
Non-blocking pwrite to the passed IO using a native buffer.
Definition scheduler.c:1152
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:594
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:872
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
Definition scheduler.c:1177
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size)
Non-blocking write to the passed IO using a native buffer.
Definition scheduler.c:1103
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
static int rb_enc_mbmaxlen(rb_encoding *enc)
Queries the maximum number of bytes that the passed encoding needs to represent a character.
Definition encoding.h:447
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1393
rb_len_t 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:858
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3953
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:2679
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:2126
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:1487
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:1783
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1827
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:1962
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:2730
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:2025
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:2993
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4359
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4365
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1744
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1794
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1148
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:1115
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
Definition vm_eval.c:1106
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_ary_entry(VALUE ary, rb_len_t off)
Queries an element of an array.
VALUE rb_ary_new_capa(rb_len_t capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
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_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:8828
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4513
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:478
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:8961
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2429
void rb_write_error2(const char *str, rb_len_t len)
Identical to rb_write_error(), except it additionally takes the message's length.
Definition io.c:9370
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9390
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:5385
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5290
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:376
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:9571
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:274
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:337
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:199
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2771
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:324
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6630
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6584
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5449
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7631
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10659
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:484
VALUE rb_output_fs
The field separator character for outputs, or the $,.
Definition io.c:197
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:7515
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:369
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7522
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5985
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:200
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
Definition load.c:711
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:2184
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:2178
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:3812
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1161
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:676
void rb_str_modify_expand(VALUE str, rb_len_t capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2841
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:3938
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1523
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1706
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1557
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:1037
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1569
void rb_str_set_len(VALUE str, rb_len_t len)
Overwrites the length of the string.
Definition string.c:3525
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:2052
VALUE rb_str_cat(VALUE dst, const char *src, rb_len_t srclen)
Destructively appends the passed contents to the string.
Definition string.c:3706
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_no_gvl_safe_acquire(VALUE orig)
Creates a frozen copy of orig that guarantees the RSTRING_PTR is safe to use in operations that relea...
Definition string.c:1598
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4407
void rb_str_no_gvl_safe_release(VALUE orig, VALUE tmp)
Releases a string created from rb_str_no_gvl_safe_acquire.
Definition string.c:1641
VALUE rb_str_substr(VALUE str, rb_len_t beg, rb_len_t len)
This is the implementation of two-argumented String#slice.
Definition string.c:3388
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:3880
VALUE rb_str_buf_new(rb_len_t capa)
Allocates a "string buffer".
Definition string.c:1783
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:3072
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3507
#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:1539
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:1916
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1663
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:1669
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:1646
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:3492
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1663
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1669
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2984
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:457
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:2150
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:516
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3715
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well... Let us hesitate from describing what a "basic definition" is.
Definition vm_method.c:3593
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:716
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:4065
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:888
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:6716
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:819
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:865
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:789
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1103
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:6849
#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:1049
#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:1058
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:1655
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:7332
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:6998
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2970
#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:9617
#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:1722
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:1675
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:181
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:3049
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:7123
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:796
#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:5896
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:825
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:6093
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:894
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:2086
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:1030
#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:831
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3543
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1611
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:9483
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:842
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1082
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:1737
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:804
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1576
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7623
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1516
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:1456
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:1525
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:1513
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:1501
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:2323
#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:232
#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:1448
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1403
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:50
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:280
#define RARRAY_AREF(a, i)
References an object in an array.
Definition rarray.h:421
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:51
#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:81
#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:604
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14908
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9269
#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
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:4870
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:229
Definition win32.h:196
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:242
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:134
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
long rb_len_t
A signed integer type for lengths and indices of objects such as String and Array.
Definition value.h:142
#define RB_LEN_MAX
Maximum possible value that a rb_len_t can take.
Definition value.h:156
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:425
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
#define RBIMPL_WARNING_IGNORED(flag)
Suppresses a warning.
#define RBIMPL_WARNING_PUSH()
Pushes compiler warning state.
#define RBIMPL_WARNING_POP()
Pops compiler warning state.