Ruby 4.1.0dev (2026-09-26 revision 57213d44ce7b1a31fc9648e9cd5eb0c4507f4a49)
io.c (57213d44ce7b1a31fc9648e9cd5eb0c4507f4a49)
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) || defined(_nec_ews)
56# define USE_SETVBUF
57#endif
58
59#ifdef __QNXNTO__
60#include <unix.h>
61#endif
62
63#include <sys/types.h>
64#ifdef HAVE_SYS_IOCTL_H
65#include <sys/ioctl.h>
66#endif
67#if defined(HAVE_FCNTL_H)
68#include <fcntl.h>
69#elif defined(HAVE_SYS_FCNTL_H)
70#include <sys/fcntl.h>
71#endif
72
73#ifdef HAVE_SYS_TIME_H
74# include <sys/time.h>
75#endif
76
77#include <sys/stat.h>
78
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
81#endif
82
83#if !defined NOFILE
84# define NOFILE 64
85#endif
86
87#ifdef HAVE_UNISTD_H
88#include <unistd.h>
89#endif
90
91#ifdef HAVE_SYSCALL_H
92#include <syscall.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
95#endif
96
97#ifdef HAVE_SYS_UIO_H
98#include <sys/uio.h>
99#endif
100
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h> /* for WNOHANG on BSD */
103#endif
104
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
107
108# ifndef COPYFILE_STATE_COPIED
109/*
110 * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
111 * COPYFILE_STATE_COPIED. Since the only use of the former here
112 * requires the latter, we disable the former when the latter is undefined.
113 */
114# undef HAVE_FCOPYFILE
115# endif
116
117#endif
118
119#if defined __APPLE__
120# include <AvailabilityMacros.h>
121#endif
122
124#include "ccan/list/list.h"
125#include "dln.h"
126#include "encindex.h"
127#include "id.h"
128#include "internal.h"
129#include "internal/class.h"
130#include "internal/encoding.h"
131#include "internal/error.h"
132#include "internal/inits.h"
133#include "internal/io.h"
134#include "internal/numeric.h"
135#include "internal/object.h"
136#include "internal/process.h"
137#include "internal/thread.h"
138#include "internal/transcode.h"
139#include "internal/variable.h"
140#include "ruby/io.h"
141#include "ruby/io/buffer.h"
142#include "ruby/missing.h"
143#include "ruby/thread.h"
144#include "ruby/util.h"
145#include "ruby_atomic.h"
146#include "ruby/ractor.h"
147
148#if !USE_POLL
149# include "vm_core.h"
150#endif
151
152#include "builtin.h"
153
154#ifndef O_ACCMODE
155#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
156#endif
157
158#ifndef PIPE_BUF
159# ifdef _POSIX_PIPE_BUF
160# define PIPE_BUF _POSIX_PIPE_BUF
161# else
162# define PIPE_BUF 512 /* is this ok? */
163# endif
164#endif
165
166#ifndef EWOULDBLOCK
167# define EWOULDBLOCK EAGAIN
168#endif
169
170#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
171/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
172off_t __syscall(quad_t number, ...);
173#endif
174
175#define IO_RBUF_CAPA_MIN 8192
176#define IO_CBUF_CAPA_MIN (128*1024)
177#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
178#define IO_WBUF_CAPA_MIN 8192
179
180#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
181
182/* define system APIs */
183#ifdef _WIN32
184#undef open
185#define open rb_w32_uopen
186#undef rename
187#define rename(f, t) rb_w32_urename((f), (t))
188#include "win32/file.h"
189#endif
190
197
198static VALUE rb_eEAGAINWaitReadable;
199static VALUE rb_eEAGAINWaitWritable;
200#if EAGAIN != EWOULDBLOCK
201static VALUE rb_eEWOULDBLOCKWaitReadable;
202static VALUE rb_eEWOULDBLOCKWaitWritable;
203#endif
204static VALUE rb_eEINPROGRESSWaitWritable;
205static VALUE rb_eEINPROGRESSWaitReadable;
206
208static VALUE orig_stdout, orig_stderr;
209
211VALUE rb_rs;
214
215static VALUE argf;
216
217static ID id_write, id_read, id_flush, id_readpartial, id_set_encoding, id_fileno;
218static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
219static VALUE sym_textmode, sym_binmode, sym_autoclose;
220static VALUE sym_SET, sym_CUR, sym_END;
221static VALUE sym_wait_readable, sym_wait_writable;
222#ifdef SEEK_DATA
223static VALUE sym_DATA;
224#endif
225#ifdef SEEK_HOLE
226static VALUE sym_HOLE;
227#endif
228
229static VALUE prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path);
230
231VALUE
232rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
233{
234 return rb_thread_io_blocking_call(io, function, argument, events);
235}
236
237VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
238{
239 return rb_io_blocking_region_wait(io, function, argument, 0);
240}
241
242struct argf {
243 VALUE filename, current_file;
244 long last_lineno; /* $. */
245 long lineno;
246 VALUE argv;
247 VALUE inplace;
248 struct rb_io_encoding encs;
249 int8_t init_p, next_p, binmode;
250};
251
252
253#if defined(__APPLE__) && \
254 (!defined(MAC_OS_VERSION_27_0) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_27_0))
255
256# if __has_attribute(availability) && __has_warning("-Wunguarded-availability-new")
257
259RBIMPL_WARNING_IGNORED(-Wunguarded-availability-new)
260
261# ifdef HAVE_DUP3
262static inline int (*rb_dup3(void))(int, int, int) {return &dup3;}
263# define dup3 rb_dup3()
264# endif
265
266# ifdef HAVE_PIPE2
267static inline int (*rb_pipe2(void))(int [2], int) {return &pipe2;}
268# define pipe2 rb_pipe2()
269# endif
270
272
273# else /* __API_AVAILABLE macro does nothing on gcc */
274
275# ifdef HAVE_DUP3
276__attribute__((weak)) int dup3(int, int, int);
277# endif
278# ifdef HAVE_PIPE2
279__attribute__((weak)) int pipe2(int [2], int);
280# endif
281
282# endif
283#endif /* __APPLE__ && < MAC_OS_X_VERSION_27_0 */
284
285static rb_atomic_t max_file_descriptor = NOFILE;
286void
288{
289 rb_atomic_t afd = (rb_atomic_t)fd;
290 rb_atomic_t max_fd = max_file_descriptor;
291 int err;
292
293 if (fd < 0 || afd <= max_fd)
294 return;
295
296#if defined(HAVE_FCNTL) && defined(F_GETFL)
297 err = fcntl(fd, F_GETFL) == -1;
298#else
299 {
300 struct stat buf;
301 err = fstat(fd, &buf) != 0;
302 }
303#endif
304 if (err && errno == EBADF) {
305 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
306 }
307
308 while (max_fd < afd) {
309 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
310 }
311}
312
313void
314rb_maygvl_fd_fix_cloexec(int fd)
315{
316 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
317#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
318 int flags, flags2, ret;
319 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
320 if (flags == -1) {
321 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
322 }
323 if (fd <= 2)
324 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
325 else
326 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
327 if (flags != flags2) {
328 ret = fcntl(fd, F_SETFD, flags2);
329 if (ret != 0) {
330 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
331 }
332 }
333#endif
334}
335
336void
338{
339 rb_maygvl_fd_fix_cloexec(fd);
341}
342
343/* this is only called once */
344static int
345rb_fix_detect_o_cloexec(int fd)
346{
347#if defined(O_CLOEXEC) && defined(F_GETFD)
348 int flags = fcntl(fd, F_GETFD);
349
350 if (flags == -1)
351 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
352
353 if (flags & FD_CLOEXEC)
354 return 1;
355#endif /* fall through if O_CLOEXEC does not work: */
356 rb_maygvl_fd_fix_cloexec(fd);
357 return 0;
358}
359
360static inline bool
361io_again_p(int e)
362{
363 return (e == EWOULDBLOCK) || (e == EAGAIN);
364}
365
366int
367rb_cloexec_open(const char *pathname, int flags, mode_t mode)
368{
369 int ret;
370 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
371
372 static const int retry_interval = 0;
373 static const int retry_max_count = 10000;
374
375 int retry_count = 0;
376
377#ifdef O_CLOEXEC
378 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
379 flags |= O_CLOEXEC;
380#elif defined O_NOINHERIT
381 flags |= O_NOINHERIT;
382#endif
383
384 while ((ret = open(pathname, flags, mode)) == -1) {
385 int e = errno;
386 if (!io_again_p(e)) break;
387 if (retry_count++ >= retry_max_count) break;
388
389 sleep(retry_interval);
390 }
391
392 if (ret < 0) return ret;
393 if (ret <= 2 || o_cloexec_state == 0) {
394 rb_maygvl_fd_fix_cloexec(ret);
395 }
396 else if (o_cloexec_state > 0) {
397 return ret;
398 }
399 else {
400 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
401 }
402 return ret;
403}
404
405int
407{
408 /* Don't allocate standard file descriptors: 0, 1, 2 */
409 return rb_cloexec_fcntl_dupfd(oldfd, 3);
410}
411
412int
413rb_cloexec_dup2(int oldfd, int newfd)
414{
415 int ret;
416
417 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
418 * rb_cloexec_dup2 succeeds as dup2. */
419 if (oldfd == newfd) {
420 ret = newfd;
421 }
422 else {
423#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
424# if defined(__APPLE__)
425# define try_dup3 (dup3 != NULL)
426# define abandon_dup3() true
427# else
428 static bool try_dup3 = true;
429# define abandon_dup3() (errno != ENOSYS || !!(try_dup3 = false))
430# endif
431 if (newfd <= 2) {
432 /* pass stdin, stdout and stderr to children */
433 }
434 else if (try_dup3) {
435 ret = dup3(oldfd, newfd, O_CLOEXEC);
436 /* dup3 is available since:
437 * - Linux 2.6.27, glibc 2.9
438 * - macOS 27.0
439 */
440 if (ret != -1)
441 return ret;
442 if (abandon_dup3()) return ret;
443 }
444#endif
445 ret = dup2(oldfd, newfd);
446 if (ret < 0) return ret;
447 }
448 rb_maygvl_fd_fix_cloexec(ret);
449 return ret;
450}
451
452static int
453rb_fd_set_nonblock(int fd)
454{
455#ifdef _WIN32
456 return rb_w32_set_nonblock(fd);
457#elif defined(F_GETFL)
458 int oflags = fcntl(fd, F_GETFL);
459
460 if (oflags == -1)
461 return -1;
462 if (oflags & O_NONBLOCK)
463 return 0;
464 oflags |= O_NONBLOCK;
465 return fcntl(fd, F_SETFL, oflags);
466#endif
467 return 0;
468}
469
470static inline int
471cloexec_pipe(int descriptors[2], int flags, bool force_cloexec)
472{
473 int result = -1;
474#ifdef HAVE_PIPE2
475# if defined(__APPLE__)
476# define try_pipe2 (pipe2 != NULL)
477# define abandon_pipe2() true
478# else
479 static bool try_pipe2 = true;
480# define abandon_pipe2() (errno != ENOSYS || !!(try_pipe2 = false))
481# endif
482 if (try_pipe2) {
483 result = pipe2(descriptors, O_CLOEXEC | flags);
484 if (result == 0) return result;
485 if (abandon_pipe2()) return result;
486 }
487#endif
488 if (result < 0 && (result = pipe(descriptors)) < 0)
489 return result;
490
491#ifdef __CYGWIN__
492 if (result == 0 && descriptors[1] == -1) {
493 close(descriptors[0]);
494 descriptors[0] = -1;
495 errno = ENFILE;
496 return -1;
497 }
498#endif
499
500 if (!force_cloexec) return result;
501
502 /* no pipe2 or fallenback to dup */
503 rb_maygvl_fd_fix_cloexec(descriptors[0]);
504 rb_maygvl_fd_fix_cloexec(descriptors[1]);
505
506#ifndef _WIN32
507 rb_fd_set_nonblock(descriptors[0]);
508 rb_fd_set_nonblock(descriptors[1]);
509#endif
510
511 return result;
512}
513
514int
515rb_cloexec_pipe(int descriptors[2])
516{
517 return cloexec_pipe(descriptors, O_NONBLOCK, true);
518}
519
520int
521rb_cloexec_fcntl_dupfd(int fd, int minfd)
522{
523 int ret;
524
525#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
526 static int try_dupfd_cloexec = 1;
527 if (try_dupfd_cloexec) {
528 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
529 if (ret != -1) {
530 if (ret <= 2)
531 rb_maygvl_fd_fix_cloexec(ret);
532 return ret;
533 }
534 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
535 if (errno == EINVAL) {
536 ret = fcntl(fd, F_DUPFD, minfd);
537 if (ret != -1) {
538 try_dupfd_cloexec = 0;
539 }
540 }
541 }
542 else {
543 ret = fcntl(fd, F_DUPFD, minfd);
544 }
545#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
546 ret = fcntl(fd, F_DUPFD, minfd);
547#else
548 ret = dup(fd);
549 if (ret >= 0 && ret < minfd) {
550 const int prev_fd = ret;
551 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
552 close(prev_fd);
553 }
554 return ret;
555#endif
556 if (ret < 0) return ret;
557 rb_maygvl_fd_fix_cloexec(ret);
558 return ret;
559}
560
561#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
562#define ARGF argf_of(argf)
563#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
564
565#define GetWriteIO(io) rb_io_get_write_io(io)
566
567#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
568#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
569#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
570#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
571
572#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
573#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
574#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
575
576#if defined(_WIN32)
577#define WAIT_FD_IN_WIN32(fptr) \
578 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
579#else
580#define WAIT_FD_IN_WIN32(fptr)
581#endif
582
583#define READ_CHECK(fptr) do {\
584 if (!READ_DATA_PENDING(fptr)) {\
585 WAIT_FD_IN_WIN32(fptr);\
586 rb_io_check_closed(fptr);\
587 }\
588} while(0)
589
590#ifndef S_ISSOCK
591# ifdef _S_ISSOCK
592# define S_ISSOCK(m) _S_ISSOCK(m)
593# else
594# ifdef _S_IFSOCK
595# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
596# else
597# ifdef S_IFSOCK
598# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
599# endif
600# endif
601# endif
602#endif
603
604static int io_fflush(rb_io_t *);
605static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
606static void clear_readconv(rb_io_t *fptr);
607static void clear_codeconv(rb_io_t *fptr);
608
609#define FMODE_SIGNAL_ON_EPIPE (1<<17)
610
611#define fptr_signal_on_epipe(fptr) \
612 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
613
614#define fptr_set_signal_on_epipe(fptr, flag) \
615 ((flag) ? \
616 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
617 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
618
619extern ID ruby_static_id_signo;
620
621NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
622static void
623rb_sys_fail_on_write(rb_io_t *fptr)
624{
625 int e = errno;
626 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
627#if defined EPIPE
628 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
629 const VALUE sig =
630# if defined SIGPIPE
631 INT2FIX(SIGPIPE) - INT2FIX(0) +
632# endif
633 INT2FIX(0);
634 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
635 }
636#endif
637 rb_exc_raise(errinfo);
638}
639
640#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
641#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
642#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
643# define RUBY_CRLF_ENVIRONMENT 1
644#else
645# define RUBY_CRLF_ENVIRONMENT 0
646#endif
647
648#if RUBY_CRLF_ENVIRONMENT
649/* Windows */
650# define DEFAULT_TEXTMODE FMODE_TEXTMODE
651# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
652/*
653 * CRLF newline is set as default newline decorator.
654 * If only CRLF newline conversion is needed, we use binary IO process
655 * with OS's text mode for IO performance improvement.
656 * If encoding conversion is needed or a user sets text mode, we use encoding
657 * conversion IO process and universal newline decorator by default.
658 */
659#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
660#define WRITECONV_MASK ( \
661 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
662 ECONV_STATEFUL_DECORATOR_MASK|\
663 0)
664#define NEED_WRITECONV(fptr) ( \
665 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
666 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
667 0)
668#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
669
670#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
671 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
672 if (((fptr)->mode & FMODE_READABLE) &&\
673 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
674 setmode((fptr)->fd, O_BINARY);\
675 }\
676 else {\
677 setmode((fptr)->fd, O_TEXT);\
678 }\
679 }\
680} while(0)
681
682#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
683 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
684 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
685 }\
686} while(0)
687
688/*
689 * IO unread with taking care of removed '\r' in text mode.
690 */
691static void
692io_unread(rb_io_t *fptr, bool discard_rbuf)
693{
694 rb_off_t r, pos;
695 ssize_t read_size;
696 long i;
697 long newlines = 0;
698 long extra_max;
699 char *p;
700 char *buf;
701
702 rb_io_check_closed(fptr);
703 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
704 return;
705 }
706
707 errno = 0;
708 if (!rb_w32_fd_is_text(fptr->fd)) {
709 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
710 if (r < 0 && errno) {
711 if (errno == ESPIPE)
712 fptr->mode |= FMODE_DUPLEX;
713 if (!discard_rbuf) return;
714 }
715
716 goto end;
717 }
718
719 pos = lseek(fptr->fd, 0, SEEK_CUR);
720 if (pos < 0 && errno) {
721 if (errno == ESPIPE)
722 fptr->mode |= FMODE_DUPLEX;
723 if (!discard_rbuf) goto end;
724 }
725
726 /* add extra offset for removed '\r' in rbuf */
727 extra_max = (long)(pos - fptr->rbuf.len);
728 p = fptr->rbuf.ptr + fptr->rbuf.off;
729
730 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
731 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
732 newlines++;
733 }
734
735 for (i = 0; i < fptr->rbuf.len; i++) {
736 if (*p == '\n') newlines++;
737 if (extra_max == newlines) break;
738 p++;
739 }
740
741 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
742 while (newlines >= 0) {
743 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
744 if (newlines == 0) break;
745 if (r < 0) {
746 newlines--;
747 continue;
748 }
749 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
750 if (read_size < 0) {
751 int e = errno;
752 free(buf);
753 rb_syserr_fail_path(e, fptr->pathv);
754 }
755 if (read_size == fptr->rbuf.len) {
756 lseek(fptr->fd, r, SEEK_SET);
757 break;
758 }
759 else {
760 newlines--;
761 }
762 }
763 free(buf);
764 end:
765 fptr->rbuf.off = 0;
766 fptr->rbuf.len = 0;
767 clear_codeconv(fptr);
768 return;
769}
770
771/*
772 * We use io_seek to back cursor position when changing mode from text to binary,
773 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
774 * conversion for working properly with mode change.
775 *
776 * Return previous translation mode.
777 */
778static inline int
779set_binary_mode_with_seek_cur(rb_io_t *fptr)
780{
781 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
782
783 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
784 return setmode(fptr->fd, O_BINARY);
785 }
786 flush_before_seek(fptr, false);
787 return setmode(fptr->fd, O_BINARY);
788}
789#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
790
791#else
792/* Unix */
793# define DEFAULT_TEXTMODE 0
794#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
795#define NEED_WRITECONV(fptr) ( \
796 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
797 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
798 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
799 0)
800#define SET_BINARY_MODE(fptr) (void)(fptr)
801#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
802#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
803#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
804#endif
805
806#if !defined HAVE_SHUTDOWN && !defined shutdown
807#define shutdown(a,b) 0
808#endif
809
810#if defined(_WIN32)
811#define is_socket(fd, path) rb_w32_is_socket(fd)
812#elif !defined(S_ISSOCK)
813#define is_socket(fd, path) 0
814#else
815static int
816is_socket(int fd, VALUE path)
817{
818 struct stat sbuf;
819 if (fstat(fd, &sbuf) < 0)
820 rb_sys_fail_path(path);
821 return S_ISSOCK(sbuf.st_mode);
822}
823#endif
824
825static const char closed_stream[] = "closed stream";
826
827static void
828io_fd_check_closed(int fd)
829{
830 if (fd < 0) {
831 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
832 rb_raise(rb_eIOError, closed_stream);
833 }
834}
835
836void
837rb_eof_error(void)
838{
839 rb_raise(rb_eEOFError, "end of file reached");
840}
841
842VALUE
844{
845 rb_check_frozen(io);
846 return io;
847}
848
849void
851{
852 if (!fptr) {
853 rb_raise(rb_eIOError, "uninitialized stream");
854 }
855}
856
857void
859{
861 io_fd_check_closed(fptr->fd);
862}
863
864static rb_io_t *
865rb_io_get_fptr(VALUE io)
866{
867 rb_io_t *fptr = RFILE(io)->fptr;
869 return fptr;
870}
871
872VALUE
874{
875 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
876}
877
878VALUE
880{
881 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
882}
883
884VALUE
886{
887 VALUE write_io;
888 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
889 if (write_io) {
890 return write_io;
891 }
892 return io;
893}
894
895VALUE
897{
898 VALUE write_io;
899 rb_io_t *fptr = rb_io_get_fptr(io);
900 if (!RTEST(w)) {
901 w = 0;
902 }
903 else {
904 GetWriteIO(w);
905 }
906 write_io = fptr->tied_io_for_writing;
907 fptr->tied_io_for_writing = w;
908 return write_io ? write_io : Qnil;
909}
910
911/*
912 * call-seq:
913 * timeout -> duration or nil
914 *
915 * Get the internal timeout duration or nil if it was not set.
916 *
917 */
918VALUE
920{
921 rb_io_t *fptr = rb_io_get_fptr(self);
922
923 return fptr->timeout;
924}
925
926/*
927 * call-seq:
928 * timeout = duration -> duration
929 * timeout = nil -> nil
930 *
931 * Sets the internal timeout to the specified duration or nil. The timeout
932 * applies to all blocking operations where possible.
933 *
934 * When the operation performs longer than the timeout set, IO::TimeoutError
935 * is raised.
936 *
937 * This affects the following methods (but is not limited to): #gets, #puts,
938 * #read, #write, #wait_readable and #wait_writable. This also affects
939 * blocking socket operations like Socket#accept and Socket#connect.
940 *
941 * Some operations like File#open and IO#close are not affected by the
942 * timeout. A timeout during a write operation may leave the IO in an
943 * inconsistent state, e.g. data was partially written. Generally speaking, a
944 * timeout is a last ditch effort to prevent an application from hanging on
945 * slow I/O operations, such as those that occur during a slowloris attack.
946 */
947VALUE
949{
950 // Validate it:
951 if (RTEST(timeout)) {
952 rb_time_interval(timeout);
953 }
954
955 rb_io_t *fptr = rb_io_get_fptr(self);
956
957 RB_OBJ_WRITE(self, &fptr->timeout, timeout);
958
959 return self;
960}
961
962/*
963 * call-seq:
964 * IO.try_convert(object) -> new_io or nil
965 *
966 * Attempts to convert +object+ into an \IO object via method +to_io+;
967 * returns the new \IO object if successful, or +nil+ otherwise:
968 *
969 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
970 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
971 * IO.try_convert('STDOUT') # => nil
972 *
973 */
974static VALUE
975rb_io_s_try_convert(VALUE dummy, VALUE io)
976{
977 return rb_io_check_io(io);
978}
979
980#if !RUBY_CRLF_ENVIRONMENT
981static void
982io_unread(rb_io_t *fptr, bool discard_rbuf)
983{
984 rb_off_t r;
985 rb_io_check_closed(fptr);
986 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
987 return;
988 /* xxx: target position may be negative if buffer is filled by ungetc */
989 errno = 0;
990 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
991 if (r < 0 && errno) {
992 if (errno == ESPIPE)
993 fptr->mode |= FMODE_DUPLEX;
994 if (!discard_rbuf) return;
995 }
996 fptr->rbuf.off = 0;
997 fptr->rbuf.len = 0;
998 clear_codeconv(fptr);
999 return;
1000}
1001#endif
1002
1003static rb_encoding *io_input_encoding(rb_io_t *fptr);
1004
1005static void
1006io_ungetbyte(VALUE str, rb_io_t *fptr)
1007{
1008 long len = RSTRING_LEN(str);
1009
1010 if (fptr->rbuf.ptr == NULL) {
1011 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
1012 fptr->rbuf.off = 0;
1013 fptr->rbuf.len = 0;
1014#if SIZEOF_LONG > SIZEOF_INT
1015 if (len > INT_MAX)
1016 rb_raise(rb_eIOError, "ungetbyte failed");
1017#endif
1018 if (len > min_capa)
1019 fptr->rbuf.capa = (int)len;
1020 else
1021 fptr->rbuf.capa = min_capa;
1022 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
1023 }
1024 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
1025 rb_raise(rb_eIOError, "ungetbyte failed");
1026 }
1027 if (fptr->rbuf.off < len) {
1028 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
1029 fptr->rbuf.ptr+fptr->rbuf.off,
1030 char, fptr->rbuf.len);
1031 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
1032 }
1033 fptr->rbuf.off-=(int)len;
1034 fptr->rbuf.len+=(int)len;
1035 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
1036}
1037
1038static rb_io_t *
1039flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
1040{
1041 if (io_fflush(fptr) < 0)
1042 rb_sys_fail_on_write(fptr);
1043 io_unread(fptr, discard_rbuf);
1044 errno = 0;
1045 return fptr;
1046}
1047
1048#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
1049#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1050
1051#ifndef SEEK_CUR
1052# define SEEK_SET 0
1053# define SEEK_CUR 1
1054# define SEEK_END 2
1055#endif
1056
1057void
1059{
1060 rb_io_check_closed(fptr);
1061 if (!(fptr->mode & FMODE_READABLE)) {
1062 rb_raise(rb_eIOError, "not opened for reading");
1063 }
1064 if (fptr->wbuf.len) {
1065 if (io_fflush(fptr) < 0)
1066 rb_sys_fail_on_write(fptr);
1067 }
1068 if (fptr->tied_io_for_writing) {
1069 rb_io_t *wfptr;
1070 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1071 if (io_fflush(wfptr) < 0)
1072 rb_sys_fail_on_write(wfptr);
1073 }
1074}
1075
1076void
1078{
1080 if (READ_CHAR_PENDING(fptr)) {
1081 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1082 }
1083}
1084
1085void
1090
1091static rb_encoding*
1092io_read_encoding(rb_io_t *fptr)
1093{
1094 if (fptr->encs.enc) {
1095 return fptr->encs.enc;
1096 }
1097 return rb_default_external_encoding();
1098}
1099
1100static rb_encoding*
1101io_input_encoding(rb_io_t *fptr)
1102{
1103 if (fptr->encs.enc2) {
1104 return fptr->encs.enc2;
1105 }
1106 return io_read_encoding(fptr);
1107}
1108
1109void
1111{
1112 rb_io_check_closed(fptr);
1113 if (!(fptr->mode & FMODE_WRITABLE)) {
1114 rb_raise(rb_eIOError, "not opened for writing");
1115 }
1116 if (fptr->rbuf.len) {
1117 io_unread(fptr, true);
1118 }
1119}
1120
1121int
1122rb_io_read_pending(rb_io_t *fptr)
1123{
1124 /* This function is used for bytes and chars. Confusing. */
1125 if (READ_CHAR_PENDING(fptr))
1126 return 1; /* should raise? */
1127 return READ_DATA_PENDING(fptr);
1128}
1129
1130void
1132{
1133 if (!READ_DATA_PENDING(fptr)) {
1134 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1135 }
1136 return;
1137}
1138
1139int
1140rb_gc_for_fd(int err)
1141{
1142 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1143 rb_gc();
1144 return 1;
1145 }
1146 return 0;
1147}
1148
1149/* try `expr` upto twice while it returns false and `errno`
1150 * is to GC. Each `errno`s are available as `first_errno` and
1151 * `retried_errno` respectively */
1152#define TRY_WITH_GC(expr) \
1153 for (int first_errno, retried_errno = 0, retried = 0; \
1154 (!retried && \
1155 !(expr) && \
1156 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1157 (retried_errno = errno, 1)); \
1158 (void)retried_errno, retried = 1)
1159
1160static int
1161ruby_dup(int orig)
1162{
1163 int fd = -1;
1164
1165 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1166 rb_syserr_fail(first_errno, 0);
1167 }
1168 rb_update_max_fd(fd);
1169 return fd;
1170}
1171
1172static VALUE
1173io_alloc(VALUE klass)
1174{
1175 UNPROTECTED_NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile));
1176
1177 io->fptr = 0;
1178
1179 return (VALUE)io;
1180}
1181
1182#ifndef S_ISREG
1183# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1184#endif
1185
1187 VALUE th;
1188 rb_io_t *fptr;
1189 int nonblock;
1190 int fd;
1191
1192 void *buf;
1193 size_t capa;
1194 struct timeval *timeout;
1195};
1196
1198 VALUE th;
1199 rb_io_t *fptr;
1200 int nonblock;
1201 int fd;
1202
1203 const void *buf;
1204 size_t capa;
1205 struct timeval *timeout;
1206};
1207
1208#ifdef HAVE_WRITEV
1209struct io_internal_writev_struct {
1210 VALUE th;
1211 rb_io_t *fptr;
1212 int nonblock;
1213 int fd;
1214
1215 int iovcnt;
1216 const struct iovec *iov;
1217 struct timeval *timeout;
1218};
1219#endif
1220
1221static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1222
1228static inline int
1229io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1230{
1231 if (!timeout && rb_thread_mn_schedulable(thread)) {
1232 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1233 return -1;
1234 }
1235
1236 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1237
1238 if (ready > 0) {
1239 return ready;
1240 }
1241 else if (ready == 0) {
1242 errno = ETIMEDOUT;
1243 return -1;
1244 }
1245
1246 // If there was an error BEFORE we started waiting, return it:
1247 if (error) {
1248 errno = error;
1249 return -1;
1250 }
1251 else {
1252 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1253 return ready;
1254 }
1255}
1256
1257static VALUE
1258internal_read_func(void *ptr)
1259{
1260 struct io_internal_read_struct *iis = ptr;
1261 ssize_t result;
1262
1263 if (iis->timeout && !iis->nonblock) {
1264 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1265 return -1;
1266 }
1267 }
1268
1269 retry:
1270 result = read(iis->fd, iis->buf, iis->capa);
1271
1272 if (result < 0 && !iis->nonblock) {
1273 if (io_again_p(errno)) {
1274 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1275 return -1;
1276 }
1277 else {
1278 goto retry;
1279 }
1280 }
1281 }
1282
1283 return result;
1284}
1285
1286#if defined __APPLE__
1287# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1288#else
1289# define do_write_retry(code) result = code
1290#endif
1291
1292static VALUE
1293internal_write_func(void *ptr)
1294{
1295 struct io_internal_write_struct *iis = ptr;
1296 ssize_t result;
1297
1298 if (iis->timeout && !iis->nonblock) {
1299 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1300 return -1;
1301 }
1302 }
1303
1304 retry:
1305 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1306
1307 if (result < 0 && !iis->nonblock) {
1308 int e = errno;
1309 if (io_again_p(e)) {
1310 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1311 return -1;
1312 }
1313 else {
1314 goto retry;
1315 }
1316 }
1317 }
1318
1319 return result;
1320}
1321
1322#ifdef HAVE_WRITEV
1323static VALUE
1324internal_writev_func(void *ptr)
1325{
1326 struct io_internal_writev_struct *iis = ptr;
1327 ssize_t result;
1328
1329 if (iis->timeout && !iis->nonblock) {
1330 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1331 return -1;
1332 }
1333 }
1334
1335 retry:
1336 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1337
1338 if (result < 0 && !iis->nonblock) {
1339 if (io_again_p(errno)) {
1340 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1341 return -1;
1342 }
1343 else {
1344 goto retry;
1345 }
1346 }
1347 }
1348
1349 return result;
1350}
1351#endif
1352
1353static ssize_t
1354rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1355{
1356 rb_thread_t *th = GET_THREAD();
1358 if (scheduler != Qnil) {
1359 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count);
1360
1361 if (!UNDEF_P(result)) {
1363 }
1364 }
1365
1366 struct io_internal_read_struct iis = {
1367 .th = th->self,
1368 .fptr = fptr,
1369 .nonblock = 0,
1370 .fd = fptr->fd,
1371
1372 .buf = buf,
1373 .capa = count,
1374 .timeout = NULL,
1375 };
1376
1377 struct timeval timeout_storage;
1378
1379 if (fptr->timeout != Qnil) {
1380 timeout_storage = rb_time_interval(fptr->timeout);
1381 iis.timeout = &timeout_storage;
1382 }
1383
1384 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1385}
1386
1387static ssize_t
1388rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1389{
1390 rb_thread_t *th = GET_THREAD();
1392 if (scheduler != Qnil) {
1393 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count);
1394
1395 if (!UNDEF_P(result)) {
1397 }
1398 }
1399
1400 struct io_internal_write_struct iis = {
1401 .th = th->self,
1402 .fptr = fptr,
1403 .nonblock = 0,
1404 .fd = fptr->fd,
1405
1406 .buf = buf,
1407 .capa = count,
1408 .timeout = NULL
1409 };
1410
1411 struct timeval timeout_storage;
1412
1413 if (fptr->timeout != Qnil) {
1414 timeout_storage = rb_time_interval(fptr->timeout);
1415 iis.timeout = &timeout_storage;
1416 }
1417
1418 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1419}
1420
1421#ifdef HAVE_WRITEV
1422static ssize_t
1423rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1424{
1425 if (!iovcnt) return 0;
1426
1427 rb_thread_t *th = GET_THREAD();
1428
1430 if (scheduler != Qnil) {
1431 // This path assumes at least one `iov`:
1432 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len);
1433
1434 if (!UNDEF_P(result)) {
1436 }
1437 }
1438
1439 struct io_internal_writev_struct iis = {
1440 .th = th->self,
1441 .fptr = fptr,
1442 .nonblock = 0,
1443 .fd = fptr->fd,
1444
1445 .iov = iov,
1446 .iovcnt = iovcnt,
1447 .timeout = NULL
1448 };
1449
1450 struct timeval timeout_storage;
1451
1452 if (fptr->timeout != Qnil) {
1453 timeout_storage = rb_time_interval(fptr->timeout);
1454 iis.timeout = &timeout_storage;
1455 }
1456
1457 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1458}
1459#endif
1460
1461static VALUE
1462io_flush_buffer_sync(void *arg)
1463{
1464 rb_io_t *fptr = arg;
1465 long l = fptr->wbuf.len;
1466 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1467
1468 if (fptr->wbuf.len <= r) {
1469 fptr->wbuf.off = 0;
1470 fptr->wbuf.len = 0;
1471 return 0;
1472 }
1473
1474 if (0 <= r) {
1475 fptr->wbuf.off += (int)r;
1476 fptr->wbuf.len -= (int)r;
1477 errno = EAGAIN;
1478 }
1479
1480 return (VALUE)-1;
1481}
1482
1483static inline VALUE
1484io_flush_buffer_fiber_scheduler(VALUE scheduler, rb_io_t *fptr)
1485{
1486 VALUE ret = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, fptr->wbuf.ptr+fptr->wbuf.off, fptr->wbuf.len);
1487 if (!UNDEF_P(ret)) {
1488 ssize_t result = rb_fiber_scheduler_io_result_apply(ret);
1489 if (result > 0) {
1490 fptr->wbuf.off += result;
1491 fptr->wbuf.len -= result;
1492 }
1493 return result >= 0 ? (VALUE)0 : (VALUE)-1;
1494 }
1495 return ret;
1496}
1497
1498static VALUE
1499io_flush_buffer_async(VALUE arg)
1500{
1501 rb_io_t *fptr = (rb_io_t *)arg;
1502
1503 VALUE scheduler = rb_fiber_scheduler_current();
1504 if (scheduler != Qnil) {
1505 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1506 if (!UNDEF_P(result)) {
1507 return result;
1508 }
1509 }
1510
1511 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1512}
1513
1514static inline int
1515io_flush_buffer(rb_io_t *fptr)
1516{
1517 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1518 return (int)io_flush_buffer_async((VALUE)fptr);
1519 }
1520 else {
1521 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1522 }
1523}
1524
1525static int
1526io_fflush(rb_io_t *fptr)
1527{
1528 rb_io_check_closed(fptr);
1529
1530 if (fptr->wbuf.len == 0)
1531 return 0;
1532
1533 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1534 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1535 return -1;
1536
1537 rb_io_check_closed(fptr);
1538 }
1539
1540 return 0;
1541}
1542
1543VALUE
1544rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1545{
1546 rb_thread_t *th = GET_THREAD();
1548
1549 if (scheduler != Qnil) {
1550 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1551 }
1552
1553 rb_io_t * fptr = NULL;
1554 RB_IO_POINTER(io, fptr);
1555
1556 struct timeval tv_storage;
1557 struct timeval *tv = NULL;
1558
1559 if (NIL_OR_UNDEF_P(timeout)) {
1560 timeout = fptr->timeout;
1561 }
1562
1563 if (timeout != Qnil) {
1564 tv_storage = rb_time_interval(timeout);
1565 tv = &tv_storage;
1566 }
1567
1568 int ready = rb_thread_io_wait(th, fptr, RB_NUM2INT(events), tv);
1569
1570 if (ready < 0) {
1571 rb_sys_fail(0);
1572 }
1573
1574 // Not sure if this is necessary:
1575 rb_io_check_closed(fptr);
1576
1577 if (ready) {
1578 return RB_INT2NUM(ready);
1579 }
1580 else {
1581 return Qfalse;
1582 }
1583}
1584
1585static VALUE
1586io_from_fd(int fd)
1587{
1588 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1589}
1590
1591static int
1592io_wait_for_single_fd(int fd, int events, struct timeval *timeout, rb_thread_t *th, VALUE scheduler)
1593{
1594 if (scheduler != Qnil) {
1595 return RTEST(
1596 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1597 );
1598 }
1599
1600 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1601}
1602
1603int
1605{
1606 io_fd_check_closed(f);
1607
1608 rb_thread_t *th = GET_THREAD();
1610
1611 switch (errno) {
1612 case EINTR:
1613#if defined(ERESTART)
1614 case ERESTART:
1615#endif
1617 return TRUE;
1618
1619 case EAGAIN:
1620#if EWOULDBLOCK != EAGAIN
1621 case EWOULDBLOCK:
1622#endif
1623 if (scheduler != Qnil) {
1624 return RTEST(
1625 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1626 );
1627 }
1628 else {
1629 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL, th, scheduler);
1630 }
1631 return TRUE;
1632
1633 default:
1634 return FALSE;
1635 }
1636}
1637
1638int
1640{
1641 io_fd_check_closed(f);
1642
1643 rb_thread_t *th = GET_THREAD();
1645
1646 switch (errno) {
1647 case EINTR:
1648#if defined(ERESTART)
1649 case ERESTART:
1650#endif
1651 /*
1652 * In old Linux, several special files under /proc and /sys don't handle
1653 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1654 * Otherwise, we face nasty hang up. Sigh.
1655 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1656 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1657 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1658 * Then rb_thread_check_ints() is enough.
1659 */
1661 return TRUE;
1662
1663 case EAGAIN:
1664#if EWOULDBLOCK != EAGAIN
1665 case EWOULDBLOCK:
1666#endif
1667 if (scheduler != Qnil) {
1668 return RTEST(
1669 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1670 );
1671 }
1672 else {
1673 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL, th, scheduler);
1674 }
1675 return TRUE;
1676
1677 default:
1678 return FALSE;
1679 }
1680}
1681
1682int
1683rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1684{
1685 rb_thread_t *th = GET_THREAD();
1687 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1688}
1689
1690int
1692{
1693 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1694}
1695
1696int
1698{
1699 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1700}
1701
1702VALUE
1703rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1704{
1705 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1706 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1707 // instead relies on `read(-1) -> -1` which causes this code path. We then
1708 // check here whether the IO was in fact closed. Probably it's better to
1709 // check that `fptr->fd != -1` before using it in syscall.
1710 rb_io_check_closed(RFILE(io)->fptr);
1711
1712 switch (error) {
1713 // In old Linux, several special files under /proc and /sys don't handle
1714 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1715 // Otherwise, we face nasty hang up. Sigh.
1716 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1717 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1718 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1719 // Then rb_thread_check_ints() is enough.
1720 case EINTR:
1721#if defined(ERESTART)
1722 case ERESTART:
1723#endif
1724 // We might have pending interrupts since the previous syscall was interrupted:
1726
1727 // The operation was interrupted, so retry it immediately:
1728 return events;
1729
1730 case EAGAIN:
1731#if EWOULDBLOCK != EAGAIN
1732 case EWOULDBLOCK:
1733#endif
1734 // The operation would block, so wait for the specified events:
1735 return rb_io_wait(io, events, timeout);
1736
1737 default:
1738 // Non-specific error, no event is ready:
1739 return Qnil;
1740 }
1741}
1742
1743int
1745{
1746 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1747
1748 if (RTEST(result)) {
1749 return RB_NUM2INT(result);
1750 }
1751 else if (result == RUBY_Qfalse) {
1752 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1753 }
1754
1755 return 0;
1756}
1757
1758int
1760{
1761 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1762
1763 if (RTEST(result)) {
1764 return RB_NUM2INT(result);
1765 }
1766 else if (result == RUBY_Qfalse) {
1767 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1768 }
1769
1770 return 0;
1771}
1772
1773static void
1774make_writeconv(rb_io_t *fptr)
1775{
1776 if (!fptr->writeconv_initialized) {
1777 const char *senc, *denc;
1778 rb_encoding *enc;
1779 int ecflags;
1780 VALUE ecopts;
1781
1782 fptr->writeconv_initialized = 1;
1783
1784 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1785 ecopts = fptr->encs.ecopts;
1786
1787 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1788 /* no encoding conversion */
1789 fptr->writeconv_pre_ecflags = 0;
1790 fptr->writeconv_pre_ecopts = Qnil;
1791 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1792 if (!fptr->writeconv)
1793 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1795 }
1796 else {
1797 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1798 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1799 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1800 /* single conversion */
1801 fptr->writeconv_pre_ecflags = ecflags;
1802 fptr->writeconv_pre_ecopts = ecopts;
1803 fptr->writeconv = NULL;
1805 }
1806 else {
1807 /* double conversion */
1808 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1809 fptr->writeconv_pre_ecopts = ecopts;
1810 if (senc) {
1811 denc = rb_enc_name(enc);
1812 fptr->writeconv_asciicompat = rb_str_new2(senc);
1813 }
1814 else {
1815 senc = denc = "";
1816 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1817 }
1819 ecopts = fptr->encs.ecopts;
1820 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1821 if (!fptr->writeconv)
1822 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1823 }
1824 }
1825 }
1826}
1827
1828/* writing functions */
1830 rb_io_t *fptr;
1831 const char *ptr;
1832 long length;
1833};
1834
1836 VALUE io;
1837 VALUE str;
1838 int nosync;
1839};
1840
1841#ifdef HAVE_WRITEV
1842static ssize_t
1843io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1844{
1845 if (fptr->wbuf.len) {
1846 struct iovec iov[2];
1847
1848 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1849 iov[0].iov_len = fptr->wbuf.len;
1850 iov[1].iov_base = (void*)ptr;
1851 iov[1].iov_len = length;
1852
1853 ssize_t result = rb_writev_internal(fptr, iov, 2);
1854
1855 if (result < 0)
1856 return result;
1857
1858 if (result >= fptr->wbuf.len) {
1859 // We wrote more than the internal buffer:
1860 result -= fptr->wbuf.len;
1861 fptr->wbuf.off = 0;
1862 fptr->wbuf.len = 0;
1863 }
1864 else {
1865 // We only wrote less data than the internal buffer:
1866 fptr->wbuf.off += (int)result;
1867 fptr->wbuf.len -= (int)result;
1868
1869 result = 0;
1870 }
1871
1872 return result;
1873 }
1874 else {
1875 return rb_io_write_memory(fptr, ptr, length);
1876 }
1877}
1878#else
1879static ssize_t
1880io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1881{
1882 long remaining = length;
1883
1884 if (fptr->wbuf.len) {
1885 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1886 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1887 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1888 fptr->wbuf.off = 0;
1889 }
1890
1891 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1892 fptr->wbuf.len += (int)length;
1893
1894 // We copied the entire incoming data to the internal buffer:
1895 remaining = 0;
1896 }
1897
1898 // Flush the internal buffer:
1899 if (io_fflush(fptr) < 0) {
1900 return -1;
1901 }
1902
1903 // If all the data was buffered, we are done:
1904 if (remaining == 0) {
1905 return length;
1906 }
1907 }
1908
1909 // Otherwise, we should write the data directly:
1910 return rb_io_write_memory(fptr, ptr, length);
1911}
1912#endif
1913
1914static VALUE
1915io_binwrite_string(VALUE arg)
1916{
1917 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1918
1919 const char *ptr = p->ptr;
1920 size_t remaining = p->length;
1921
1922 while (remaining) {
1923 // Write as much as possible:
1924 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1925
1926 if (result == 0) {
1927 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1928 // should try again immediately.
1929 }
1930 else if (result > 0) {
1931 if ((size_t)result == remaining) break;
1932 ptr += result;
1933 remaining -= result;
1934 }
1935 // Wait for it to become writable:
1936 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1937 rb_io_check_closed(p->fptr);
1938 }
1939 else {
1940 // The error was unrelated to waiting for it to become writable, so we fail:
1941 return -1;
1942 }
1943 }
1944
1945 return p->length;
1946}
1947
1948inline static void
1949io_allocate_write_buffer(rb_io_t *fptr, int sync)
1950{
1951 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1952 fptr->wbuf.off = 0;
1953 fptr->wbuf.len = 0;
1954 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1955 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1956 }
1957
1958 if (NIL_P(fptr->write_lock)) {
1959 fptr->write_lock = rb_mutex_new();
1960 rb_mutex_allow_trap(fptr->write_lock, 1);
1961 }
1962}
1963
1964static inline int
1965io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1966{
1967 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1968 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1969 return 1;
1970
1971 // If the amount of data we want to write exceeds the internal buffer:
1972 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1973 return 1;
1974
1975 // Otherwise, we can append to the internal buffer:
1976 return 0;
1977}
1978
1979static long
1980io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1981{
1982 if (len <= 0) return len;
1983
1984 // Don't write anything if current thread has a pending interrupt:
1986
1987 io_allocate_write_buffer(fptr, !nosync);
1988
1989 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1990 struct binwrite_arg arg;
1991
1992 arg.fptr = fptr;
1993 arg.ptr = ptr;
1994 arg.length = len;
1995
1996 if (!NIL_P(fptr->write_lock)) {
1997 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1998 }
1999 else {
2000 return io_binwrite_string((VALUE)&arg);
2001 }
2002 }
2003 else {
2004 if (fptr->wbuf.off) {
2005 if (fptr->wbuf.len)
2006 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
2007 fptr->wbuf.off = 0;
2008 }
2009
2010 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
2011 fptr->wbuf.len += (int)len;
2012
2013 return len;
2014 }
2015}
2016
2017# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
2018 (fmode & FMODE_TEXTMODE) ? (c) : (a))
2019
2020#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
2021 MODE_BTMODE(d, e, f) : \
2022 MODE_BTMODE(a, b, c))
2023
2024static VALUE
2025do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
2026{
2027 if (NEED_WRITECONV(fptr)) {
2028 VALUE common_encoding = Qnil;
2029 SET_BINARY_MODE(fptr);
2030
2031 make_writeconv(fptr);
2032
2033 if (fptr->writeconv) {
2034#define fmode (fptr->mode)
2035 if (!NIL_P(fptr->writeconv_asciicompat))
2036 common_encoding = fptr->writeconv_asciicompat;
2037 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
2038 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2039 rb_enc_name(rb_enc_get(str)));
2040 }
2041#undef fmode
2042 }
2043 else {
2044 if (fptr->encs.enc2)
2045 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
2046 else if (fptr->encs.enc != rb_ascii8bit_encoding())
2047 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
2048 }
2049
2050 if (!NIL_P(common_encoding)) {
2051 str = rb_str_encode(str, common_encoding,
2053 *converted = 1;
2054 }
2055
2056 if (fptr->writeconv) {
2058 *converted = 1;
2059 }
2060 }
2061#if RUBY_CRLF_ENVIRONMENT
2062#define fmode (fptr->mode)
2063 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2064 if ((fptr->mode & FMODE_READABLE) &&
2066 setmode(fptr->fd, O_BINARY);
2067 }
2068 else {
2069 setmode(fptr->fd, O_TEXT);
2070 }
2071 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2072 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2073 rb_enc_name(rb_enc_get(str)));
2074 }
2075 }
2076#undef fmode
2077#endif
2078 return str;
2079}
2080
2081static long
2082io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
2083{
2084 int converted = 0;
2085 VALUE tmp;
2086 long n, len;
2087 const char *ptr;
2088
2089#ifdef _WIN32
2090 if (fptr->mode & FMODE_TTY) {
2091 long len = rb_w32_write_console(str, fptr->fd);
2092 if (len > 0) return len;
2093 }
2094#endif
2095
2096 str = do_writeconv(str, fptr, &converted);
2097 if (converted)
2098 OBJ_FREEZE(str);
2099
2100 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2101 RSTRING_GETMEM(tmp, ptr, len);
2102 n = io_binwrite(ptr, len, fptr, nosync);
2103 rb_str_tmp_frozen_release(str, tmp);
2104
2105 return n;
2106}
2107
2108ssize_t
2109rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2110{
2111 rb_io_t *fptr;
2112
2113 GetOpenFile(io, fptr);
2115 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2116}
2117
2118static VALUE
2119io_write(VALUE io, VALUE str, int nosync)
2120{
2121 rb_io_t *fptr;
2122 long n;
2123 VALUE tmp;
2124
2125 io = GetWriteIO(io);
2126 str = rb_obj_as_string(str);
2127 tmp = rb_io_check_io(io);
2128
2129 if (NIL_P(tmp)) {
2130 /* port is not IO, call write method for it. */
2131 return rb_funcall(io, id_write, 1, str);
2132 }
2133
2134 io = tmp;
2135 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2136
2137 GetOpenFile(io, fptr);
2139
2140 n = io_fwrite(str, fptr, nosync);
2141 if (n < 0L) rb_sys_fail_on_write(fptr);
2142
2143 return LONG2FIX(n);
2144}
2145
2146#ifdef HAVE_WRITEV
2147struct binwritev_arg {
2148 rb_io_t *fptr;
2149 struct iovec *iov;
2150 int iovcnt;
2151 size_t total;
2152};
2153
2154static VALUE
2155io_binwritev_internal(VALUE arg)
2156{
2157 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2158
2159 size_t remaining = p->total;
2160 size_t offset = 0;
2161
2162 rb_io_t *fptr = p->fptr;
2163 struct iovec *iov = p->iov;
2164 int iovcnt = p->iovcnt;
2165
2166 while (remaining) {
2167 long result = rb_writev_internal(fptr, iov, iovcnt);
2168
2169 if (result >= 0) {
2170 offset += result;
2171 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2172 if (offset < (size_t)fptr->wbuf.len) {
2173 fptr->wbuf.off += result;
2174 fptr->wbuf.len -= result;
2175 }
2176 else {
2177 offset -= (size_t)fptr->wbuf.len;
2178 fptr->wbuf.off = 0;
2179 fptr->wbuf.len = 0;
2180 }
2181 }
2182
2183 if (offset == p->total) {
2184 return p->total;
2185 }
2186
2187 while (result >= (ssize_t)iov->iov_len) {
2188 /* iovcnt > 0 */
2189 result -= iov->iov_len;
2190 iov->iov_len = 0;
2191 iov++;
2192
2193 if (!--iovcnt) {
2194 // I don't believe this code path can ever occur.
2195 return offset;
2196 }
2197 }
2198
2199 iov->iov_base = (char *)iov->iov_base + result;
2200 iov->iov_len -= result;
2201 }
2202 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2203 rb_io_check_closed(fptr);
2204 }
2205 else {
2206 return -1;
2207 }
2208 }
2209
2210 return offset;
2211}
2212
2213static long
2214io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2215{
2216 // Don't write anything if current thread has a pending interrupt:
2218
2219 if (iovcnt == 0) return 0;
2220
2221 size_t total = 0;
2222 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2223
2224 io_allocate_write_buffer(fptr, 1);
2225
2226 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2227 // The end of the buffered data:
2228 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2229
2230 if (offset + total <= (size_t)fptr->wbuf.capa) {
2231 for (int i = 1; i < iovcnt; i++) {
2232 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2233 offset += iov[i].iov_len;
2234 }
2235
2236 fptr->wbuf.len += total;
2237
2238 /* io_binwritev is only reached in sync/TTY mode (it is called only
2239 * from io_fwritev, which io_writev uses only when FMODE_SYNC or
2240 * FMODE_TTY is set), so the coalesced data must be flushed
2241 * immediately rather than left in the buffer until the next flush
2242 * or close. Otherwise a multi-argument write with many arguments
2243 * would not be observably atomic under sync. */
2244 if (io_fflush(fptr) < 0) return -1;
2245
2246 return total;
2247 }
2248 else {
2249 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2250 iov[0].iov_len = fptr->wbuf.len;
2251 }
2252 }
2253 else {
2254 // The first iov is reserved for the internal buffer, and it's empty.
2255 iov++;
2256
2257 if (!--iovcnt) {
2258 // If there are no other io vectors we are done.
2259 return 0;
2260 }
2261 }
2262
2263 struct binwritev_arg arg;
2264 arg.fptr = fptr;
2265 arg.iov = iov;
2266 arg.iovcnt = iovcnt;
2267 arg.total = total;
2268
2269 if (!NIL_P(fptr->write_lock)) {
2270 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2271 }
2272 else {
2273 return io_binwritev_internal((VALUE)&arg);
2274 }
2275}
2276
2277static long
2278io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2279{
2280 int i, converted, iovcnt = argc + 1;
2281 long n;
2282 VALUE v1, v2, str, tmp, *tmp_array;
2283 struct iovec *iov;
2284
2285 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2286 tmp_array = ALLOCV_N(VALUE, v2, argc);
2287
2288 for (i = 0; i < argc; i++) {
2289 str = rb_obj_as_string(argv[i]);
2290 converted = 0;
2291 str = do_writeconv(str, fptr, &converted);
2292
2293 if (converted)
2294 OBJ_FREEZE(str);
2295
2296 tmp = rb_str_tmp_frozen_acquire(str);
2297 tmp_array[i] = tmp;
2298
2299 /* iov[0] is reserved for buffer of fptr */
2300 iov[i+1].iov_base = RSTRING_PTR(tmp);
2301 iov[i+1].iov_len = RSTRING_LEN(tmp);
2302 }
2303
2304 n = io_binwritev(iov, iovcnt, fptr);
2305 if (v1) ALLOCV_END(v1);
2306
2307 for (i = 0; i < argc; i++) {
2308 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2309 }
2310
2311 if (v2) ALLOCV_END(v2);
2312
2313 return n;
2314}
2315
2316static int
2317iovcnt_ok(int iovcnt)
2318{
2319#ifdef IOV_MAX
2320 return iovcnt < IOV_MAX;
2321#else /* GNU/Hurd has writev, but no IOV_MAX */
2322 return 1;
2323#endif
2324}
2325#endif /* HAVE_WRITEV */
2326
2327static VALUE
2328io_writev(int argc, const VALUE *argv, VALUE io)
2329{
2330 rb_io_t *fptr;
2331 long n;
2332 VALUE tmp, total = INT2FIX(0);
2333 int i, cnt = 1;
2334
2335 io = GetWriteIO(io);
2336 tmp = rb_io_check_io(io);
2337
2338 if (NIL_P(tmp)) {
2339 /* port is not IO, call write method for it. */
2340 return rb_funcallv(io, id_write, argc, argv);
2341 }
2342
2343 io = tmp;
2344
2345 GetOpenFile(io, fptr);
2347
2348 for (i = 0; i < argc; i += cnt) {
2349#ifdef HAVE_WRITEV
2350 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2351 n = io_fwritev(cnt, &argv[i], fptr);
2352 }
2353 else
2354#endif
2355 {
2356 cnt = 1;
2357 /* sync at last item */
2358 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2359 }
2360
2361 if (n < 0L)
2362 rb_sys_fail_on_write(fptr);
2363
2364 total = rb_fix_plus(LONG2FIX(n), total);
2365 }
2366
2367 return total;
2368}
2369
2370/*
2371 * call-seq:
2372 * write(*objects) -> integer
2373 *
2374 * Writes each of the given +objects+ to +self+,
2375 * which must be opened for writing
2376 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2377 * returns the total number bytes written;
2378 * each of +objects+ that is not a string is converted via method +to_s+:
2379 *
2380 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2381 * $stdout.write('foo', :bar, 2, "\n") # => 8
2382 *
2383 * Output:
2384 *
2385 * Hello, World!
2386 * foobar2
2387 *
2388 * Related: IO#read.
2389 */
2390
2391static VALUE
2392io_write_m(int argc, VALUE *argv, VALUE io)
2393{
2394 if (argc != 1) {
2395 return io_writev(argc, argv, io);
2396 }
2397 else {
2398 VALUE str = argv[0];
2399 return io_write(io, str, 0);
2400 }
2401}
2402
2403VALUE
2404rb_io_write(VALUE io, VALUE str)
2405{
2406 return rb_funcallv(io, id_write, 1, &str);
2407}
2408
2409static VALUE
2410rb_io_writev(VALUE io, int argc, const VALUE *argv)
2411{
2412 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2413 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2414 VALUE klass = CLASS_OF(io);
2415 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2417 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2418 " which accepts just one argument",
2419 klass, sep
2420 );
2421 }
2422
2423 do rb_io_write(io, *argv++); while (--argc);
2424
2425 return Qnil;
2426 }
2427
2428 return rb_funcallv(io, id_write, argc, argv);
2429}
2430
2431/*
2432 * call-seq:
2433 * self << object -> self
2434 *
2435 * Writes the given +object+ to +self+,
2436 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2437 * returns +self+;
2438 * if +object+ is not a string, it is converted via method +to_s+:
2439 *
2440 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2441 * $stdout << 'foo' << :bar << 2 << "\n"
2442 *
2443 * Output:
2444 *
2445 * Hello, World!
2446 * foobar2
2447 *
2448 */
2449
2450
2451VALUE
2453{
2454 rb_io_write(io, str);
2455 return io;
2456}
2457
2458#ifdef HAVE_FSYNC
2459static VALUE
2460nogvl_fsync(void *ptr)
2461{
2462 rb_io_t *fptr = ptr;
2463
2464#ifdef _WIN32
2465 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2466 return 0;
2467#endif
2468 return (VALUE)fsync(fptr->fd);
2469}
2470#endif
2471
2472VALUE
2473rb_io_flush_raw(VALUE io, int sync)
2474{
2475 rb_io_t *fptr;
2476
2477 if (!RB_TYPE_P(io, T_FILE)) {
2478 return rb_funcall(io, id_flush, 0);
2479 }
2480
2481 io = GetWriteIO(io);
2482 GetOpenFile(io, fptr);
2483
2484 if (fptr->mode & FMODE_WRITABLE) {
2485 if (io_fflush(fptr) < 0)
2486 rb_sys_fail_on_write(fptr);
2487 }
2488 if (fptr->mode & FMODE_READABLE) {
2489 io_unread(fptr, true);
2490 }
2491
2492 return io;
2493}
2494
2495/*
2496 * call-seq:
2497 * flush -> self
2498 *
2499 * Flushes data buffered in +self+ to the operating system
2500 * (but does not necessarily flush data buffered in the operating system):
2501 *
2502 * $stdout.print 'no newline' # Not necessarily flushed.
2503 * $stdout.flush # Flushed.
2504 *
2505 */
2506
2507VALUE
2508rb_io_flush(VALUE io)
2509{
2510 return rb_io_flush_raw(io, 1);
2511}
2512
2513/*
2514 * call-seq:
2515 * tell -> integer
2516 *
2517 * Returns the current position (in bytes) in +self+
2518 * (see {Position}[rdoc-ref:IO@Position]):
2519 *
2520 * f = File.open('t.txt')
2521 * f.tell # => 0
2522 * f.gets # => "First line\n"
2523 * f.tell # => 12
2524 * f.close
2525 *
2526 * Related: IO#pos=, IO#seek.
2527 */
2528
2529static VALUE
2530rb_io_tell(VALUE io)
2531{
2532 rb_io_t *fptr;
2533 rb_off_t pos;
2534
2535 GetOpenFile(io, fptr);
2536 pos = io_tell(fptr);
2537 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2538 pos -= fptr->rbuf.len;
2539 return OFFT2NUM(pos);
2540}
2541
2542static VALUE
2543rb_io_seek(VALUE io, VALUE offset, int whence)
2544{
2545 rb_io_t *fptr;
2546 rb_off_t pos;
2547
2548 pos = NUM2OFFT(offset);
2549 GetOpenFile(io, fptr);
2550 pos = io_seek(fptr, pos, whence);
2551 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2552 if (fptr->readconv) clear_readconv(fptr);
2553
2554 return INT2FIX(0);
2555}
2556
2557static int
2558interpret_seek_whence(VALUE vwhence)
2559{
2560 if (vwhence == sym_SET)
2561 return SEEK_SET;
2562 if (vwhence == sym_CUR)
2563 return SEEK_CUR;
2564 if (vwhence == sym_END)
2565 return SEEK_END;
2566#ifdef SEEK_DATA
2567 if (vwhence == sym_DATA)
2568 return SEEK_DATA;
2569#endif
2570#ifdef SEEK_HOLE
2571 if (vwhence == sym_HOLE)
2572 return SEEK_HOLE;
2573#endif
2574 return NUM2INT(vwhence);
2575}
2576
2577/*
2578 * call-seq:
2579 * seek(offset, whence = IO::SEEK_SET) -> 0
2580 *
2581 * Seeks to the position given by integer +offset+
2582 * (see {Position}[rdoc-ref:IO@Position])
2583 * and constant +whence+, which is one of:
2584 *
2585 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2586 * Repositions the stream to its current position plus the given +offset+:
2587 *
2588 * f = File.open('t.txt')
2589 * f.tell # => 0
2590 * f.seek(20, :CUR) # => 0
2591 * f.tell # => 20
2592 * f.seek(-10, :CUR) # => 0
2593 * f.tell # => 10
2594 * f.close
2595 *
2596 * - +:END+ or <tt>IO::SEEK_END</tt>:
2597 * Repositions the stream to its end plus the given +offset+:
2598 *
2599 * f = File.open('t.txt')
2600 * f.tell # => 0
2601 * f.seek(0, :END) # => 0 # Repositions to stream end.
2602 * f.tell # => 52
2603 * f.seek(-20, :END) # => 0
2604 * f.tell # => 32
2605 * f.seek(-40, :END) # => 0
2606 * f.tell # => 12
2607 * f.close
2608 *
2609 * - +:SET+ or <tt>IO::SEEK_SET</tt>:
2610 * Repositions the stream to the given +offset+:
2611 *
2612 * f = File.open('t.txt')
2613 * f.tell # => 0
2614 * f.seek(20, :SET) # => 0
2615 * f.tell # => 20
2616 * f.seek(40, :SET) # => 0
2617 * f.tell # => 40
2618 * f.close
2619 *
2620 * Related: IO#pos=, IO#tell.
2621 *
2622 */
2623
2624static VALUE
2625rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2626{
2627 VALUE offset, ptrname;
2628 int whence = SEEK_SET;
2629
2630 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2631 whence = interpret_seek_whence(ptrname);
2632 }
2633
2634 return rb_io_seek(io, offset, whence);
2635}
2636
2637/*
2638 * call-seq:
2639 * pos = new_position -> new_position
2640 *
2641 * Seeks to the given +new_position+ (in bytes);
2642 * see {Position}[rdoc-ref:IO@Position]:
2643 *
2644 * f = File.open('t.txt')
2645 * f.tell # => 0
2646 * f.pos = 20 # => 20
2647 * f.tell # => 20
2648 * f.close
2649 *
2650 * Related: IO#seek, IO#tell.
2651 *
2652 */
2653
2654static VALUE
2655rb_io_set_pos(VALUE io, VALUE offset)
2656{
2657 rb_io_t *fptr;
2658 rb_off_t pos;
2659
2660 pos = NUM2OFFT(offset);
2661 GetOpenFile(io, fptr);
2662 pos = io_seek(fptr, pos, SEEK_SET);
2663 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2664 if (fptr->readconv) clear_readconv(fptr);
2665
2666 return OFFT2NUM(pos);
2667}
2668
2669/*
2670 * call-seq:
2671 * rewind -> 0
2672 *
2673 * Repositions the stream to its beginning,
2674 * setting both the position and the line number to zero;
2675 * see {Position}[rdoc-ref:IO@Position]
2676 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2677 *
2678 * f = File.open('t.txt')
2679 * f.tell # => 0
2680 * f.lineno # => 0
2681 * f.gets # => "First line\n"
2682 * f.tell # => 12
2683 * f.lineno # => 1
2684 * f.rewind # => 0
2685 * f.tell # => 0
2686 * f.lineno # => 0
2687 * f.close
2688 *
2689 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2690 *
2691 */
2692
2693static VALUE
2694rb_io_rewind(VALUE io)
2695{
2696 rb_io_t *fptr;
2697
2698 GetOpenFile(io, fptr);
2699 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2700 if (io == ARGF.current_file) {
2701 ARGF.lineno -= fptr->lineno;
2702 }
2703 fptr->lineno = 0;
2704 if (fptr->readconv) {
2705 clear_readconv(fptr);
2706 }
2707
2708 return INT2FIX(0);
2709}
2710
2711static int
2712fptr_wait_readable(rb_io_t *fptr)
2713{
2714 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2715
2716 if (result)
2717 rb_io_check_closed(fptr);
2718
2719 return result;
2720}
2721
2722static int
2723io_fillbuf(rb_io_t *fptr)
2724{
2725 ssize_t r;
2726
2727 if (fptr->rbuf.ptr == NULL) {
2728 fptr->rbuf.off = 0;
2729 fptr->rbuf.len = 0;
2730 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2731 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2732 }
2733 if (fptr->rbuf.len == 0) {
2734 retry:
2735 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2736
2737 if (r < 0) {
2738 if (fptr_wait_readable(fptr))
2739 goto retry;
2740
2741 int e = errno;
2742 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2743 if (!NIL_P(fptr->pathv)) {
2744 rb_str_append(path, fptr->pathv);
2745 }
2746
2747 rb_syserr_fail_path(e, path);
2748 }
2749 if (r > 0) rb_io_check_closed(fptr);
2750 fptr->rbuf.off = 0;
2751 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2752 if (r == 0)
2753 return -1; /* EOF */
2754 }
2755 return 0;
2756}
2757
2758/*
2759 * call-seq:
2760 * eof -> true or false
2761 *
2762 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2763 * see {Position}[rdoc-ref:IO@Position]:
2764 *
2765 * f = File.open('t.txt')
2766 * f.eof # => false
2767 * f.seek(0, :END) # => 0
2768 * f.eof # => true
2769 * f.close
2770 *
2771 * Raises an exception unless the stream is opened for reading;
2772 * see {Mode}[rdoc-ref:File@Access+Modes].
2773 *
2774 * If +self+ is a stream such as pipe or socket, this method
2775 * blocks until the other end sends some data or closes it:
2776 *
2777 * r, w = IO.pipe
2778 * Thread.new { sleep 1; w.close }
2779 * r.eof? # => true # After 1-second wait.
2780 *
2781 * r, w = IO.pipe
2782 * Thread.new { sleep 1; w.puts "a" }
2783 * r.eof? # => false # After 1-second wait.
2784 *
2785 * r, w = IO.pipe
2786 * r.eof? # blocks forever
2787 *
2788 * Note that this method reads data to the input byte buffer. So
2789 * IO#sysread may not behave as you intend with IO#eof?, unless you
2790 * call IO#rewind first (which is not available for some streams).
2791 */
2792
2793VALUE
2795{
2796 rb_io_t *fptr;
2797
2798 GetOpenFile(io, fptr);
2800
2801 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2802 if (READ_DATA_PENDING(fptr)) return Qfalse;
2803 READ_CHECK(fptr);
2804#if RUBY_CRLF_ENVIRONMENT
2805 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2806 return RBOOL(eof(fptr->fd));
2807 }
2808#endif
2809 return RBOOL(io_fillbuf(fptr) < 0);
2810}
2811
2812/*
2813 * call-seq:
2814 * sync -> true or false
2815 *
2816 * Returns the current sync mode of the stream.
2817 * When sync mode is true, all output is immediately flushed to the underlying
2818 * operating system and is not buffered by Ruby internally. See also #fsync.
2819 *
2820 * f = File.open('t.tmp', 'w')
2821 * f.sync # => false
2822 * f.sync = true
2823 * f.sync # => true
2824 * f.close
2825 *
2826 */
2827
2828static VALUE
2829rb_io_sync(VALUE io)
2830{
2831 rb_io_t *fptr;
2832
2833 io = GetWriteIO(io);
2834 GetOpenFile(io, fptr);
2835 return RBOOL(fptr->mode & FMODE_SYNC);
2836}
2837
2838#ifdef HAVE_FSYNC
2839
2840/*
2841 * call-seq:
2842 * sync = boolean -> boolean
2843 *
2844 * Sets the _sync_ _mode_ for the stream to the given value;
2845 * returns the given value.
2846 *
2847 * Values for the sync mode:
2848 *
2849 * - +true+: All output is immediately flushed to the
2850 * underlying operating system and is not buffered internally.
2851 * - +false+: Output may be buffered internally.
2852 *
2853 * Example;
2854 *
2855 * f = File.open('t.tmp', 'w')
2856 * f.sync # => false
2857 * f.sync = true
2858 * f.sync # => true
2859 * f.close
2860 *
2861 * Related: IO#fsync.
2862 *
2863 */
2864
2865static VALUE
2866rb_io_set_sync(VALUE io, VALUE sync)
2867{
2868 rb_io_t *fptr;
2869
2870 io = GetWriteIO(io);
2871 GetOpenFile(io, fptr);
2872 if (RTEST(sync)) {
2873 fptr->mode |= FMODE_SYNC;
2874 }
2875 else {
2876 fptr->mode &= ~FMODE_SYNC;
2877 }
2878 return sync;
2879}
2880
2881/*
2882 * call-seq:
2883 * fsync -> 0
2884 *
2885 * Immediately writes to disk all data buffered in the stream,
2886 * via the operating system's <tt>fsync(2)</tt>.
2887
2888 * Note this difference:
2889 *
2890 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2891 * but does not guarantee that the operating system actually writes the data to disk.
2892 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2893 * and that data is written to disk.
2894 *
2895 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2896 *
2897 */
2898
2899static VALUE
2900rb_io_fsync(VALUE io)
2901{
2902 rb_io_t *fptr;
2903
2904 io = GetWriteIO(io);
2905 GetOpenFile(io, fptr);
2906
2907 if (io_fflush(fptr) < 0)
2908 rb_sys_fail_on_write(fptr);
2909
2910 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2911 rb_sys_fail_path(fptr->pathv);
2912
2913 return INT2FIX(0);
2914}
2915#else
2916# define rb_io_fsync rb_f_notimplement
2917# define rb_io_sync rb_f_notimplement
2918static VALUE
2919rb_io_set_sync(VALUE io, VALUE sync)
2920{
2921 rb_notimplement();
2923}
2924#endif
2925
2926#ifdef HAVE_FDATASYNC
2927static VALUE
2928nogvl_fdatasync(void *ptr)
2929{
2930 rb_io_t *fptr = ptr;
2931
2932 return (VALUE)fdatasync(fptr->fd);
2933}
2934
2935/*
2936 * call-seq:
2937 * fdatasync -> 0
2938 *
2939 * Immediately writes to disk all data buffered in the stream,
2940 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2941 * otherwise via <tt>fsync(2)</tt>, if supported;
2942 * otherwise raises an exception.
2943 *
2944 */
2945
2946static VALUE
2947rb_io_fdatasync(VALUE io)
2948{
2949 rb_io_t *fptr;
2950
2951 io = GetWriteIO(io);
2952 GetOpenFile(io, fptr);
2953
2954 if (io_fflush(fptr) < 0)
2955 rb_sys_fail_on_write(fptr);
2956
2957 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2958 return INT2FIX(0);
2959
2960 /* fall back */
2961 return rb_io_fsync(io);
2962}
2963#else
2964#define rb_io_fdatasync rb_io_fsync
2965#endif
2966
2967/*
2968 * call-seq:
2969 * fileno -> integer
2970 *
2971 * Returns the integer file descriptor for the stream:
2972 *
2973 * $stdin.fileno # => 0
2974 * $stdout.fileno # => 1
2975 * $stderr.fileno # => 2
2976 * File.open('t.txt').fileno # => 10
2977 * f.close
2978 *
2979 */
2980
2981static VALUE
2982rb_io_fileno(VALUE io)
2983{
2984 rb_io_t *fptr = RFILE(io)->fptr;
2985 int fd;
2986
2987 rb_io_check_closed(fptr);
2988 fd = fptr->fd;
2989 return INT2FIX(fd);
2990}
2991
2992int
2994{
2995 if (RB_TYPE_P(io, T_FILE)) {
2996 rb_io_t *fptr = RFILE(io)->fptr;
2997 rb_io_check_closed(fptr);
2998 return fptr->fd;
2999 }
3000 else {
3001 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
3002 if (!UNDEF_P(fileno)) {
3003 return RB_NUM2INT(fileno);
3004 }
3005 }
3006
3007 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
3008
3010}
3011
3012int
3013rb_io_mode(VALUE io)
3014{
3015 rb_io_t *fptr;
3016 GetOpenFile(io, fptr);
3017 return fptr->mode;
3018}
3019
3020/*
3021 * call-seq:
3022 * pid -> integer or nil
3023 *
3024 * Returns the process ID of a child process associated with the stream,
3025 * which will have been set by IO#popen, or +nil+ if the stream was not
3026 * created by IO#popen:
3027 *
3028 * pipe = IO.popen("-")
3029 * if pipe
3030 * $stderr.puts "In parent, child pid is #{pipe.pid}"
3031 * else
3032 * $stderr.puts "In child, pid is #{$$}"
3033 * end
3034 *
3035 * Output:
3036 *
3037 * In child, pid is 26209
3038 * In parent, child pid is 26209
3039 *
3040 */
3041
3042static VALUE
3043rb_io_pid(VALUE io)
3044{
3045 rb_io_t *fptr;
3046
3047 GetOpenFile(io, fptr);
3048 if (!fptr->pid)
3049 return Qnil;
3050 return PIDT2NUM(fptr->pid);
3051}
3052
3053/*
3054 * :markup: markdown
3055 *
3056 * call-seq:
3057 * path -> string or nil
3058 *
3059 * Returns the string path associated with `self`,
3060 * or `nil` if there is no associated path:
3061 *
3062 * ```ruby
3063 * path = 'doc/maintainers.md'
3064 * fd = File.open(path).fileno # => 6
3065 * IO.new(fd, path: path).path # => "doc/maintainers.md"
3066 * IO.new(fd).path # => nil
3067 * ```
3068 *
3069 */
3070
3071VALUE
3073{
3074 rb_io_t *fptr = RFILE(io)->fptr;
3075
3076 if (!fptr)
3077 return Qnil;
3078
3079 return rb_obj_dup(fptr->pathv);
3080}
3081
3082/*
3083 * call-seq:
3084 * inspect -> string
3085 *
3086 * Returns a string representation of +self+:
3087 *
3088 * f = File.open('t.txt')
3089 * f.inspect # => "#<File:t.txt>"
3090 * f.close
3091 *
3092 */
3093
3094static VALUE
3095rb_io_inspect(VALUE obj)
3096{
3097 rb_io_t *fptr;
3098 VALUE result;
3099 static const char closed[] = " (closed)";
3100
3101 fptr = RFILE(obj)->fptr;
3102 if (!fptr) return rb_any_to_s(obj);
3103 result = rb_str_new_cstr("#<");
3104 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3105 rb_str_cat2(result, ":");
3106 if (NIL_P(fptr->pathv)) {
3107 if (fptr->fd < 0) {
3108 rb_str_cat(result, closed+1, strlen(closed)-1);
3109 }
3110 else {
3111 rb_str_catf(result, "fd %d", fptr->fd);
3112 }
3113 }
3114 else {
3115 rb_str_append(result, fptr->pathv);
3116 if (fptr->fd < 0) {
3117 rb_str_cat(result, closed, strlen(closed));
3118 }
3119 }
3120 return rb_str_cat2(result, ">");
3121}
3122
3123/*
3124 * call-seq:
3125 * to_io -> self
3126 *
3127 * Returns +self+.
3128 *
3129 */
3130
3131static VALUE
3132rb_io_to_io(VALUE io)
3133{
3134 return io;
3135}
3136
3137/* reading functions */
3138static long
3139read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3140{
3141 int n;
3142
3143 n = READ_DATA_PENDING_COUNT(fptr);
3144 if (n <= 0) return 0;
3145 if (n > len) n = (int)len;
3146 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3147 fptr->rbuf.off += n;
3148 fptr->rbuf.len -= n;
3149 return n;
3150}
3151
3152static long
3153io_bufread(char *ptr, long len, rb_io_t *fptr)
3154{
3155 long offset = 0;
3156 long n = len;
3157 long c;
3158
3159 if (READ_DATA_PENDING(fptr) == 0) {
3160 while (n > 0) {
3161 again:
3162 rb_io_check_closed(fptr);
3163 c = rb_io_read_memory(fptr, ptr+offset, n);
3164 if (c == 0) break;
3165 if (c < 0) {
3166 if (fptr_wait_readable(fptr))
3167 goto again;
3168 return -1;
3169 }
3170 offset += c;
3171 if ((n -= c) <= 0) break;
3172 }
3173 return len - n;
3174 }
3175
3176 while (n > 0) {
3177 c = read_buffered_data(ptr+offset, n, fptr);
3178 if (c > 0) {
3179 offset += c;
3180 if ((n -= c) <= 0) break;
3181 }
3182 rb_io_check_closed(fptr);
3183 if (io_fillbuf(fptr) < 0) {
3184 break;
3185 }
3186 }
3187 return len - n;
3188}
3189
3190static int io_setstrbuf(VALUE *str, long len);
3191
3193 char *str_ptr;
3194 long len;
3195 rb_io_t *fptr;
3196};
3197
3198static VALUE
3199bufread_call(VALUE arg)
3200{
3201 struct bufread_arg *p = (struct bufread_arg *)arg;
3202 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3203 return Qundef;
3204}
3205
3206static long
3207io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3208{
3209 long len;
3210 struct bufread_arg arg;
3211
3212 io_setstrbuf(&str, offset + size);
3213 arg.str_ptr = RSTRING_PTR(str) + offset;
3214 arg.len = size;
3215 arg.fptr = fptr;
3216 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3217 len = arg.len;
3218 if (len < 0) rb_sys_fail_path(fptr->pathv);
3219 return len;
3220}
3221
3222static long
3223remain_size(rb_io_t *fptr)
3224{
3225 struct stat st;
3226 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3227 rb_off_t pos;
3228
3229 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3230#if defined(__HAIKU__)
3231 && (st.st_dev > 3)
3232#endif
3233 )
3234 {
3235 if (io_fflush(fptr) < 0)
3236 rb_sys_fail_on_write(fptr);
3237 pos = lseek(fptr->fd, 0, SEEK_CUR);
3238 if (st.st_size >= pos && pos >= 0) {
3239 siz += st.st_size - pos;
3240 if (siz > LONG_MAX) {
3241 rb_raise(rb_eIOError, "file too big for single read");
3242 }
3243 }
3244 }
3245 else {
3246 siz += BUFSIZ;
3247 }
3248 return (long)siz;
3249}
3250
3251static VALUE
3252io_enc_str(VALUE str, rb_io_t *fptr)
3253{
3254 rb_enc_associate(str, io_read_encoding(fptr));
3255 return str;
3256}
3257
3258static void
3259make_readconv(rb_io_t *fptr, int size)
3260{
3261 if (!fptr->readconv) {
3262 int ecflags;
3263 VALUE ecopts;
3264 const char *sname, *dname;
3265 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3266 ecopts = fptr->encs.ecopts;
3267 if (fptr->encs.enc2) {
3268 sname = rb_enc_name(fptr->encs.enc2);
3269 dname = rb_enc_name(io_read_encoding(fptr));
3270 }
3271 else {
3272 sname = dname = "";
3273 }
3274 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3275 if (!fptr->readconv)
3276 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3277 fptr->cbuf.off = 0;
3278 fptr->cbuf.len = 0;
3279 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3280 fptr->cbuf.capa = size;
3281 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3282 }
3283}
3284
3285#define MORE_CHAR_SUSPENDED Qtrue
3286#define MORE_CHAR_FINISHED Qnil
3287static VALUE
3288fill_cbuf(rb_io_t *fptr, int ec_flags)
3289{
3290 const unsigned char *ss, *sp, *se;
3291 unsigned char *ds, *dp, *de;
3293 int putbackable;
3294 int cbuf_len0;
3295 VALUE exc;
3296
3297 ec_flags |= ECONV_PARTIAL_INPUT;
3298
3299 if (fptr->cbuf.len == fptr->cbuf.capa)
3300 return MORE_CHAR_SUSPENDED; /* cbuf full */
3301 if (fptr->cbuf.len == 0)
3302 fptr->cbuf.off = 0;
3303 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3304 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3305 fptr->cbuf.off = 0;
3306 }
3307
3308 cbuf_len0 = fptr->cbuf.len;
3309
3310 while (1) {
3311 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3312 se = sp + fptr->rbuf.len;
3313 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3314 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3315 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3316 fptr->rbuf.off += (int)(sp - ss);
3317 fptr->rbuf.len -= (int)(sp - ss);
3318 fptr->cbuf.len += (int)(dp - ds);
3319
3320 putbackable = rb_econv_putbackable(fptr->readconv);
3321 if (putbackable) {
3322 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3323 fptr->rbuf.off -= putbackable;
3324 fptr->rbuf.len += putbackable;
3325 }
3326
3327 exc = rb_econv_make_exception(fptr->readconv);
3328 if (!NIL_P(exc))
3329 return exc;
3330
3331 if (cbuf_len0 != fptr->cbuf.len)
3332 return MORE_CHAR_SUSPENDED;
3333
3334 if (res == econv_finished) {
3335 return MORE_CHAR_FINISHED;
3336 }
3337
3338 if (res == econv_source_buffer_empty) {
3339 if (fptr->rbuf.len == 0) {
3340 READ_CHECK(fptr);
3341 if (io_fillbuf(fptr) < 0) {
3342 if (!fptr->readconv) {
3343 return MORE_CHAR_FINISHED;
3344 }
3345 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3346 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3347 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3348 fptr->cbuf.len += (int)(dp - ds);
3350 break;
3351 }
3352 }
3353 }
3354 }
3355 if (cbuf_len0 != fptr->cbuf.len)
3356 return MORE_CHAR_SUSPENDED;
3357
3358 return MORE_CHAR_FINISHED;
3359}
3360
3361static VALUE
3362more_char(rb_io_t *fptr)
3363{
3364 VALUE v;
3365 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3366 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3367 rb_exc_raise(v);
3368 return v;
3369}
3370
3371static VALUE
3372io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3373{
3374 VALUE str = Qnil;
3375 if (strp) {
3376 str = *strp;
3377 if (NIL_P(str)) {
3378 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3379 }
3380 else {
3381 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3382 }
3383 rb_enc_associate(str, fptr->encs.enc);
3384 }
3385 fptr->cbuf.off += len;
3386 fptr->cbuf.len -= len;
3387 /* xxx: set coderange */
3388 if (fptr->cbuf.len == 0)
3389 fptr->cbuf.off = 0;
3390 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3391 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3392 fptr->cbuf.off = 0;
3393 }
3394 return str;
3395}
3396
3397static int
3398io_setstrbuf(VALUE *str, long len)
3399{
3400 if (NIL_P(*str)) {
3401 *str = rb_str_new(0, len);
3402 return TRUE;
3403 }
3404 else {
3405 VALUE s = StringValue(*str);
3406 rb_str_modify(s);
3407
3408 long clen = RSTRING_LEN(s);
3409 if (clen >= len) {
3410 return FALSE;
3411 }
3412 len -= clen;
3413 }
3414 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3416 }
3417 return FALSE;
3418}
3419
3420#define MAX_REALLOC_GAP 4096
3421static void
3422io_shrink_read_string(VALUE str, long n)
3423{
3424 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3425 rb_str_resize(str, n);
3426 }
3427}
3428
3429static void
3430io_set_read_length(VALUE str, long n, int shrinkable)
3431{
3432 if (RSTRING_LEN(str) != n) {
3433 rb_str_modify(str);
3434 rb_str_set_len(str, n);
3435 if (shrinkable) io_shrink_read_string(str, n);
3436 }
3437}
3438
3439static VALUE
3440read_all(rb_io_t *fptr, long siz, VALUE str)
3441{
3442 long bytes;
3443 long n;
3444 long pos;
3445 rb_encoding *enc;
3446 int cr;
3447 int shrinkable;
3448
3449 if (NEED_READCONV(fptr)) {
3450 int first = !NIL_P(str);
3451 SET_BINARY_MODE(fptr);
3452 shrinkable = io_setstrbuf(&str,0);
3453 make_readconv(fptr, 0);
3454 while (1) {
3455 VALUE v;
3456 if (fptr->cbuf.len) {
3457 if (first) rb_str_set_len(str, first = 0);
3458 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3459 }
3460 v = fill_cbuf(fptr, 0);
3461 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3462 if (fptr->cbuf.len) {
3463 if (first) rb_str_set_len(str, first = 0);
3464 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3465 }
3466 rb_exc_raise(v);
3467 }
3468 if (v == MORE_CHAR_FINISHED) {
3469 clear_readconv(fptr);
3470 if (first) rb_str_set_len(str, first = 0);
3471 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3472 return io_enc_str(str, fptr);
3473 }
3474 }
3475 }
3476
3477 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3478 bytes = 0;
3479 pos = 0;
3480
3481 enc = io_read_encoding(fptr);
3482 cr = 0;
3483
3484 if (siz == 0) {
3485 siz = BUFSIZ;
3486 }
3487 else {
3488 // If `siz` is set, we got it from `stat(2)`.
3489 // We attempt to read one extra byte because:
3490 // - If the file was appended to since then, we'll continue reading.
3491 // - If the file is still the same length, we won't issue a second `io_fread`.
3492 siz++;
3493 }
3494 shrinkable = io_setstrbuf(&str, siz);
3495 for (;;) {
3496 READ_CHECK(fptr);
3497 n = io_fread(str, bytes, siz - bytes, fptr);
3498 if (n == 0 && bytes == 0) {
3499 rb_str_set_len(str, 0);
3500 break;
3501 }
3502 bytes += n;
3503 rb_str_set_len(str, bytes);
3504 if (cr != ENC_CODERANGE_BROKEN)
3505 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3506 if (bytes < siz) break;
3507 siz += BUFSIZ;
3508
3509 size_t capa = rb_str_capacity(str);
3510 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3511 if (capa < BUFSIZ) {
3512 capa = BUFSIZ;
3513 }
3514 else if (capa > IO_MAX_BUFFER_GROWTH) {
3515 capa = IO_MAX_BUFFER_GROWTH;
3516 }
3518 }
3519 }
3520 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3521 str = io_enc_str(str, fptr);
3522 ENC_CODERANGE_SET(str, cr);
3523 return str;
3524}
3525
3526void
3528{
3529 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3530 rb_sys_fail_path(fptr->pathv);
3531 }
3532}
3533
3534static VALUE
3535io_read_memory_call(VALUE arg)
3536{
3537 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3538
3539 VALUE scheduler = rb_fiber_scheduler_current();
3540 if (scheduler != Qnil) {
3541 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa);
3542
3543 if (!UNDEF_P(result)) {
3544 // This is actually returned as a pseudo-VALUE and later cast to a long:
3546 }
3547 }
3548
3549 if (iis->nonblock) {
3550 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3551 }
3552 else {
3553 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3554 }
3555}
3556
3557static long
3558io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3559{
3560 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3561}
3562
3563#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3564
3565static VALUE
3566io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3567{
3568 rb_io_t *fptr;
3569 VALUE length, str;
3570 long n, len;
3571 struct io_internal_read_struct iis;
3572 int shrinkable;
3573
3574 rb_scan_args(argc, argv, "11", &length, &str);
3575
3576 if ((len = NUM2LONG(length)) < 0) {
3577 rb_raise(rb_eArgError, "negative length %ld given", len);
3578 }
3579
3580 shrinkable = io_setstrbuf(&str, len);
3581
3582 GetOpenFile(io, fptr);
3584
3585 if (len == 0) {
3586 io_set_read_length(str, 0, shrinkable);
3587 return str;
3588 }
3589
3590 if (!nonblock)
3591 READ_CHECK(fptr);
3592 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3593 if (n <= 0) {
3594 again:
3595 if (nonblock) {
3596 rb_io_set_nonblock(fptr);
3597 }
3598 io_setstrbuf(&str, len);
3599 iis.th = rb_thread_current();
3600 iis.fptr = fptr;
3601 iis.nonblock = nonblock;
3602 iis.fd = fptr->fd;
3603 iis.buf = RSTRING_PTR(str);
3604 iis.capa = len;
3605 iis.timeout = NULL;
3606 n = io_read_memory_locktmp(str, &iis);
3607 if (n < 0) {
3608 int e = errno;
3609 if (!nonblock && fptr_wait_readable(fptr))
3610 goto again;
3611 if (nonblock && (io_again_p(e))) {
3612 if (no_exception)
3613 return sym_wait_readable;
3614 else
3615 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3616 e, "read would block");
3617 }
3618 rb_syserr_fail_path(e, fptr->pathv);
3619 }
3620 }
3621 io_set_read_length(str, n, shrinkable);
3622
3623 if (n == 0)
3624 return Qnil;
3625 else
3626 return str;
3627}
3628
3629/*
3630 * call-seq:
3631 * readpartial(maxlen) -> string
3632 * readpartial(maxlen, out_string) -> out_string
3633 *
3634 * Reads up to +maxlen+ bytes from the stream;
3635 * returns a string (either a new string or the given +out_string+).
3636 * Its encoding is:
3637 *
3638 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3639 * - ASCII-8BIT, otherwise.
3640 *
3641 * - Contains +maxlen+ bytes from the stream, if available.
3642 * - Otherwise contains all available bytes, if any available.
3643 * - Is an empty string if +maxlen+ is zero.
3644 *
3645 * With the single non-negative integer argument +maxlen+ given,
3646 * returns a new string:
3647 *
3648 * f = File.new('t.txt')
3649 * f.readpartial(20) # => "First line\nSecond l"
3650 * f.readpartial(20) # => "ine\n\nFourth line\n"
3651 * f.readpartial(20) # => "Fifth line\n"
3652 * f.readpartial(20) # Raises EOFError.
3653 * f.close
3654 *
3655 * With both argument +maxlen+ and string argument +out_string+ given,
3656 * returns modified +out_string+:
3657 *
3658 * f = File.new('t.txt')
3659 * s = 'foo'
3660 * f.readpartial(20, s) # => "First line\nSecond l"
3661 * s = 'bar'
3662 * f.readpartial(0, s) # => ""
3663 * f.close
3664 *
3665 * This method is useful for a stream such as a pipe, a socket, or a tty.
3666 * It blocks only when no data is immediately available.
3667 * This means that it blocks only when _all_ of the following are true:
3668 *
3669 * - The byte buffer in the stream is empty.
3670 * - The content of the stream is empty.
3671 * - The stream is not at EOF.
3672 *
3673 * When blocked, the method waits for either more data or EOF on the stream:
3674 *
3675 * - If more data is read, the method returns the data.
3676 * - If EOF is reached, the method raises EOFError.
3677 *
3678 * When not blocked, the method responds immediately:
3679 *
3680 * - Returns data from the buffer if there is any.
3681 * - Otherwise returns data from the stream if there is any.
3682 * - Otherwise raises EOFError if the stream has reached EOF.
3683 *
3684 * Note that this method is similar to sysread. The differences are:
3685 *
3686 * - If the byte buffer is not empty, read from the byte buffer
3687 * instead of "sysread for buffered IO (IOError)".
3688 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3689 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3690 * readpartial retries the system call.
3691 *
3692 * The latter means that readpartial is non-blocking-flag insensitive.
3693 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3694 * if the fd is blocking mode.
3695 *
3696 * Examples:
3697 *
3698 * # # Returned Buffer Content Pipe Content
3699 * r, w = IO.pipe #
3700 * w << 'abc' # "" "abc".
3701 * r.readpartial(4096) # => "abc" "" ""
3702 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3703 *
3704 * # # Returned Buffer Content Pipe Content
3705 * r, w = IO.pipe #
3706 * w << 'abc' # "" "abc"
3707 * w.close # "" "abc" EOF
3708 * r.readpartial(4096) # => "abc" "" EOF
3709 * r.readpartial(4096) # raises EOFError
3710 *
3711 * # # Returned Buffer Content Pipe Content
3712 * r, w = IO.pipe #
3713 * w << "abc\ndef\n" # "" "abc\ndef\n"
3714 * r.gets # => "abc\n" "def\n" ""
3715 * w << "ghi\n" # "def\n" "ghi\n"
3716 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3717 * r.readpartial(4096) # => "ghi\n" "" ""
3718 *
3719 */
3720
3721static VALUE
3722io_readpartial(int argc, VALUE *argv, VALUE io)
3723{
3724 VALUE ret;
3725
3726 ret = io_getpartial(argc, argv, io, Qnil, 0);
3727 if (NIL_P(ret))
3728 rb_eof_error();
3729 return ret;
3730}
3731
3732static VALUE
3733io_nonblock_eof(int no_exception)
3734{
3735 if (!no_exception) {
3736 rb_eof_error();
3737 }
3738 return Qnil;
3739}
3740
3741/* :nodoc: */
3742static VALUE
3743io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3744{
3745 rb_io_t *fptr;
3746 long n, len;
3747 struct io_internal_read_struct iis;
3748 int shrinkable;
3749
3750 if ((len = NUM2LONG(length)) < 0) {
3751 rb_raise(rb_eArgError, "negative length %ld given", len);
3752 }
3753
3754 shrinkable = io_setstrbuf(&str, len);
3755 rb_bool_expected(ex, "exception", TRUE);
3756
3757 GetOpenFile(io, fptr);
3759
3760 if (len == 0) {
3761 io_set_read_length(str, 0, shrinkable);
3762 return str;
3763 }
3764
3765 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3766 if (n <= 0) {
3767 rb_fd_set_nonblock(fptr->fd);
3768 shrinkable |= io_setstrbuf(&str, len);
3769 iis.fptr = fptr;
3770 iis.nonblock = 1;
3771 iis.fd = fptr->fd;
3772 iis.buf = RSTRING_PTR(str);
3773 iis.capa = len;
3774 iis.timeout = NULL;
3775 n = io_read_memory_locktmp(str, &iis);
3776 if (n < 0) {
3777 int e = errno;
3778 if (io_again_p(e)) {
3779 if (!ex) return sym_wait_readable;
3780 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3781 e, "read would block");
3782 }
3783 rb_syserr_fail_path(e, fptr->pathv);
3784 }
3785 }
3786 io_set_read_length(str, n, shrinkable);
3787
3788 if (n == 0) {
3789 if (!ex) return Qnil;
3790 rb_eof_error();
3791 }
3792
3793 return str;
3794}
3795
3796/* :nodoc: */
3797static VALUE
3798io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3799{
3800 rb_io_t *fptr;
3801 long n;
3802
3803 if (!RB_TYPE_P(str, T_STRING))
3804 str = rb_obj_as_string(str);
3805 rb_bool_expected(ex, "exception", TRUE);
3806
3807 io = GetWriteIO(io);
3808 GetOpenFile(io, fptr);
3810
3811 if (io_fflush(fptr) < 0)
3812 rb_sys_fail_on_write(fptr);
3813
3814 rb_fd_set_nonblock(fptr->fd);
3815 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3816 RB_GC_GUARD(str);
3817
3818 if (n < 0) {
3819 int e = errno;
3820 if (io_again_p(e)) {
3821 if (!ex) {
3822 return sym_wait_writable;
3823 }
3824 else {
3825 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3826 }
3827 }
3828 rb_syserr_fail_path(e, fptr->pathv);
3829 }
3830
3831 return LONG2FIX(n);
3832}
3833
3834/*
3835 * call-seq:
3836 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3837 *
3838 * Reads bytes from the stream; the stream must be opened for reading
3839 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3840 *
3841 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3842 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3843 *
3844 * Returns a string (either a new string or the given +out_string+)
3845 * containing the bytes read.
3846 * The encoding of the string depends on both +maxLen+ and +out_string+:
3847 *
3848 * - +maxlen+ is +nil+: uses internal encoding of +self+
3849 * (regardless of whether +out_string+ was given).
3850 * - +maxlen+ not +nil+:
3851 *
3852 * - +out_string+ given: encoding of +out_string+ not modified.
3853 * - +out_string+ not given: ASCII-8BIT is used.
3854 *
3855 * <b>Without Argument +out_string+</b>
3856 *
3857 * When argument +out_string+ is omitted,
3858 * the returned value is a new string:
3859 *
3860 * f = File.new('t.txt')
3861 * f.read
3862 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3863 * f.rewind
3864 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3865 * f.read(30) # => "rth line\r\nFifth line\r\n"
3866 * f.read(30) # => nil
3867 * f.close
3868 *
3869 * If +maxlen+ is zero, returns an empty string.
3870 *
3871 * <b> With Argument +out_string+</b>
3872 *
3873 * When argument +out_string+ is given,
3874 * the returned value is +out_string+, whose content is replaced:
3875 *
3876 * f = File.new('t.txt')
3877 * s = 'foo' # => "foo"
3878 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3879 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3880 * f.rewind
3881 * s = 'bar'
3882 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3883 * s # => "First line\r\nSecond line\r\n\r\nFou"
3884 * s = 'baz'
3885 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3886 * s # => "rth line\r\nFifth line\r\n"
3887 * s = 'bat'
3888 * f.read(30, s) # => nil
3889 * s # => ""
3890 * f.close
3891 *
3892 * Note that this method behaves like the fread() function in C.
3893 * This means it retries to invoke read(2) system calls to read data
3894 * with the specified maxlen (or until EOF).
3895 *
3896 * This behavior is preserved even if the stream is in non-blocking mode.
3897 * (This method is non-blocking-flag insensitive as other methods.)
3898 *
3899 * If you need the behavior like a single read(2) system call,
3900 * consider #readpartial, #read_nonblock, and #sysread.
3901 *
3902 * Related: IO#write.
3903 */
3904
3905static VALUE
3906io_read(int argc, VALUE *argv, VALUE io)
3907{
3908 rb_io_t *fptr;
3909 long n, len;
3910 VALUE length, str;
3911 int shrinkable;
3912#if RUBY_CRLF_ENVIRONMENT
3913 int previous_mode;
3914#endif
3915
3916 rb_scan_args(argc, argv, "02", &length, &str);
3917
3918 if (NIL_P(length)) {
3919 GetOpenFile(io, fptr);
3921 return read_all(fptr, remain_size(fptr), str);
3922 }
3923 len = NUM2LONG(length);
3924 if (len < 0) {
3925 rb_raise(rb_eArgError, "negative length %ld given", len);
3926 }
3927
3928 shrinkable = io_setstrbuf(&str,len);
3929
3930 GetOpenFile(io, fptr);
3932 if (len == 0) {
3933 io_set_read_length(str, 0, shrinkable);
3934 return str;
3935 }
3936
3937 READ_CHECK(fptr);
3938#if RUBY_CRLF_ENVIRONMENT
3939 previous_mode = set_binary_mode_with_seek_cur(fptr);
3940#endif
3941 n = io_fread(str, 0, len, fptr);
3942 io_set_read_length(str, n, shrinkable);
3943#if RUBY_CRLF_ENVIRONMENT
3944 if (previous_mode == O_TEXT) {
3945 setmode(fptr->fd, O_TEXT);
3946 }
3947#endif
3948 if (n == 0) return Qnil;
3949
3950 return str;
3951}
3952
3953static void
3954rscheck(const char *rsptr, long rslen, VALUE rs)
3955{
3956 if (!rs) return;
3957 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3958 rb_raise(rb_eRuntimeError, "rs modified");
3959}
3960
3961static const char *
3962search_delim(const char *p, long len, int delim, rb_encoding *enc)
3963{
3964 if (rb_enc_mbminlen(enc) == 1) {
3965 p = memchr(p, delim, len);
3966 if (p) return p + 1;
3967 }
3968 else {
3969 const char *end = p + len;
3970 while (p < end) {
3971 int r = rb_enc_precise_mbclen(p, end, enc);
3972 if (!MBCLEN_CHARFOUND_P(r)) {
3973 p += rb_enc_mbminlen(enc);
3974 continue;
3975 }
3976 int n = MBCLEN_CHARFOUND_LEN(r);
3977 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3978 return p + n;
3979 }
3980 p += n;
3981 }
3982 }
3983 return NULL;
3984}
3985
3986static int
3987appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3988{
3989 VALUE str = *strp;
3990 long limit = *lp;
3991
3992 if (NEED_READCONV(fptr)) {
3993 SET_BINARY_MODE(fptr);
3994 make_readconv(fptr, 0);
3995 do {
3996 const char *p, *e;
3997 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3998 if (searchlen) {
3999 p = READ_CHAR_PENDING_PTR(fptr);
4000 if (0 < limit && limit < searchlen)
4001 searchlen = (int)limit;
4002 e = search_delim(p, searchlen, delim, enc);
4003 if (e) {
4004 int len = (int)(e-p);
4005 if (NIL_P(str))
4006 *strp = str = rb_str_new(p, len);
4007 else
4008 rb_str_buf_cat(str, p, len);
4009 fptr->cbuf.off += len;
4010 fptr->cbuf.len -= len;
4011 limit -= len;
4012 *lp = limit;
4013 return delim;
4014 }
4015
4016 if (NIL_P(str))
4017 *strp = str = rb_str_new(p, searchlen);
4018 else
4019 rb_str_buf_cat(str, p, searchlen);
4020 fptr->cbuf.off += searchlen;
4021 fptr->cbuf.len -= searchlen;
4022 limit -= searchlen;
4023
4024 if (limit == 0) {
4025 *lp = limit;
4026 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4027 }
4028 }
4029 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4030 clear_readconv(fptr);
4031 *lp = limit;
4032 return EOF;
4033 }
4034
4035 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4036 do {
4037 long pending = READ_DATA_PENDING_COUNT(fptr);
4038 if (pending > 0) {
4039 const char *p = READ_DATA_PENDING_PTR(fptr);
4040 const char *e;
4041 long last;
4042
4043 if (limit > 0 && pending > limit) pending = limit;
4044 e = search_delim(p, pending, delim, enc);
4045 if (e) pending = e - p;
4046 if (!NIL_P(str)) {
4047 last = RSTRING_LEN(str);
4048 rb_str_resize(str, last + pending);
4049 }
4050 else {
4051 last = 0;
4052 *strp = str = rb_str_buf_new(pending);
4053 rb_str_set_len(str, pending);
4054 }
4055 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
4056 limit -= pending;
4057 *lp = limit;
4058 if (e) return delim;
4059 if (limit == 0)
4060 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4061 }
4062 READ_CHECK(fptr);
4063 } while (io_fillbuf(fptr) >= 0);
4064 *lp = limit;
4065 return EOF;
4066}
4067
4068static inline int
4069swallow(rb_io_t *fptr, int term)
4070{
4071 if (NEED_READCONV(fptr)) {
4072 rb_encoding *enc = io_read_encoding(fptr);
4073 int needconv = rb_enc_mbminlen(enc) != 1;
4074 SET_BINARY_MODE(fptr);
4075 make_readconv(fptr, 0);
4076 do {
4077 size_t cnt;
4078 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4079 const char *p = READ_CHAR_PENDING_PTR(fptr);
4080 int i;
4081 if (!needconv) {
4082 if (*p != term) return TRUE;
4083 i = (int)cnt;
4084 while (--i && *++p == term);
4085 }
4086 else {
4087 const char *e = p + cnt;
4088 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
4089 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4090 i = (int)(e - p);
4091 }
4092 io_shift_cbuf(fptr, (int)cnt - i, NULL);
4093 }
4094 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4095 return FALSE;
4096 }
4097
4098 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4099 do {
4100 size_t cnt;
4101 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4102 char buf[1024];
4103 const char *p = READ_DATA_PENDING_PTR(fptr);
4104 int i;
4105 if (cnt > sizeof buf) cnt = sizeof buf;
4106 if (*p != term) return TRUE;
4107 i = (int)cnt;
4108 while (--i && *++p == term);
4109 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4110 rb_sys_fail_path(fptr->pathv);
4111 }
4112 READ_CHECK(fptr);
4113 } while (io_fillbuf(fptr) == 0);
4114 return FALSE;
4115}
4116
4117static VALUE
4118rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4119{
4120 VALUE str = Qnil;
4121 int len = 0;
4122 long pos = 0;
4123 int cr = 0;
4124
4125 do {
4126 int pending = READ_DATA_PENDING_COUNT(fptr);
4127
4128 if (pending > 0) {
4129 const char *p = READ_DATA_PENDING_PTR(fptr);
4130 const char *e;
4131 int chomplen = 0;
4132
4133 e = memchr(p, '\n', pending);
4134 if (e) {
4135 pending = (int)(e - p + 1);
4136 if (chomp) {
4137 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4138 }
4139 }
4140 if (NIL_P(str)) {
4141 str = rb_str_new(p, pending - chomplen);
4142 fptr->rbuf.off += pending;
4143 fptr->rbuf.len -= pending;
4144 }
4145 else {
4146 rb_str_resize(str, len + pending - chomplen);
4147 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4148 fptr->rbuf.off += chomplen;
4149 fptr->rbuf.len -= chomplen;
4150 if (pending == 1 && chomplen == 1 && len > 0) {
4151 if (RSTRING_PTR(str)[len-1] == '\r') {
4152 rb_str_resize(str, --len);
4153 break;
4154 }
4155 }
4156 }
4157 len += pending - chomplen;
4158 if (cr != ENC_CODERANGE_BROKEN)
4159 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4160 if (e) break;
4161 }
4162 READ_CHECK(fptr);
4163 } while (io_fillbuf(fptr) >= 0);
4164 if (NIL_P(str)) return Qnil;
4165
4166 str = io_enc_str(str, fptr);
4167 ENC_CODERANGE_SET(str, cr);
4168 fptr->lineno++;
4169
4170 return str;
4171}
4172
4174 VALUE io;
4175 VALUE rs;
4176 long limit;
4177 unsigned int chomp: 1;
4178};
4179
4180static void
4181extract_getline_opts(VALUE opts, struct getline_arg *args)
4182{
4183 int chomp = FALSE;
4184 if (!NIL_P(opts)) {
4185 static ID kwds[1];
4186 VALUE vchomp;
4187 if (!kwds[0]) {
4188 kwds[0] = rb_intern_const("chomp");
4189 }
4190 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4191 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4192 }
4193 args->chomp = chomp;
4194}
4195
4196static void
4197extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4198{
4199 VALUE rs = rb_rs, lim = Qnil;
4200
4201 if (argc == 1) {
4202 VALUE tmp = Qnil;
4203
4204 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4205 rs = tmp;
4206 }
4207 else {
4208 lim = argv[0];
4209 }
4210 }
4211 else if (2 <= argc) {
4212 rs = argv[0], lim = argv[1];
4213 if (!NIL_P(rs))
4214 StringValue(rs);
4215 }
4216 args->rs = rs;
4217 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4218}
4219
4220static void
4221check_getline_args(VALUE *rsp, long *limit, VALUE io)
4222{
4223 rb_io_t *fptr;
4224 VALUE rs = *rsp;
4225
4226 if (!NIL_P(rs)) {
4227 rb_encoding *enc_rs, *enc_io;
4228
4229 GetOpenFile(io, fptr);
4230 enc_rs = rb_enc_get(rs);
4231 enc_io = io_read_encoding(fptr);
4232 if (enc_io != enc_rs &&
4233 (!is_ascii_string(rs) ||
4234 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4235 if (rs == rb_default_rs) {
4236 rs = rb_enc_str_new(0, 0, enc_io);
4237 rb_str_buf_cat_ascii(rs, "\n");
4238 *rsp = rs;
4239 }
4240 else {
4241 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4242 rb_enc_name(enc_io),
4243 rb_enc_name(enc_rs));
4244 }
4245 }
4246 }
4247}
4248
4249static void
4250prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4251{
4252 VALUE opts;
4253 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4254 extract_getline_args(argc, argv, args);
4255 extract_getline_opts(opts, args);
4256 check_getline_args(&args->rs, &args->limit, io);
4257}
4258
4259static VALUE
4260rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4261{
4262 VALUE str = Qnil;
4263 int nolimit = 0;
4264 rb_encoding *enc;
4265
4267 if (NIL_P(rs) && limit < 0) {
4268 str = read_all(fptr, 0, Qnil);
4269 if (RSTRING_LEN(str) == 0) return Qnil;
4270 }
4271 else if (limit == 0) {
4272 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4273 }
4274 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4275 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4276 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4277 return rb_io_getline_fast(fptr, enc, chomp);
4278 }
4279 else {
4280 int c, newline = -1;
4281 const char *rsptr = 0;
4282 long rslen = 0;
4283 int rspara = 0;
4284 int extra_limit = 16;
4285 int chomp_cr = chomp;
4286
4287 SET_BINARY_MODE(fptr);
4288 enc = io_read_encoding(fptr);
4289
4290 if (!NIL_P(rs)) {
4291 rslen = RSTRING_LEN(rs);
4292 if (rslen == 0) {
4293 rsptr = "\n\n";
4294 rslen = 2;
4295 rspara = 1;
4296 swallow(fptr, '\n');
4297 rs = 0;
4298 if (!rb_enc_asciicompat(enc)) {
4299 rs = rb_usascii_str_new(rsptr, rslen);
4300 rs = rb_str_conv_enc(rs, 0, enc);
4301 OBJ_FREEZE(rs);
4302 rsptr = RSTRING_PTR(rs);
4303 rslen = RSTRING_LEN(rs);
4304 }
4305 newline = '\n';
4306 }
4307 else if (rb_enc_mbminlen(enc) == 1) {
4308 rsptr = RSTRING_PTR(rs);
4309 newline = (unsigned char)rsptr[rslen - 1];
4310 }
4311 else {
4312 rs = rb_str_conv_enc(rs, 0, enc);
4313 rsptr = RSTRING_PTR(rs);
4314 const char *e = rsptr + rslen;
4315 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4316 int n;
4317 newline = rb_enc_codepoint_len(last, e, &n, enc);
4318 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4319 }
4320 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4321 }
4322
4323 /* MS - Optimization */
4324 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4325 const char *s, *p, *pp, *e;
4326
4327 if (c == newline) {
4328 if (RSTRING_LEN(str) < rslen) continue;
4329 s = RSTRING_PTR(str);
4330 e = RSTRING_END(str);
4331 p = e - rslen;
4332 if (!at_char_boundary(s, p, e, enc)) continue;
4333 if (!rspara) rscheck(rsptr, rslen, rs);
4334 if (memcmp(p, rsptr, rslen) == 0) {
4335 if (chomp) {
4336 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4337 rb_str_set_len(str, p - s);
4338 }
4339 break;
4340 }
4341 }
4342 if (limit == 0) {
4343 s = RSTRING_PTR(str);
4344 p = RSTRING_END(str);
4345 pp = rb_enc_prev_char(s, p, p, enc);
4346 if (extra_limit && pp &&
4347 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4348 /* relax the limit while incomplete character.
4349 * extra_limit limits the relax length */
4350 limit = 1;
4351 extra_limit--;
4352 }
4353 else {
4354 nolimit = 1;
4355 break;
4356 }
4357 }
4358 }
4359
4360 if (rspara && c != EOF)
4361 swallow(fptr, '\n');
4362 if (!NIL_P(str))
4363 str = io_enc_str(str, fptr);
4364 }
4365
4366 if (!NIL_P(str) && !nolimit) {
4367 fptr->lineno++;
4368 }
4369
4370 return str;
4371}
4372
4373static VALUE
4374rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4375{
4376 rb_io_t *fptr;
4377 int old_lineno, new_lineno;
4378 VALUE str;
4379
4380 GetOpenFile(io, fptr);
4381 old_lineno = fptr->lineno;
4382 str = rb_io_getline_0(rs, limit, chomp, fptr);
4383 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4384 if (io == ARGF.current_file) {
4385 ARGF.lineno += new_lineno - old_lineno;
4386 ARGF.last_lineno = ARGF.lineno;
4387 }
4388 else {
4389 ARGF.last_lineno = new_lineno;
4390 }
4391 }
4392
4393 return str;
4394}
4395
4396static VALUE
4397rb_io_getline(int argc, VALUE *argv, VALUE io)
4398{
4399 struct getline_arg args;
4400
4401 prepare_getline_args(argc, argv, &args, io);
4402 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4403}
4404
4405VALUE
4407{
4408 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4409}
4410
4411VALUE
4412rb_io_gets_limit_internal(VALUE io, long limit)
4413{
4414 rb_io_t *fptr;
4415 GetOpenFile(io, fptr);
4416 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4417}
4418
4419VALUE
4420rb_io_gets_internal(VALUE io)
4421{
4422 return rb_io_gets_limit_internal(io, -1);
4423}
4424
4425/*
4426 * call-seq:
4427 * gets(sep = $/, chomp: false) -> string or nil
4428 * gets(limit, chomp: false) -> string or nil
4429 * gets(sep, limit, chomp: false) -> string or nil
4430 *
4431 * Reads and returns a line from the stream;
4432 * assigns the return value to <tt>$_</tt>.
4433 * See {Line IO}[rdoc-ref:IO@Line+IO].
4434 *
4435 * With no arguments given, returns the next line
4436 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4437 *
4438 * f = File.open('t.txt')
4439 * f.gets # => "First line\n"
4440 * $_ # => "First line\n"
4441 * f.gets # => "\n"
4442 * f.gets # => "Fourth line\n"
4443 * f.gets # => "Fifth line\n"
4444 * f.gets # => nil
4445 * f.close
4446 *
4447 * With only string argument +sep+ given,
4448 * returns the next line as determined by line separator +sep+,
4449 * or +nil+ if none;
4450 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4451 *
4452 * f = File.new('t.txt')
4453 * f.gets('l') # => "First l"
4454 * f.gets('li') # => "ine\nSecond li"
4455 * f.gets('lin') # => "ne\n\nFourth lin"
4456 * f.gets # => "e\n"
4457 * f.close
4458 *
4459 * The two special values for +sep+ are honored:
4460 *
4461 * f = File.new('t.txt')
4462 * # Get all.
4463 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4464 * f.rewind
4465 * # Get paragraph (up to two line separators).
4466 * f.gets('') # => "First line\nSecond line\n\n"
4467 * f.close
4468 *
4469 * With only integer argument +limit+ given,
4470 * limits the number of bytes in the line;
4471 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4472 *
4473 * # No more than one line.
4474 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4475 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4476 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4477 *
4478 * With arguments +sep+ and +limit+ given,
4479 * combines the two behaviors
4480 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4481 *
4482 * Optional keyword argument +chomp+ specifies whether line separators
4483 * are to be omitted:
4484 *
4485 * f = File.open('t.txt')
4486 * # Chomp the lines.
4487 * f.gets(chomp: true) # => "First line"
4488 * f.gets(chomp: true) # => "Second line"
4489 * f.gets(chomp: true) # => ""
4490 * f.gets(chomp: true) # => "Fourth line"
4491 * f.gets(chomp: true) # => "Fifth line"
4492 * f.gets(chomp: true) # => nil
4493 * f.close
4494 *
4495 */
4496
4497static VALUE
4498rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4499{
4500 VALUE str;
4501
4502 str = rb_io_getline(argc, argv, io);
4503 rb_lastline_set(str);
4504
4505 return str;
4506}
4507
4508/*
4509 * call-seq:
4510 * lineno -> integer
4511 *
4512 * Returns the current line number for the stream;
4513 * see {Line Number}[rdoc-ref:IO@Line+Number].
4514 *
4515 */
4516
4517static VALUE
4518rb_io_lineno(VALUE io)
4519{
4520 rb_io_t *fptr;
4521
4522 GetOpenFile(io, fptr);
4524 return INT2NUM(fptr->lineno);
4525}
4526
4527/*
4528 * call-seq:
4529 * lineno = integer -> integer
4530 *
4531 * Sets and returns the line number for the stream;
4532 * see {Line Number}[rdoc-ref:IO@Line+Number].
4533 *
4534 */
4535
4536static VALUE
4537rb_io_set_lineno(VALUE io, VALUE lineno)
4538{
4539 rb_io_t *fptr;
4540
4541 GetOpenFile(io, fptr);
4543 fptr->lineno = NUM2INT(lineno);
4544 return lineno;
4545}
4546
4547/* :nodoc: */
4548static VALUE
4549io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4550{
4551 long limit = -1;
4552 if (NIL_P(lim)) {
4553 VALUE tmp = Qnil;
4554 // If sep is specified, but it's not a string and not nil, then assume
4555 // it's the limit (it should be an integer)
4556 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4557 // If the user has specified a non-nil / non-string value
4558 // for the separator, we assume it's the limit and set the
4559 // separator to default: rb_rs.
4560 lim = sep;
4561 limit = NUM2LONG(lim);
4562 sep = rb_rs;
4563 }
4564 else {
4565 sep = tmp;
4566 }
4567 }
4568 else {
4569 if (!NIL_P(sep)) StringValue(sep);
4570 limit = NUM2LONG(lim);
4571 }
4572
4573 check_getline_args(&sep, &limit, io);
4574
4575 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4576 rb_lastline_set_up(line, 1);
4577
4578 if (NIL_P(line)) {
4579 rb_eof_error();
4580 }
4581 return line;
4582}
4583
4584static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4585
4586/*
4587 * call-seq:
4588 * readlines(sep = $/, chomp: false) -> array
4589 * readlines(limit, chomp: false) -> array
4590 * readlines(sep, limit, chomp: false) -> array
4591 *
4592 * Reads and returns all remaining line from the stream;
4593 * does not modify <tt>$_</tt>.
4594 * See {Line IO}[rdoc-ref:IO@Line+IO].
4595 *
4596 * With no arguments given, returns lines
4597 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4598 *
4599 * f = File.new('t.txt')
4600 * f.readlines
4601 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4602 * f.readlines # => []
4603 * f.close
4604 *
4605 * With only string argument +sep+ given,
4606 * returns lines as determined by line separator +sep+,
4607 * or +nil+ if none;
4608 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4609 *
4610 * f = File.new('t.txt')
4611 * f.readlines('li')
4612 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4613 * f.close
4614 *
4615 * The two special values for +sep+ are honored:
4616 *
4617 * f = File.new('t.txt')
4618 * # Get all into one string.
4619 * f.readlines(nil)
4620 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4621 * # Get paragraphs (up to two line separators).
4622 * f.rewind
4623 * f.readlines('')
4624 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4625 * f.close
4626 *
4627 * With only integer argument +limit+ given,
4628 * limits the number of bytes in each line;
4629 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4630 *
4631 * f = File.new('t.txt')
4632 * f.readlines(8)
4633 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4634 * f.close
4635 *
4636 * With arguments +sep+ and +limit+ given,
4637 * combines the two behaviors
4638 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4639 *
4640 * Optional keyword argument +chomp+ specifies whether line separators
4641 * are to be omitted:
4642 *
4643 * f = File.new('t.txt')
4644 * f.readlines(chomp: true)
4645 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4646 * f.close
4647 *
4648 */
4649
4650static VALUE
4651rb_io_readlines(int argc, VALUE *argv, VALUE io)
4652{
4653 struct getline_arg args;
4654
4655 prepare_getline_args(argc, argv, &args, io);
4656 return io_readlines(&args, io);
4657}
4658
4659static VALUE
4660io_readlines(const struct getline_arg *arg, VALUE io)
4661{
4662 VALUE line, ary;
4663
4664 if (arg->limit == 0)
4665 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4666 ary = rb_ary_new();
4667 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4668 rb_ary_push(ary, line);
4669 }
4670 return ary;
4671}
4672
4673/*
4674 * call-seq:
4675 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4676 * each_line(limit, chomp: false) {|line| ... } -> self
4677 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4678 * each_line -> enumerator
4679 *
4680 * Calls the block with each remaining line read from the stream;
4681 * returns +self+.
4682 * Does nothing if already at end-of-stream;
4683 * See {Line IO}[rdoc-ref:IO@Line+IO].
4684 *
4685 * With no arguments given, reads lines
4686 * as determined by line separator <tt>$/</tt>:
4687 *
4688 * f = File.new('t.txt')
4689 * f.each_line {|line| p line }
4690 * f.each_line {|line| fail 'Cannot happen' }
4691 * f.close
4692 *
4693 * Output:
4694 *
4695 * "First line\n"
4696 * "Second line\n"
4697 * "\n"
4698 * "Fourth line\n"
4699 * "Fifth line\n"
4700 *
4701 * With only string argument +sep+ given,
4702 * reads lines as determined by line separator +sep+;
4703 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4704 *
4705 * f = File.new('t.txt')
4706 * f.each_line('li') {|line| p line }
4707 * f.close
4708 *
4709 * Output:
4710 *
4711 * "First li"
4712 * "ne\nSecond li"
4713 * "ne\n\nFourth li"
4714 * "ne\nFifth li"
4715 * "ne\n"
4716 *
4717 * The two special values for +sep+ are honored:
4718 *
4719 * f = File.new('t.txt')
4720 * # Get all into one string.
4721 * f.each_line(nil) {|line| p line }
4722 * f.close
4723 *
4724 * Output:
4725 *
4726 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4727 *
4728 * f.rewind
4729 * # Get paragraphs (up to two line separators).
4730 * f.each_line('') {|line| p line }
4731 *
4732 * Output:
4733 *
4734 * "First line\nSecond line\n\n"
4735 * "Fourth line\nFifth line\n"
4736 *
4737 * With only integer argument +limit+ given,
4738 * limits the number of bytes in each line;
4739 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4740 *
4741 * f = File.new('t.txt')
4742 * f.each_line(8) {|line| p line }
4743 * f.close
4744 *
4745 * Output:
4746 *
4747 * "First li"
4748 * "ne\n"
4749 * "Second l"
4750 * "ine\n"
4751 * "\n"
4752 * "Fourth l"
4753 * "ine\n"
4754 * "Fifth li"
4755 * "ne\n"
4756 *
4757 * With arguments +sep+ and +limit+ given,
4758 * combines the two behaviors
4759 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4760 *
4761 * Optional keyword argument +chomp+ specifies whether line separators
4762 * are to be omitted:
4763 *
4764 * f = File.new('t.txt')
4765 * f.each_line(chomp: true) {|line| p line }
4766 * f.close
4767 *
4768 * Output:
4769 *
4770 * "First line"
4771 * "Second line"
4772 * ""
4773 * "Fourth line"
4774 * "Fifth line"
4775 *
4776 * Returns an Enumerator if no block is given.
4777 */
4778
4779static VALUE
4780rb_io_each_line(int argc, VALUE *argv, VALUE io)
4781{
4782 VALUE str;
4783 struct getline_arg args;
4784
4785 RETURN_ENUMERATOR(io, argc, argv);
4786 prepare_getline_args(argc, argv, &args, io);
4787 if (args.limit == 0)
4788 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4789 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4790 rb_yield(str);
4791 }
4792 return io;
4793}
4794
4795/*
4796 * call-seq:
4797 * each_byte {|byte| ... } -> self
4798 * each_byte -> enumerator
4799 *
4800 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4801 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4802 *
4803 * File.read('t.ja') # => "こんにちは"
4804 * f = File.new('t.ja')
4805 * a = []
4806 * f.each_byte {|b| a << b }
4807 * a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
4808 * f.close
4809 *
4810 * Returns an Enumerator if no block is given.
4811 *
4812 * Related: IO#each_char, IO#each_codepoint.
4813 *
4814 */
4815
4816static VALUE
4817rb_io_each_byte(VALUE io)
4818{
4819 rb_io_t *fptr;
4820
4821 RETURN_ENUMERATOR(io, 0, 0);
4822 GetOpenFile(io, fptr);
4823
4824 do {
4825 while (fptr->rbuf.len > 0) {
4826 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4827 fptr->rbuf.len--;
4828 rb_yield(INT2FIX(*p & 0xff));
4830 errno = 0;
4831 }
4832 READ_CHECK(fptr);
4833 } while (io_fillbuf(fptr) >= 0);
4834 return io;
4835}
4836
4837static VALUE
4838io_getc(rb_io_t *fptr, rb_encoding *enc)
4839{
4840 int r, n, cr = 0;
4841 VALUE str;
4842
4843 if (NEED_READCONV(fptr)) {
4844 rb_encoding *read_enc = io_read_encoding(fptr);
4845
4846 str = Qnil;
4847 SET_BINARY_MODE(fptr);
4848 make_readconv(fptr, 0);
4849
4850 while (1) {
4851 if (fptr->cbuf.len) {
4852 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4853 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4854 read_enc);
4855 if (!MBCLEN_NEEDMORE_P(r))
4856 break;
4857 if (fptr->cbuf.len == fptr->cbuf.capa) {
4858 rb_raise(rb_eIOError, "too long character");
4859 }
4860 }
4861
4862 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4863 if (fptr->cbuf.len == 0) {
4864 clear_readconv(fptr);
4865 return Qnil;
4866 }
4867 /* return an unit of an incomplete character just before EOF */
4868 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4869 fptr->cbuf.off += 1;
4870 fptr->cbuf.len -= 1;
4871 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4873 return str;
4874 }
4875 }
4876 if (MBCLEN_INVALID_P(r)) {
4877 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4878 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4879 read_enc);
4880 io_shift_cbuf(fptr, r, &str);
4882 }
4883 else {
4884 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4886 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4887 ISASCII(RSTRING_PTR(str)[0])) {
4888 cr = ENC_CODERANGE_7BIT;
4889 }
4890 }
4891 str = io_enc_str(str, fptr);
4892 ENC_CODERANGE_SET(str, cr);
4893 return str;
4894 }
4895
4896 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4897 if (io_fillbuf(fptr) < 0) {
4898 return Qnil;
4899 }
4900 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4901 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4902 fptr->rbuf.off += 1;
4903 fptr->rbuf.len -= 1;
4904 cr = ENC_CODERANGE_7BIT;
4905 }
4906 else {
4907 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4908 if (MBCLEN_CHARFOUND_P(r) &&
4909 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4910 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4911 fptr->rbuf.off += n;
4912 fptr->rbuf.len -= n;
4914 }
4915 else if (MBCLEN_NEEDMORE_P(r)) {
4916 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4917 fptr->rbuf.len = 0;
4918 getc_needmore:
4919 if (io_fillbuf(fptr) != -1) {
4920 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4921 fptr->rbuf.off++;
4922 fptr->rbuf.len--;
4923 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4924 if (MBCLEN_NEEDMORE_P(r)) {
4925 goto getc_needmore;
4926 }
4927 else if (MBCLEN_CHARFOUND_P(r)) {
4929 }
4930 }
4931 }
4932 else {
4933 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4934 fptr->rbuf.off++;
4935 fptr->rbuf.len--;
4936 }
4937 }
4938 if (!cr) cr = ENC_CODERANGE_BROKEN;
4939 str = io_enc_str(str, fptr);
4940 ENC_CODERANGE_SET(str, cr);
4941 return str;
4942}
4943
4944/*
4945 * call-seq:
4946 * each_char {|c| ... } -> self
4947 * each_char -> enumerator
4948 *
4949 * Calls the given block with each character in the stream; returns +self+.
4950 * See {Character IO}[rdoc-ref:IO@Character+IO].
4951 *
4952 * File.read('t.ja') # => "こんにちは"
4953 * f = File.new('t.ja')
4954 * a = []
4955 * f.each_char {|c| a << c.ord }
4956 * a # => [12371, 12435, 12395, 12385, 12399]
4957 * f.close
4958 *
4959 * Returns an Enumerator if no block is given.
4960 *
4961 * Related: IO#each_byte, IO#each_codepoint.
4962 *
4963 */
4964
4965static VALUE
4966rb_io_each_char(VALUE io)
4967{
4968 rb_io_t *fptr;
4969 rb_encoding *enc;
4970 VALUE c;
4971
4972 RETURN_ENUMERATOR(io, 0, 0);
4973 GetOpenFile(io, fptr);
4975
4976 enc = io_input_encoding(fptr);
4977 READ_CHECK(fptr);
4978 while (!NIL_P(c = io_getc(fptr, enc))) {
4979 rb_yield(c);
4980 }
4981 return io;
4982}
4983
4984/*
4985 * call-seq:
4986 * each_codepoint {|c| ... } -> self
4987 * each_codepoint -> enumerator
4988 *
4989 * Calls the given block with each codepoint in the stream; returns +self+:
4990 *
4991 * File.read('t.ja') # => "こんにちは"
4992 * f = File.new('t.ja')
4993 * a = []
4994 * f.each_codepoint {|c| a << c }
4995 * a # => [12371, 12435, 12395, 12385, 12399]
4996 * f.close
4997 *
4998 * Returns an Enumerator if no block is given.
4999 *
5000 * Related: IO#each_byte, IO#each_char.
5001 *
5002 */
5003
5004static VALUE
5005rb_io_each_codepoint(VALUE io)
5006{
5007 rb_io_t *fptr;
5008 rb_encoding *enc;
5009 unsigned int c;
5010 int r, n;
5011
5012 RETURN_ENUMERATOR(io, 0, 0);
5013 GetOpenFile(io, fptr);
5015
5016 READ_CHECK(fptr);
5017 enc = io_read_encoding(fptr);
5018 if (NEED_READCONV(fptr)) {
5019 SET_BINARY_MODE(fptr);
5020 r = 1; /* no invalid char yet */
5021 for (;;) {
5022 make_readconv(fptr, 0);
5023 for (;;) {
5024 if (fptr->cbuf.len) {
5025 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
5026 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5027 enc);
5028 if (!MBCLEN_NEEDMORE_P(r))
5029 break;
5030 if (fptr->cbuf.len == fptr->cbuf.capa) {
5031 rb_raise(rb_eIOError, "too long character");
5032 }
5033 }
5034 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5035 clear_readconv(fptr);
5036 if (!MBCLEN_CHARFOUND_P(r)) {
5037 goto invalid;
5038 }
5039 return io;
5040 }
5041 }
5042 if (MBCLEN_INVALID_P(r)) {
5043 goto invalid;
5044 }
5045 n = MBCLEN_CHARFOUND_LEN(r);
5046 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
5047 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5048 enc);
5049 fptr->cbuf.off += n;
5050 fptr->cbuf.len -= n;
5051 rb_yield(UINT2NUM(c));
5053 }
5054 }
5055 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5056 while (io_fillbuf(fptr) >= 0) {
5057 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
5058 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5059 if (MBCLEN_CHARFOUND_P(r) &&
5060 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
5061 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
5062 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5063 fptr->rbuf.off += n;
5064 fptr->rbuf.len -= n;
5065 rb_yield(UINT2NUM(c));
5066 }
5067 else if (MBCLEN_INVALID_P(r)) {
5068 goto invalid;
5069 }
5070 else if (MBCLEN_NEEDMORE_P(r)) {
5071 char cbuf[8], *p = cbuf;
5072 int more = MBCLEN_NEEDMORE_LEN(r);
5073 if (more > numberof(cbuf)) goto invalid;
5074 more += n = fptr->rbuf.len;
5075 if (more > numberof(cbuf)) goto invalid;
5076 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
5077 (p += n, (more -= n) > 0)) {
5078 if (io_fillbuf(fptr) < 0) goto invalid;
5079 if ((n = fptr->rbuf.len) > more) n = more;
5080 }
5081 r = rb_enc_precise_mbclen(cbuf, p, enc);
5082 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
5083 c = rb_enc_codepoint(cbuf, p, enc);
5084 rb_yield(UINT2NUM(c));
5085 }
5086 else {
5087 continue;
5088 }
5090 }
5091 return io;
5092
5093 invalid:
5094 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
5096}
5097
5098/*
5099 * call-seq:
5100 * getc -> character or nil
5101 *
5102 * Reads and returns the next 1-character string from the stream;
5103 * returns +nil+ if already at end-of-stream.
5104 * See {Character IO}[rdoc-ref:IO@Character+IO].
5105 *
5106 * f = File.open('t.txt')
5107 * f.getc # => "F"
5108 * f.close
5109 * File.read('t.ja') # => "こんにちは"
5110 * f = File.open('t.ja')
5111 * f.getc.ord # => 12371
5112 * f.close
5113 *
5114 * Related: IO#readchar (may raise EOFError).
5115 *
5116 */
5117
5118static VALUE
5119rb_io_getc(VALUE io)
5120{
5121 rb_io_t *fptr;
5122 rb_encoding *enc;
5123
5124 GetOpenFile(io, fptr);
5126
5127 enc = io_input_encoding(fptr);
5128 READ_CHECK(fptr);
5129 return io_getc(fptr, enc);
5130}
5131
5132/*
5133 * call-seq:
5134 * readchar -> string
5135 *
5136 * Reads and returns the next 1-character string from the stream;
5137 * raises EOFError if already at end-of-stream.
5138 * See {Character IO}[rdoc-ref:IO@Character+IO].
5139 *
5140 * f = File.open('t.txt')
5141 * f.readchar # => "F"
5142 * f.close
5143 * File.read('t.ja') # => "こんにちは"
5144 * f = File.open('t.ja')
5145 * f.readchar.ord # => 12371
5146 * f.close
5147 *
5148 * Related: IO#getc (will not raise EOFError).
5149 *
5150 */
5151
5152static VALUE
5153rb_io_readchar(VALUE io)
5154{
5155 VALUE c = rb_io_getc(io);
5156
5157 if (NIL_P(c)) {
5158 rb_eof_error();
5159 }
5160 return c;
5161}
5162
5163/*
5164 * call-seq:
5165 * getbyte -> integer or nil
5166 *
5167 * Reads and returns the next byte (in range 0..255) from the stream;
5168 * returns +nil+ if already at end-of-stream.
5169 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5170 *
5171 * f = File.open('t.txt')
5172 * f.getbyte # => 70
5173 * f.close
5174 * File.read('t.ja') # => "こんにちは"
5175 * f = File.open('t.ja')
5176 * f.getbyte # => 227
5177 * f.close
5178 *
5179 * Related: IO#readbyte (may raise EOFError).
5180 */
5181
5182VALUE
5184{
5185 rb_io_t *fptr;
5186 int c;
5187
5188 GetOpenFile(io, fptr);
5190 READ_CHECK(fptr);
5191 VALUE r_stdout = rb_ractor_stdout();
5192 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5193 rb_io_t *ofp;
5194 GetOpenFile(r_stdout, ofp);
5195 if (ofp->mode & FMODE_TTY) {
5196 rb_io_flush(r_stdout);
5197 }
5198 }
5199 if (io_fillbuf(fptr) < 0) {
5200 return Qnil;
5201 }
5202 fptr->rbuf.off++;
5203 fptr->rbuf.len--;
5204 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5205 return INT2FIX(c & 0xff);
5206}
5207
5208/*
5209 * call-seq:
5210 * readbyte -> integer
5211 *
5212 * Reads and returns the next byte (in range 0..255) from the stream;
5213 * raises EOFError if already at end-of-stream.
5214 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5215 *
5216 * f = File.open('t.txt')
5217 * f.readbyte # => 70
5218 * f.close
5219 * File.read('t.ja') # => "こんにちは"
5220 * f = File.open('t.ja')
5221 * f.readbyte # => 227
5222 * f.close
5223 *
5224 * Related: IO#getbyte (will not raise EOFError).
5225 *
5226 */
5227
5228static VALUE
5229rb_io_readbyte(VALUE io)
5230{
5231 VALUE c = rb_io_getbyte(io);
5232
5233 if (NIL_P(c)) {
5234 rb_eof_error();
5235 }
5236 return c;
5237}
5238
5239/*
5240 * call-seq:
5241 * ungetbyte(integer) -> nil
5242 * ungetbyte(string) -> nil
5243 *
5244 * Pushes back ("unshifts") the given data onto the stream's buffer,
5245 * placing the data so that it is next to be read; returns +nil+.
5246 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5247 *
5248 * Note that:
5249 *
5250 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5251 * - Calling #rewind on the stream discards the pushed-back data.
5252 *
5253 * When argument +integer+ is given, uses only its low-order byte:
5254 *
5255 * File.write('t.tmp', '012')
5256 * f = File.open('t.tmp')
5257 * f.ungetbyte(0x41) # => nil
5258 * f.read # => "A012"
5259 * f.rewind
5260 * f.ungetbyte(0x4243) # => nil
5261 * f.read # => "C012"
5262 * f.close
5263 *
5264 * When argument +string+ is given, uses all bytes:
5265 *
5266 * File.write('t.tmp', '012')
5267 * f = File.open('t.tmp')
5268 * f.ungetbyte('A') # => nil
5269 * f.read # => "A012"
5270 * f.rewind
5271 * f.ungetbyte('BCDE') # => nil
5272 * f.read # => "BCDE012"
5273 * f.close
5274 *
5275 */
5276
5277VALUE
5279{
5280 rb_io_t *fptr;
5281
5282 GetOpenFile(io, fptr);
5284 switch (TYPE(b)) {
5285 case T_NIL:
5286 return Qnil;
5287 case T_FIXNUM:
5288 case T_BIGNUM: ;
5289 VALUE v = rb_int_modulo(b, INT2FIX(256));
5290 unsigned char c = NUM2INT(v) & 0xFF;
5291 b = rb_str_new((const char *)&c, 1);
5292 break;
5293 default:
5294 StringValue(b);
5295 }
5296 io_ungetbyte(b, fptr);
5297 return Qnil;
5298}
5299
5300/*
5301 * call-seq:
5302 * ungetc(integer) -> nil
5303 * ungetc(string) -> nil
5304 *
5305 * Pushes back ("unshifts") the given data onto the stream's buffer,
5306 * placing the data so that it is next to be read; returns +nil+.
5307 * See {Character IO}[rdoc-ref:IO@Character+IO].
5308 *
5309 * Note that:
5310 *
5311 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5312 * - Calling #rewind on the stream discards the pushed-back data.
5313 *
5314 * When argument +integer+ is given, interprets the integer as a character:
5315 *
5316 * File.write('t.tmp', '012')
5317 * f = File.open('t.tmp')
5318 * f.ungetc(0x41) # => nil
5319 * f.read # => "A012"
5320 * f.rewind
5321 * f.ungetc(0x0442) # => nil
5322 * f.getc.ord # => 1090
5323 * f.close
5324 *
5325 * When argument +string+ is given, uses all characters:
5326 *
5327 * File.write('t.tmp', '012')
5328 * f = File.open('t.tmp')
5329 * f.ungetc('A') # => nil
5330 * f.read # => "A012"
5331 * f.rewind
5332 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5333 * f.getc.ord # => 1090
5334 * f.getc.ord # => 1077
5335 * f.getc.ord # => 1089
5336 * f.getc.ord # => 1090
5337 * f.close
5338 *
5339 */
5340
5341VALUE
5343{
5344 rb_io_t *fptr;
5345 long len;
5346
5347 GetOpenFile(io, fptr);
5349 if (FIXNUM_P(c)) {
5350 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5351 }
5352 else if (RB_BIGNUM_TYPE_P(c)) {
5353 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5354 }
5355 else {
5356 StringValue(c);
5357 }
5358 if (NEED_READCONV(fptr)) {
5359 SET_BINARY_MODE(fptr);
5360 len = RSTRING_LEN(c);
5361#if SIZEOF_LONG > SIZEOF_INT
5362 if (len > INT_MAX)
5363 rb_raise(rb_eIOError, "ungetc failed");
5364#endif
5365 make_readconv(fptr, (int)len);
5366 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5367 rb_raise(rb_eIOError, "ungetc failed");
5368 if (fptr->cbuf.off < len) {
5369 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5370 fptr->cbuf.ptr+fptr->cbuf.off,
5371 char, fptr->cbuf.len);
5372 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5373 }
5374 fptr->cbuf.off -= (int)len;
5375 fptr->cbuf.len += (int)len;
5376 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5377 }
5378 else {
5379 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5380 io_ungetbyte(c, fptr);
5381 }
5382 return Qnil;
5383}
5384
5385/*
5386 * call-seq:
5387 * isatty -> true or false
5388 *
5389 * Returns +true+ if the stream is associated with a terminal device (tty),
5390 * +false+ otherwise:
5391 *
5392 * f = File.new('t.txt').isatty #=> false
5393 * f.close
5394 * f = File.new('/dev/tty').isatty #=> true
5395 * f.close
5396 *
5397 */
5398
5399static VALUE
5400rb_io_isatty(VALUE io)
5401{
5402 rb_io_t *fptr;
5403
5404 GetOpenFile(io, fptr);
5405 return RBOOL(isatty(fptr->fd) != 0);
5406}
5407
5408#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5409/*
5410 * call-seq:
5411 * close_on_exec? -> true or false
5412 *
5413 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5414 *
5415 * f = File.open('t.txt')
5416 * f.close_on_exec? # => true
5417 * f.close_on_exec = false
5418 * f.close_on_exec? # => false
5419 * f.close
5420 *
5421 */
5422
5423static VALUE
5424rb_io_close_on_exec_p(VALUE io)
5425{
5426 rb_io_t *fptr;
5427 VALUE write_io;
5428 int fd, ret;
5429
5430 write_io = GetWriteIO(io);
5431 if (io != write_io) {
5432 GetOpenFile(write_io, fptr);
5433 if (fptr && 0 <= (fd = fptr->fd)) {
5434 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5435 if (!(ret & FD_CLOEXEC)) return Qfalse;
5436 }
5437 }
5438
5439 GetOpenFile(io, fptr);
5440 if (fptr && 0 <= (fd = fptr->fd)) {
5441 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5442 if (!(ret & FD_CLOEXEC)) return Qfalse;
5443 }
5444 return Qtrue;
5445}
5446#else
5447#define rb_io_close_on_exec_p rb_f_notimplement
5448#endif
5449
5450#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5451/*
5452 * call-seq:
5453 * self.close_on_exec = bool -> true or false
5454 *
5455 * Sets a close-on-exec flag.
5456 *
5457 * f = File.open(File::NULL)
5458 * f.close_on_exec = true
5459 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5460 * f.closed? #=> false
5461 *
5462 * Ruby sets close-on-exec flags of all file descriptors by default
5463 * since Ruby 2.0.0.
5464 * So you don't need to set by yourself.
5465 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5466 * if another thread use fork() and exec() (via system() method for example).
5467 * If you really needs file descriptor inheritance to child process,
5468 * use spawn()'s argument such as fd=>fd.
5469 */
5470
5471static VALUE
5472rb_io_set_close_on_exec(VALUE io, VALUE arg)
5473{
5474 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5475 rb_io_t *fptr;
5476 VALUE write_io;
5477 int fd, ret;
5478
5479 write_io = GetWriteIO(io);
5480 if (io != write_io) {
5481 GetOpenFile(write_io, fptr);
5482 if (fptr && 0 <= (fd = fptr->fd)) {
5483 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5484 if ((ret & FD_CLOEXEC) != flag) {
5485 ret = (ret & ~FD_CLOEXEC) | flag;
5486 ret = fcntl(fd, F_SETFD, ret);
5487 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5488 }
5489 }
5490
5491 }
5492
5493 GetOpenFile(io, fptr);
5494 if (fptr && 0 <= (fd = fptr->fd)) {
5495 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5496 if ((ret & FD_CLOEXEC) != flag) {
5497 ret = (ret & ~FD_CLOEXEC) | flag;
5498 ret = fcntl(fd, F_SETFD, ret);
5499 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5500 }
5501 }
5502 return Qnil;
5503}
5504#else
5505#define rb_io_set_close_on_exec rb_f_notimplement
5506#endif
5507
5508#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5509#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5510
5511static VALUE
5512finish_writeconv(rb_io_t *fptr, int noalloc)
5513{
5514 unsigned char *ds, *dp, *de;
5516
5517 if (!fptr->wbuf.ptr) {
5518 unsigned char buf[1024];
5519
5521 while (res == econv_destination_buffer_full) {
5522 ds = dp = buf;
5523 de = buf + sizeof(buf);
5524 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5525 while (dp-ds) {
5526 size_t remaining = dp-ds;
5527 long result = rb_io_write_memory(fptr, ds, remaining);
5528
5529 if (result > 0) {
5530 ds += result;
5531 if ((size_t)result == remaining) break;
5532 }
5533 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5534 if (fptr->fd < 0)
5535 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5536 }
5537 else {
5538 return noalloc ? Qtrue : INT2NUM(errno);
5539 }
5540 }
5541 if (res == econv_invalid_byte_sequence ||
5542 res == econv_incomplete_input ||
5544 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5545 }
5546 }
5547
5548 return Qnil;
5549 }
5550
5552 while (res == econv_destination_buffer_full) {
5553 if (fptr->wbuf.len == fptr->wbuf.capa) {
5554 if (io_fflush(fptr) < 0) {
5555 return noalloc ? Qtrue : INT2NUM(errno);
5556 }
5557 }
5558
5559 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5560 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5561 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5562 fptr->wbuf.len += (int)(dp - ds);
5563 if (res == econv_invalid_byte_sequence ||
5564 res == econv_incomplete_input ||
5566 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5567 }
5568 }
5569 return Qnil;
5570}
5571
5573 rb_io_t *fptr;
5574 int noalloc;
5575};
5576
5577static VALUE
5578finish_writeconv_sync(VALUE arg)
5579{
5580 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5581 return finish_writeconv(p->fptr, p->noalloc);
5582}
5583
5584static void*
5585nogvl_close(void *ptr)
5586{
5587 int *fd = ptr;
5588
5589 return (void*)(intptr_t)close(*fd);
5590}
5591
5592static int
5593maygvl_close(int fd, int keepgvl)
5594{
5595 if (keepgvl)
5596 return close(fd);
5597
5598 /*
5599 * close() may block for certain file types (NFS, SO_LINGER sockets,
5600 * inotify), so let other threads run.
5601 */
5602 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5603}
5604
5605static void*
5606nogvl_fclose(void *ptr)
5607{
5608 FILE *file = ptr;
5609
5610 return (void*)(intptr_t)fclose(file);
5611}
5612
5613static int
5614maygvl_fclose(FILE *file, int keepgvl)
5615{
5616 if (keepgvl)
5617 return fclose(file);
5618
5619 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5620}
5621
5622static void free_io_buffer(rb_io_buffer_t *buf);
5623
5624static void
5625fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5626{
5627 VALUE error = Qnil;
5628 int fd = fptr->fd;
5629 FILE *stdio_file = fptr->stdio_file;
5630 int mode = fptr->mode;
5631
5632 if (fptr->writeconv) {
5633 if (!NIL_P(fptr->write_lock) && !noraise) {
5634 struct finish_writeconv_arg arg;
5635 arg.fptr = fptr;
5636 arg.noalloc = noraise;
5637 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5638 }
5639 else {
5640 error = finish_writeconv(fptr, noraise);
5641 }
5642 }
5643 /* Do not flush the write buffer on close when the stream is in sync
5644 * mode. In sync mode Ruby's write buffer is not authoritative (writes go
5645 * straight to the OS), so any bytes left in the buffer are the result of
5646 * writes made while sync was disabled. Setting sync = true is therefore a
5647 * way to abandon that pending output rather than replaying it on close,
5648 * which matters after an interrupted write where the amount actually
5649 * written is indeterminate. Call flush before enabling sync if the
5650 * buffered data should still be sent. */
5651 if (fptr->wbuf.len && !(fptr->mode & FMODE_SYNC)) {
5652 if (noraise) {
5653 io_flush_buffer_sync(fptr);
5654 }
5655 else {
5656 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5657 error = INT2NUM(errno);
5658 }
5659 }
5660 }
5661
5662 int done = 0;
5663
5664 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5665 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5666 done = 1;
5667 }
5668
5669 fptr->fd = -1;
5670 fptr->stdio_file = 0;
5672
5673 // Wait for blocking operations to ensure they do not hit EBADF:
5674 rb_thread_io_close_wait(fptr);
5675
5676 if (!done && stdio_file) {
5677 // stdio_file is deallocated anyway even if fclose failed.
5678 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5679 if (!noraise) {
5680 error = INT2NUM(errno);
5681 }
5682 }
5683
5684 done = 1;
5685 }
5686
5687 VALUE scheduler = rb_fiber_scheduler_current();
5688 if (!done && fd >= 0 && scheduler != Qnil) {
5689 VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
5690
5691 if (!UNDEF_P(result)) {
5692 done = RTEST(result);
5693 }
5694 }
5695
5696 if (!done && fd >= 0) {
5697 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5698 // We assumes it is closed.
5699
5700 keepgvl |= !(mode & FMODE_WRITABLE);
5701 keepgvl |= noraise;
5702 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5703 if (!noraise) {
5704 error = INT2NUM(errno);
5705 }
5706 }
5707
5708 done = 1;
5709 }
5710
5711 if (!NIL_P(error) && !noraise) {
5712 if (RB_INTEGER_TYPE_P(error))
5713 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5714 else
5715 rb_exc_raise(error);
5716 }
5717}
5718
5719static void
5720fptr_finalize(rb_io_t *fptr, int noraise)
5721{
5722 fptr_finalize_flush(fptr, noraise, FALSE);
5723 free_io_buffer(&fptr->rbuf);
5724 free_io_buffer(&fptr->wbuf);
5725 clear_codeconv(fptr);
5726}
5727
5728static void
5729rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5730{
5731 if (fptr->finalize) {
5732 (*fptr->finalize)(fptr, noraise);
5733 }
5734 else {
5735 fptr_finalize(fptr, noraise);
5736 }
5737}
5738
5739static void
5740free_io_buffer(rb_io_buffer_t *buf)
5741{
5742 if (buf->ptr) {
5743 ruby_xfree_sized(buf->ptr, (size_t)buf->capa);
5744 buf->ptr = NULL;
5745 }
5746 buf->off = buf->len = buf->capa = 0;
5747}
5748
5749static void
5750clear_readconv(rb_io_t *fptr)
5751{
5752 if (fptr->readconv) {
5753 rb_econv_close(fptr->readconv);
5754 fptr->readconv = NULL;
5755 }
5756 free_io_buffer(&fptr->cbuf);
5757}
5758
5759static void
5760clear_writeconv(rb_io_t *fptr)
5761{
5762 if (fptr->writeconv) {
5764 fptr->writeconv = NULL;
5765 }
5766 fptr->writeconv_initialized = 0;
5767}
5768
5769static void
5770clear_codeconv(rb_io_t *fptr)
5771{
5772 clear_readconv(fptr);
5773 clear_writeconv(fptr);
5774}
5775
5776static void
5777rb_io_fptr_cleanup_all(rb_io_t *fptr)
5778{
5779 fptr->pathv = Qnil;
5780 if (0 <= fptr->fd)
5781 rb_io_fptr_cleanup(fptr, TRUE);
5782 fptr->write_lock = Qnil;
5783 free_io_buffer(&fptr->rbuf);
5784 free_io_buffer(&fptr->wbuf);
5785 clear_codeconv(fptr);
5786}
5787
5788int
5790{
5791 if (!io) return 0;
5792 rb_io_fptr_cleanup_all(io);
5793 free(io);
5794
5795 return 1;
5796}
5797
5798bool
5799rb_io_fptr_finalize_closed(struct rb_io *io)
5800{
5801 if (!io) return true;
5802 if (io->fd >= 0) return false;
5804 return true;
5805}
5806
5807size_t
5808rb_io_memsize(const rb_io_t *io)
5809{
5810 size_t size = sizeof(rb_io_t);
5811 size += io->rbuf.capa;
5812 size += io->wbuf.capa;
5813 size += io->cbuf.capa;
5814 if (io->readconv) size += rb_econv_memsize(io->readconv);
5815 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5816
5817 struct rb_io_blocking_operation *blocking_operation = 0;
5818
5819 // 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.
5820 rb_serial_t fork_generation = GET_VM()->fork_gen;
5821 if (io->fork_generation == fork_generation) {
5822 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5823 size += sizeof(struct rb_io_blocking_operation);
5824 }
5825 }
5826
5827 return size;
5828}
5829
5830#ifdef _WIN32
5831/* keep GVL while closing to prevent crash on Windows */
5832# define KEEPGVL TRUE
5833#else
5834# define KEEPGVL FALSE
5835#endif
5836
5837static rb_io_t *
5838io_close_fptr(VALUE io)
5839{
5840 rb_io_t *fptr;
5841 VALUE write_io;
5842 rb_io_t *write_fptr;
5843
5844 write_io = GetWriteIO(io);
5845 if (io != write_io) {
5846 write_fptr = RFILE(write_io)->fptr;
5847 if (write_fptr && 0 <= write_fptr->fd) {
5848 rb_io_fptr_cleanup(write_fptr, TRUE);
5849 }
5850 }
5851
5852 fptr = RFILE(io)->fptr;
5853 if (!fptr) return 0;
5854 if (fptr->fd < 0) return 0;
5855
5856 // This guards against multiple threads closing the same IO object:
5857 if (rb_thread_io_close_interrupt(fptr)) {
5858 /* calls close(fptr->fd): */
5859 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5860 }
5861
5862 rb_io_fptr_cleanup(fptr, FALSE);
5863 return fptr;
5864}
5865
5866static void
5867fptr_waitpid(rb_io_t *fptr, int nohang)
5868{
5869 int status;
5870 if (fptr->pid) {
5871 rb_last_status_clear();
5872 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5873 fptr->pid = 0;
5874 }
5875}
5876
5877VALUE
5879{
5880 rb_io_t *fptr = io_close_fptr(io);
5881 if (fptr) fptr_waitpid(fptr, 0);
5882 return Qnil;
5883}
5884
5885/*
5886 * call-seq:
5887 * close -> nil
5888 *
5889 * Closes the stream for both reading and writing
5890 * if open for either or both; returns +nil+.
5891 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5892 *
5893 * If the stream is open for writing, flushes any buffered writes
5894 * to the operating system before closing.
5895 *
5896 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5897 * (child exit status).
5898 *
5899 * It is not an error to close an IO object that has already been closed.
5900 * It just returns nil.
5901 *
5902 * Example:
5903 *
5904 * IO.popen('ruby', 'r+') do |pipe|
5905 * puts pipe.closed?
5906 * pipe.close
5907 * puts $?
5908 * puts pipe.closed?
5909 * end
5910 *
5911 * Output:
5912 *
5913 * false
5914 * pid 13760 exit 0
5915 * true
5916 *
5917 * Related: IO#close_read, IO#close_write, IO#closed?.
5918 */
5919
5920static VALUE
5921rb_io_close_m(VALUE io)
5922{
5923 rb_io_t *fptr = rb_io_get_fptr(io);
5924 if (fptr->fd < 0) {
5925 return Qnil;
5926 }
5927 rb_io_close(io);
5928 return Qnil;
5929}
5930
5931static VALUE
5932io_call_close(VALUE io)
5933{
5934 rb_check_funcall(io, rb_intern("close"), 0, 0);
5935 return io;
5936}
5937
5938static VALUE
5939ignore_closed_stream(VALUE io, VALUE exc)
5940{
5941 enum {mesg_len = sizeof(closed_stream)-1};
5942 VALUE mesg = rb_attr_get(exc, idMesg);
5943 if (!RB_TYPE_P(mesg, T_STRING) ||
5944 RSTRING_LEN(mesg) != mesg_len ||
5945 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5946 rb_exc_raise(exc);
5947 }
5948 return io;
5949}
5950
5951static VALUE
5952io_close(VALUE io)
5953{
5954 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5955 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5956 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5957 rb_eIOError, (VALUE)0);
5958 return io;
5959}
5960
5961/*
5962 * call-seq:
5963 * closed? -> true or false
5964 *
5965 * Returns +true+ if the stream is closed for both reading and writing,
5966 * +false+ otherwise.
5967 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5968 *
5969 * IO.popen('ruby', 'r+') do |pipe|
5970 * puts pipe.closed?
5971 * pipe.close_read
5972 * puts pipe.closed?
5973 * pipe.close_write
5974 * puts pipe.closed?
5975 * end
5976 *
5977 * Output:
5978 *
5979 * false
5980 * false
5981 * true
5982 *
5983 * Related: IO#close_read, IO#close_write, IO#close.
5984 */
5985VALUE
5987{
5988 rb_io_t *fptr;
5989 VALUE write_io;
5990 rb_io_t *write_fptr;
5991
5992 write_io = GetWriteIO(io);
5993 if (io != write_io) {
5994 write_fptr = RFILE(write_io)->fptr;
5995 if (write_fptr && 0 <= write_fptr->fd) {
5996 return Qfalse;
5997 }
5998 }
5999
6000 fptr = rb_io_get_fptr(io);
6001 return RBOOL(0 > fptr->fd);
6002}
6003
6004/*
6005 * call-seq:
6006 * close_read -> nil
6007 *
6008 * Closes the stream for reading if open for reading;
6009 * returns +nil+.
6010 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6011 *
6012 * If the stream was opened by IO.popen and is also closed for writing,
6013 * sets global variable <tt>$?</tt> (child exit status).
6014 *
6015 * Example:
6016 *
6017 * IO.popen('ruby', 'r+') do |pipe|
6018 * puts pipe.closed?
6019 * pipe.close_write
6020 * puts pipe.closed?
6021 * pipe.close_read
6022 * puts $?
6023 * puts pipe.closed?
6024 * end
6025 *
6026 * Output:
6027 *
6028 * false
6029 * false
6030 * pid 14748 exit 0
6031 * true
6032 *
6033 * Related: IO#close, IO#close_write, IO#closed?.
6034 */
6035
6036static VALUE
6037rb_io_close_read(VALUE io)
6038{
6039 rb_io_t *fptr;
6040 VALUE write_io;
6041
6042 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6043 if (fptr->fd < 0) return Qnil;
6044 if (is_socket(fptr->fd, fptr->pathv)) {
6045#ifndef SHUT_RD
6046# define SHUT_RD 0
6047#endif
6048 if (shutdown(fptr->fd, SHUT_RD) < 0)
6049 rb_sys_fail_path(fptr->pathv);
6050 fptr->mode &= ~FMODE_READABLE;
6051 if (!(fptr->mode & FMODE_WRITABLE))
6052 return rb_io_close(io);
6053 return Qnil;
6054 }
6055
6056 write_io = GetWriteIO(io);
6057 if (io != write_io) {
6058 rb_io_t *wfptr;
6059 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6060 wfptr->pid = fptr->pid;
6061 fptr->pid = 0;
6062 RFILE(io)->fptr = wfptr;
6063 /* bind to write_io temporarily to get rid of memory/fd leak */
6064 fptr->tied_io_for_writing = 0;
6065 RFILE(write_io)->fptr = fptr;
6066 rb_io_fptr_cleanup(fptr, FALSE);
6067 /* should not finalize fptr because another thread may be reading it */
6068 return Qnil;
6069 }
6070
6071 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
6072 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
6073 }
6074 return rb_io_close(io);
6075}
6076
6077/*
6078 * call-seq:
6079 * close_write -> nil
6080 *
6081 * Closes the stream for writing if open for writing;
6082 * returns +nil+.
6083 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6084 *
6085 * Flushes any buffered writes to the operating system before closing.
6086 *
6087 * If the stream was opened by IO.popen and is also closed for reading,
6088 * sets global variable <tt>$?</tt> (child exit status).
6089 *
6090 * IO.popen('ruby', 'r+') do |pipe|
6091 * puts pipe.closed?
6092 * pipe.close_read
6093 * puts pipe.closed?
6094 * pipe.close_write
6095 * puts $?
6096 * puts pipe.closed?
6097 * end
6098 *
6099 * Output:
6100 *
6101 * false
6102 * false
6103 * pid 15044 exit 0
6104 * true
6105 *
6106 * Related: IO#close, IO#close_read, IO#closed?.
6107 */
6108
6109static VALUE
6110rb_io_close_write(VALUE io)
6111{
6112 rb_io_t *fptr;
6113 VALUE write_io;
6114
6115 write_io = GetWriteIO(io);
6116 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6117 if (fptr->fd < 0) return Qnil;
6118 if (is_socket(fptr->fd, fptr->pathv)) {
6119#ifndef SHUT_WR
6120# define SHUT_WR 1
6121#endif
6122 /* Flush any buffered data before shutting down the write side.
6123 * Otherwise the buffered bytes are silently dropped here, and a
6124 * subsequent #close would try to flush them into the now
6125 * shutdown(SHUT_WR) socket and fail with EPIPE. This matches the
6126 * behaviour of the non-socket path below, which flushes via
6127 * rb_io_close(). */
6128 if (fptr->mode & FMODE_WRITABLE) {
6129 if (io_fflush(fptr) < 0)
6130 rb_sys_fail_on_write(fptr);
6131 }
6132 if (shutdown(fptr->fd, SHUT_WR) < 0)
6133 rb_sys_fail_path(fptr->pathv);
6134 fptr->mode &= ~FMODE_WRITABLE;
6135 if (!(fptr->mode & FMODE_READABLE))
6136 return rb_io_close(write_io);
6137 return Qnil;
6138 }
6139
6140 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6141 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6142 }
6143
6144 if (io != write_io) {
6145 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6146 fptr->tied_io_for_writing = 0;
6147 }
6148 rb_io_close(write_io);
6149 return Qnil;
6150}
6151
6152/*
6153 * call-seq:
6154 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6155 *
6156 * Behaves like IO#seek, except that it:
6157 *
6158 * - Uses low-level system functions.
6159 * - Returns the new position.
6160 *
6161 */
6162
6163static VALUE
6164rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6165{
6166 VALUE offset, ptrname;
6167 int whence = SEEK_SET;
6168 rb_io_t *fptr;
6169 rb_off_t pos;
6170
6171 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6172 whence = interpret_seek_whence(ptrname);
6173 }
6174 pos = NUM2OFFT(offset);
6175 GetOpenFile(io, fptr);
6176 if ((fptr->mode & FMODE_READABLE) &&
6177 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6178 rb_raise(rb_eIOError, "sysseek for buffered IO");
6179 }
6180 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6181 rb_warn("sysseek for buffered IO");
6182 }
6183 errno = 0;
6184 pos = lseek(fptr->fd, pos, whence);
6185 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6186
6187 return OFFT2NUM(pos);
6188}
6189
6190/*
6191 * call-seq:
6192 * syswrite(object) -> integer
6193 *
6194 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6195 * returns the number bytes written.
6196 * If +object+ is not a string is converted via method to_s:
6197 *
6198 * f = File.new('t.tmp', 'w')
6199 * f.syswrite('foo') # => 3
6200 * f.syswrite(30) # => 2
6201 * f.syswrite(:foo) # => 3
6202 * f.close
6203 *
6204 * This methods should not be used with other stream-writer methods.
6205 *
6206 */
6207
6208static VALUE
6209rb_io_syswrite(VALUE io, VALUE str)
6210{
6211 VALUE tmp;
6212 rb_io_t *fptr;
6213 long n, len;
6214 const char *ptr;
6215
6216 if (!RB_TYPE_P(str, T_STRING))
6217 str = rb_obj_as_string(str);
6218
6219 io = GetWriteIO(io);
6220 GetOpenFile(io, fptr);
6222
6223 if (fptr->wbuf.len) {
6224 rb_warn("syswrite for buffered IO");
6225 }
6226
6227 tmp = rb_str_tmp_frozen_acquire(str);
6228 RSTRING_GETMEM(tmp, ptr, len);
6229 n = rb_io_write_memory(fptr, ptr, len);
6230 if (n < 0) rb_sys_fail_path(fptr->pathv);
6231 rb_str_tmp_frozen_release(str, tmp);
6232
6233 return LONG2FIX(n);
6234}
6235
6236/*
6237 * call-seq:
6238 * sysread(maxlen) -> string
6239 * sysread(maxlen, out_string) -> string
6240 *
6241 * Behaves like IO#readpartial, except that it uses low-level system functions.
6242 *
6243 * This method should not be used with other stream-reader methods.
6244 *
6245 */
6246
6247static VALUE
6248rb_io_sysread(int argc, VALUE *argv, VALUE io)
6249{
6250 VALUE len, str;
6251 rb_io_t *fptr;
6252 long n, ilen;
6253 struct io_internal_read_struct iis;
6254 int shrinkable;
6255
6256 rb_scan_args(argc, argv, "11", &len, &str);
6257 ilen = NUM2LONG(len);
6258
6259 shrinkable = io_setstrbuf(&str, ilen);
6260 if (ilen == 0) return str;
6261
6262 GetOpenFile(io, fptr);
6264
6265 if (READ_DATA_BUFFERED(fptr)) {
6266 rb_raise(rb_eIOError, "sysread for buffered IO");
6267 }
6268
6269 rb_io_check_closed(fptr);
6270
6271 io_setstrbuf(&str, ilen);
6272 iis.th = rb_thread_current();
6273 iis.fptr = fptr;
6274 iis.nonblock = 0;
6275 iis.fd = fptr->fd;
6276 iis.buf = RSTRING_PTR(str);
6277 iis.capa = ilen;
6278 iis.timeout = NULL;
6279 n = io_read_memory_locktmp(str, &iis);
6280
6281 if (n < 0) {
6282 rb_sys_fail_path(fptr->pathv);
6283 }
6284
6285 io_set_read_length(str, n, shrinkable);
6286
6287 if (n == 0 && ilen > 0) {
6288 rb_eof_error();
6289 }
6290
6291 return str;
6292}
6293
6295 struct rb_io *io;
6296 int fd;
6297 void *buf;
6298 size_t count;
6299 rb_off_t offset;
6300};
6301
6302static VALUE
6303internal_pread_func(void *_arg)
6304{
6305 struct prdwr_internal_arg *arg = _arg;
6306
6307 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6308}
6309
6310static VALUE
6311pread_internal_call(VALUE _arg)
6312{
6313 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6314
6315 VALUE scheduler = rb_fiber_scheduler_current();
6316 if (scheduler != Qnil) {
6317 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6318
6319 if (!UNDEF_P(result)) {
6321 }
6322 }
6323
6324 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6325}
6326
6327/*
6328 * call-seq:
6329 * pread(maxlen, offset) -> string
6330 * pread(maxlen, offset, out_string) -> string
6331 *
6332 * Behaves like IO#readpartial, except that it:
6333 *
6334 * - Reads at the given +offset+ (in bytes).
6335 * - Disregards, and does not modify, the stream's position
6336 * (see {Position}[rdoc-ref:IO@Position]).
6337 * - Bypasses any user space buffering in the stream.
6338 *
6339 * Because this method does not disturb the stream's state
6340 * (its position, in particular), +pread+ allows multiple threads and processes
6341 * to use the same \IO object for reading at various offsets.
6342 *
6343 * f = File.open('t.txt')
6344 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6345 * f.pos # => 52
6346 * # Read 12 bytes at offset 0.
6347 * f.pread(12, 0) # => "First line\n"
6348 * # Read 9 bytes at offset 8.
6349 * f.pread(9, 8) # => "ne\nSecon"
6350 * f.close
6351 *
6352 * Not available on some platforms.
6353 *
6354 */
6355static VALUE
6356rb_io_pread(int argc, VALUE *argv, VALUE io)
6357{
6358 VALUE len, offset, str;
6359 rb_io_t *fptr;
6360 ssize_t n;
6361 struct prdwr_internal_arg arg;
6362 int shrinkable;
6363
6364 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6365 arg.count = NUM2SIZET(len);
6366 arg.offset = NUM2OFFT(offset);
6367
6368 shrinkable = io_setstrbuf(&str, (long)arg.count);
6369 if (arg.count == 0) return str;
6370 arg.buf = RSTRING_PTR(str);
6371
6372 GetOpenFile(io, fptr);
6374
6375 arg.io = fptr;
6376 arg.fd = fptr->fd;
6377 rb_io_check_closed(fptr);
6378
6379 rb_str_locktmp(str);
6380 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6381
6382 if (n < 0) {
6383 rb_sys_fail_path(fptr->pathv);
6384 }
6385 io_set_read_length(str, n, shrinkable);
6386 if (n == 0 && arg.count > 0) {
6387 rb_eof_error();
6388 }
6389
6390 return str;
6391}
6392
6393static VALUE
6394internal_pwrite_func(void *_arg)
6395{
6396 struct prdwr_internal_arg *arg = _arg;
6397
6398 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6399}
6400
6401static VALUE
6402pwrite_internal_call(VALUE _arg)
6403{
6404 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6405
6406 VALUE scheduler = rb_fiber_scheduler_current();
6407 if (scheduler != Qnil) {
6408 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6409
6410 if (!UNDEF_P(result)) {
6412 }
6413 }
6414
6415 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
6416}
6417
6418/*
6419 * call-seq:
6420 * pwrite(object, offset) -> integer
6421 *
6422 * Behaves like IO#write, except that it:
6423 *
6424 * - Writes at the given +offset+ (in bytes).
6425 * - Disregards, and does not modify, the stream's position
6426 * (see {Position}[rdoc-ref:IO@Position]).
6427 * - Bypasses any user space buffering in the stream.
6428 *
6429 * Because this method does not disturb the stream's state
6430 * (its position, in particular), +pwrite+ allows multiple threads and processes
6431 * to use the same \IO object for writing at various offsets.
6432 *
6433 * f = File.open('t.tmp', 'w+')
6434 * # Write 6 bytes at offset 3.
6435 * f.pwrite('ABCDEF', 3) # => 6
6436 * f.rewind
6437 * f.read # => "\u0000\u0000\u0000ABCDEF"
6438 * f.close
6439 *
6440 * Not available on some platforms.
6441 *
6442 */
6443static VALUE
6444rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6445{
6446 rb_io_t *fptr;
6447 ssize_t n;
6448 struct prdwr_internal_arg arg;
6449 VALUE tmp;
6450
6451 if (!RB_TYPE_P(str, T_STRING))
6452 str = rb_obj_as_string(str);
6453
6454 arg.offset = NUM2OFFT(offset);
6455
6456 io = GetWriteIO(io);
6457 GetOpenFile(io, fptr);
6459
6460 arg.io = fptr;
6461 arg.fd = fptr->fd;
6462
6463 tmp = rb_str_tmp_frozen_acquire(str);
6464 arg.buf = RSTRING_PTR(tmp);
6465 arg.count = (size_t)RSTRING_LEN(tmp);
6466
6467 n = (ssize_t)pwrite_internal_call((VALUE)&arg);
6468 if (n < 0) rb_sys_fail_path(fptr->pathv);
6469 rb_str_tmp_frozen_release(str, tmp);
6470
6471 return SSIZET2NUM(n);
6472}
6473
6474VALUE
6476{
6477 rb_io_t *fptr;
6478
6479 GetOpenFile(io, fptr);
6480 if (fptr->readconv)
6482 if (fptr->writeconv)
6484 fptr->mode |= FMODE_BINMODE;
6485 fptr->mode &= ~FMODE_TEXTMODE;
6486 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6487#ifdef O_BINARY
6488 if (!fptr->readconv) {
6489 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6490 }
6491 else {
6492 setmode(fptr->fd, O_BINARY);
6493 }
6494#endif
6495 return io;
6496}
6497
6498static void
6499io_ascii8bit_binmode(rb_io_t *fptr)
6500{
6501 if (fptr->readconv) {
6502 rb_econv_close(fptr->readconv);
6503 fptr->readconv = NULL;
6504 }
6505 if (fptr->writeconv) {
6507 fptr->writeconv = NULL;
6508 }
6509 fptr->mode |= FMODE_BINMODE;
6510 fptr->mode &= ~FMODE_TEXTMODE;
6511 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6512
6513 fptr->encs.enc = rb_ascii8bit_encoding();
6514 fptr->encs.enc2 = NULL;
6515 fptr->encs.ecflags = 0;
6516 fptr->encs.ecopts = Qnil;
6517 clear_codeconv(fptr);
6518}
6519
6520VALUE
6522{
6523 rb_io_t *fptr;
6524
6525 GetOpenFile(io, fptr);
6526 io_ascii8bit_binmode(fptr);
6527
6528 return io;
6529}
6530
6531/*
6532 * call-seq:
6533 * binmode -> self
6534 *
6535 * Sets the stream's data mode as binary
6536 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6537 *
6538 * A stream's data mode may not be changed from binary to text.
6539 *
6540 */
6541
6542static VALUE
6543rb_io_binmode_m(VALUE io)
6544{
6545 VALUE write_io;
6546
6548
6549 write_io = GetWriteIO(io);
6550 if (write_io != io)
6551 rb_io_ascii8bit_binmode(write_io);
6552 return io;
6553}
6554
6555/*
6556 * call-seq:
6557 * binmode? -> true or false
6558 *
6559 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6560 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6561 *
6562 */
6563static VALUE
6564rb_io_binmode_p(VALUE io)
6565{
6566 rb_io_t *fptr;
6567 GetOpenFile(io, fptr);
6568 return RBOOL(fptr->mode & FMODE_BINMODE);
6569}
6570
6571static const char*
6572rb_io_fmode_modestr(enum rb_io_mode fmode)
6573{
6574 if (fmode & FMODE_APPEND) {
6575 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6576 return MODE_BTMODE("a+", "ab+", "at+");
6577 }
6578 return MODE_BTMODE("a", "ab", "at");
6579 }
6580 switch (fmode & FMODE_READWRITE) {
6581 default:
6582 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6583 case FMODE_READABLE:
6584 return MODE_BTMODE("r", "rb", "rt");
6585 case FMODE_WRITABLE:
6586 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6587 case FMODE_READWRITE:
6588 if (fmode & FMODE_CREATE) {
6589 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6590 }
6591 return MODE_BTMODE("r+", "rb+", "rt+");
6592 }
6593}
6594
6595static const char bom_prefix[] = "bom|";
6596static const char utf_prefix[] = "utf-";
6597enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6598enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6599
6600static int
6601io_encname_bom_p(const char *name, long len)
6602{
6603 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6604}
6605
6606enum rb_io_mode
6607rb_io_modestr_fmode(const char *modestr)
6608{
6609 enum rb_io_mode fmode = 0;
6610 const char *m = modestr, *p = NULL;
6611
6612 switch (*m++) {
6613 case 'r':
6614 fmode |= FMODE_READABLE;
6615 break;
6616 case 'w':
6618 break;
6619 case 'a':
6621 break;
6622 default:
6623 goto error;
6624 }
6625
6626 while (*m) {
6627 switch (*m++) {
6628 case 'b':
6629 fmode |= FMODE_BINMODE;
6630 break;
6631 case 't':
6632 fmode |= FMODE_TEXTMODE;
6633 break;
6634 case '+':
6635 fmode |= FMODE_READWRITE;
6636 break;
6637 case 'x':
6638 if (modestr[0] != 'w')
6639 goto error;
6640 fmode |= FMODE_EXCL;
6641 break;
6642 default:
6643 goto error;
6644 case ':':
6645 p = strchr(m, ':');
6646 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6647 fmode |= FMODE_SETENC_BY_BOM;
6648 goto finished;
6649 }
6650 }
6651
6652 finished:
6653 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6654 goto error;
6655
6656 return fmode;
6657
6658 error:
6659 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6661}
6662
6663int
6664rb_io_oflags_fmode(int oflags)
6665{
6666 enum rb_io_mode fmode = 0;
6667
6668 switch (oflags & O_ACCMODE) {
6669 case O_RDONLY:
6670 fmode = FMODE_READABLE;
6671 break;
6672 case O_WRONLY:
6673 fmode = FMODE_WRITABLE;
6674 break;
6675 case O_RDWR:
6676 fmode = FMODE_READWRITE;
6677 break;
6678 }
6679
6680 if (oflags & O_APPEND) {
6681 fmode |= FMODE_APPEND;
6682 }
6683 if (oflags & O_TRUNC) {
6684 fmode |= FMODE_TRUNC;
6685 }
6686 if (oflags & O_CREAT) {
6687 fmode |= FMODE_CREATE;
6688 }
6689 if (oflags & O_EXCL) {
6690 fmode |= FMODE_EXCL;
6691 }
6692#ifdef O_BINARY
6693 if (oflags & O_BINARY) {
6694 fmode |= FMODE_BINMODE;
6695 }
6696#endif
6697
6698 return fmode;
6699}
6700
6701static int
6702rb_io_fmode_oflags(enum rb_io_mode fmode)
6703{
6704 int oflags = 0;
6705
6706 switch (fmode & FMODE_READWRITE) {
6707 case FMODE_READABLE:
6708 oflags |= O_RDONLY;
6709 break;
6710 case FMODE_WRITABLE:
6711 oflags |= O_WRONLY;
6712 break;
6713 case FMODE_READWRITE:
6714 oflags |= O_RDWR;
6715 break;
6716 }
6717
6718 if (fmode & FMODE_APPEND) {
6719 oflags |= O_APPEND;
6720 }
6721 if (fmode & FMODE_TRUNC) {
6722 oflags |= O_TRUNC;
6723 }
6724 if (fmode & FMODE_CREATE) {
6725 oflags |= O_CREAT;
6726 }
6727 if (fmode & FMODE_EXCL) {
6728 oflags |= O_EXCL;
6729 }
6730#ifdef O_BINARY
6731 if (fmode & FMODE_BINMODE) {
6732 oflags |= O_BINARY;
6733 }
6734#endif
6735
6736 return oflags;
6737}
6738
6739int
6740rb_io_modestr_oflags(const char *modestr)
6741{
6742 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6743}
6744
6745static const char*
6746rb_io_oflags_modestr(int oflags)
6747{
6748#ifdef O_BINARY
6749# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6750#else
6751# define MODE_BINARY(a,b) (a)
6752#endif
6753 int accmode;
6754 if (oflags & O_EXCL) {
6755 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6756 }
6757 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6758 if (oflags & O_APPEND) {
6759 if (accmode == O_WRONLY) {
6760 return MODE_BINARY("a", "ab");
6761 }
6762 if (accmode == O_RDWR) {
6763 return MODE_BINARY("a+", "ab+");
6764 }
6765 }
6766 switch (accmode) {
6767 default:
6768 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6769 case O_RDONLY:
6770 return MODE_BINARY("r", "rb");
6771 case O_WRONLY:
6772 return MODE_BINARY("w", "wb");
6773 case O_RDWR:
6774 if (oflags & O_TRUNC) {
6775 return MODE_BINARY("w+", "wb+");
6776 }
6777 return MODE_BINARY("r+", "rb+");
6778 }
6779}
6780
6781/*
6782 * Convert external/internal encodings to enc/enc2
6783 * NULL => use default encoding
6784 * Qnil => no encoding specified (internal only)
6785 */
6786static void
6787rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6788{
6789 int default_ext = 0;
6790
6791 if (ext == NULL) {
6792 ext = rb_default_external_encoding();
6793 default_ext = 1;
6794 }
6795 if (rb_is_ascii8bit_enc(ext)) {
6796 /* If external is ASCII-8BIT, no transcoding */
6797 intern = NULL;
6798 }
6799 else if (intern == NULL) {
6800 intern = rb_default_internal_encoding();
6801 }
6802 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6803 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6804 /* No internal encoding => use external + no transcoding */
6805 *enc = (default_ext && intern != ext) ? NULL : ext;
6806 *enc2 = NULL;
6807 }
6808 else {
6809 *enc = intern;
6810 *enc2 = ext;
6811 }
6812}
6813
6814static void
6815unsupported_encoding(const char *name, rb_encoding *enc)
6816{
6817 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6818}
6819
6820static void
6821parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6822 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6823{
6824 const char *p;
6825 char encname[ENCODING_MAXNAMELEN+1];
6826 int idx, idx2;
6827 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6828 rb_encoding *ext_enc, *int_enc;
6829 long len;
6830
6831 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6832
6833 p = strrchr(estr, ':');
6834 len = p ? (p++ - estr) : (long)strlen(estr);
6835 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6836 estr += bom_prefix_len;
6837 len -= bom_prefix_len;
6838 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6839 fmode |= FMODE_SETENC_BY_BOM;
6840 }
6841 else {
6842 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6843 fmode &= ~FMODE_SETENC_BY_BOM;
6844 }
6845 }
6846 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6847 idx = -1;
6848 }
6849 else {
6850 if (p) {
6851 memcpy(encname, estr, len);
6852 encname[len] = '\0';
6853 estr = encname;
6854 }
6855 idx = rb_enc_find_index(estr);
6856 }
6857 if (fmode_p) *fmode_p = fmode;
6858
6859 if (idx >= 0)
6860 ext_enc = rb_enc_from_index(idx);
6861 else {
6862 if (idx != -2)
6863 unsupported_encoding(estr, estr_enc);
6864 ext_enc = NULL;
6865 }
6866
6867 int_enc = NULL;
6868 if (p) {
6869 if (*p == '-' && *(p+1) == '\0') {
6870 /* Special case - "-" => no transcoding */
6871 int_enc = (rb_encoding *)Qnil;
6872 }
6873 else {
6874 idx2 = rb_enc_find_index(p);
6875 if (idx2 < 0)
6876 unsupported_encoding(p, estr_enc);
6877 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6878 int_enc = (rb_encoding *)Qnil;
6879 }
6880 else
6881 int_enc = rb_enc_from_index(idx2);
6882 }
6883 }
6884
6885 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6886}
6887
6888int
6889rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6890{
6891 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6892 int extracted = 0;
6893 rb_encoding *extencoding = NULL;
6894 rb_encoding *intencoding = NULL;
6895
6896 if (!NIL_P(opt)) {
6897 VALUE v;
6898 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6899 if (v != Qnil) encoding = v;
6900 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6901 if (v != Qnil) extenc = v;
6902 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6903 if (!UNDEF_P(v)) intenc = v;
6904 }
6905 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6906 if (!NIL_P(ruby_verbose)) {
6907 int idx = rb_to_encoding_index(encoding);
6908 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6909 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6910 encoding, UNDEF_P(extenc) ? "internal" : "external");
6911 }
6912 encoding = Qnil;
6913 }
6914 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6915 extencoding = rb_to_encoding(extenc);
6916 }
6917 if (!UNDEF_P(intenc)) {
6918 if (NIL_P(intenc)) {
6919 /* internal_encoding: nil => no transcoding */
6920 intencoding = (rb_encoding *)Qnil;
6921 }
6922 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6923 char *p = StringValueCStr(tmp);
6924
6925 if (*p == '-' && *(p+1) == '\0') {
6926 /* Special case - "-" => no transcoding */
6927 intencoding = (rb_encoding *)Qnil;
6928 }
6929 else {
6930 intencoding = rb_to_encoding(intenc);
6931 }
6932 }
6933 else {
6934 intencoding = rb_to_encoding(intenc);
6935 }
6936 if (extencoding == intencoding) {
6937 intencoding = (rb_encoding *)Qnil;
6938 }
6939 }
6940 if (!NIL_P(encoding)) {
6941 extracted = 1;
6942 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6943 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6944 enc_p, enc2_p, fmode_p);
6945 }
6946 else {
6947 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6948 }
6949 }
6950 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6951 extracted = 1;
6952 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6953 }
6954 return extracted;
6955}
6956
6957static void
6958validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6959{
6960 enum rb_io_mode fmode = *fmode_p;
6961
6962 if ((fmode & FMODE_READABLE) &&
6963 !enc2 &&
6964 !(fmode & FMODE_BINMODE) &&
6965 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6966 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6967
6968 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6969 rb_raise(rb_eArgError, "newline decorator with binary mode");
6970 }
6971 if (!(fmode & FMODE_BINMODE) &&
6972 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6973 fmode |= FMODE_TEXTMODE;
6974 *fmode_p = fmode;
6975 }
6976#if !DEFAULT_TEXTMODE
6977 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6978 fmode &= ~FMODE_TEXTMODE;
6979 *fmode_p = fmode;
6980 }
6981#endif
6982}
6983
6984static void
6985extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
6986{
6987 if (!NIL_P(opthash)) {
6988 VALUE v;
6989 v = rb_hash_aref(opthash, sym_textmode);
6990 if (!NIL_P(v)) {
6991 if (*fmode & FMODE_TEXTMODE)
6992 rb_raise(rb_eArgError, "textmode specified twice");
6993 if (*fmode & FMODE_BINMODE)
6994 rb_raise(rb_eArgError, "both textmode and binmode specified");
6995 if (RTEST(v))
6996 *fmode |= FMODE_TEXTMODE;
6997 }
6998 v = rb_hash_aref(opthash, sym_binmode);
6999 if (!NIL_P(v)) {
7000 if (*fmode & FMODE_BINMODE)
7001 rb_raise(rb_eArgError, "binmode specified twice");
7002 if (*fmode & FMODE_TEXTMODE)
7003 rb_raise(rb_eArgError, "both textmode and binmode specified");
7004 if (RTEST(v))
7005 *fmode |= FMODE_BINMODE;
7006 }
7007
7008 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
7009 rb_raise(rb_eArgError, "both textmode and binmode specified");
7010 }
7011}
7012
7013void
7014rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
7015 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
7016{
7017 VALUE vmode;
7018 int oflags;
7019 enum rb_io_mode fmode;
7020 rb_encoding *enc, *enc2;
7021 int ecflags;
7022 VALUE ecopts;
7023 int has_enc = 0, has_vmode = 0;
7024 VALUE intmode;
7025
7026 vmode = *vmode_p;
7027
7028 /* Set to defaults */
7029 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
7030
7031 vmode_handle:
7032 if (NIL_P(vmode)) {
7033 fmode = FMODE_READABLE;
7034 oflags = O_RDONLY;
7035 }
7036 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
7037 vmode = intmode;
7038 oflags = NUM2INT(intmode);
7039 fmode = rb_io_oflags_fmode(oflags);
7040 }
7041 else {
7042 const char *p;
7043
7044 StringValue(vmode);
7045 p = StringValueCStr(vmode);
7046 fmode = rb_io_modestr_fmode(p);
7047 oflags = rb_io_fmode_oflags(fmode);
7048 p = strchr(p, ':');
7049 if (p) {
7050 has_enc = 1;
7051 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
7052 }
7053 else {
7054 rb_encoding *e;
7055
7056 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7057 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
7058 }
7059 }
7060
7061 if (NIL_P(opthash)) {
7062 ecflags = (fmode & FMODE_READABLE) ?
7065#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7066 ecflags |= (fmode & FMODE_WRITABLE) ?
7067 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7068 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7069#endif
7070 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7071 ecopts = Qnil;
7072 if (fmode & FMODE_BINMODE) {
7073#ifdef O_BINARY
7074 oflags |= O_BINARY;
7075#endif
7076 if (!has_enc)
7077 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7078 }
7079#if DEFAULT_TEXTMODE
7080 else if (NIL_P(vmode)) {
7081 fmode |= DEFAULT_TEXTMODE;
7082 }
7083#endif
7084 }
7085 else {
7086 VALUE v;
7087 if (!has_vmode) {
7088 v = rb_hash_aref(opthash, sym_mode);
7089 if (!NIL_P(v)) {
7090 if (!NIL_P(vmode)) {
7091 rb_raise(rb_eArgError, "mode specified twice");
7092 }
7093 has_vmode = 1;
7094 vmode = v;
7095 goto vmode_handle;
7096 }
7097 }
7098 v = rb_hash_aref(opthash, sym_flags);
7099 if (!NIL_P(v)) {
7100 v = rb_to_int(v);
7101 oflags |= NUM2INT(v);
7102 vmode = INT2NUM(oflags);
7103 fmode = rb_io_oflags_fmode(oflags);
7104 }
7105 extract_binmode(opthash, &fmode);
7106 if (fmode & FMODE_BINMODE) {
7107#ifdef O_BINARY
7108 oflags |= O_BINARY;
7109#endif
7110 if (!has_enc)
7111 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7112 }
7113#if DEFAULT_TEXTMODE
7114 else if (NIL_P(vmode)) {
7115 fmode |= DEFAULT_TEXTMODE;
7116 }
7117#endif
7118 v = rb_hash_aref(opthash, sym_perm);
7119 if (!NIL_P(v)) {
7120 if (vperm_p) {
7121 if (!NIL_P(*vperm_p)) {
7122 rb_raise(rb_eArgError, "perm specified twice");
7123 }
7124 *vperm_p = v;
7125 }
7126 else {
7127 /* perm no use, just ignore */
7128 }
7129 }
7130 ecflags = (fmode & FMODE_READABLE) ?
7133#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7134 ecflags |= (fmode & FMODE_WRITABLE) ?
7135 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7136 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7137#endif
7138
7139 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7140 if (has_enc) {
7141 rb_raise(rb_eArgError, "encoding specified twice");
7142 }
7143 }
7144 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7145 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7146 }
7147
7148 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7149
7150 *vmode_p = vmode;
7151
7152 *oflags_p = oflags;
7153 *fmode_p = fmode;
7154 convconfig_p->enc = enc;
7155 convconfig_p->enc2 = enc2;
7156 convconfig_p->ecflags = ecflags;
7157 convconfig_p->ecopts = ecopts;
7158}
7159
7161 VALUE fname;
7162 int oflags;
7163 mode_t perm;
7164};
7165
7166static void *
7167sysopen_func(void *ptr)
7168{
7169 const struct sysopen_struct *data = ptr;
7170 const char *fname = RSTRING_PTR(data->fname);
7171 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7172}
7173
7174static inline int
7175rb_sysopen_internal(struct sysopen_struct *data)
7176{
7177 int fd;
7178 do {
7179 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7180 } while (fd < 0 && errno == EINTR);
7181 if (0 <= fd)
7182 rb_update_max_fd(fd);
7183 return fd;
7184}
7185
7186static int
7187rb_sysopen(VALUE fname, int oflags, mode_t perm)
7188{
7189 int fd = -1;
7190 struct sysopen_struct data;
7191
7192 data.fname = rb_str_encode_ospath(fname);
7193 StringValueCStr(data.fname);
7194 data.oflags = oflags;
7195 data.perm = perm;
7196
7197 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7198 rb_syserr_fail_path(first_errno, fname);
7199 }
7200 return fd;
7201}
7202
7203static inline FILE *
7204fdopen_internal(int fd, const char *modestr)
7205{
7206 FILE *file;
7207
7208#if defined(__sun)
7209 errno = 0;
7210#endif
7211 file = fdopen(fd, modestr);
7212 if (!file) {
7213#ifdef _WIN32
7214 if (errno == 0) errno = EINVAL;
7215#elif defined(__sun)
7216 if (errno == 0) errno = EMFILE;
7217#endif
7218 }
7219 return file;
7220}
7221
7222FILE *
7223rb_fdopen(int fd, const char *modestr)
7224{
7225 FILE *file = 0;
7226
7227 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7228 rb_syserr_fail(first_errno, 0);
7229 }
7230
7231 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7232#ifdef USE_SETVBUF
7233 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7234 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7235#endif
7236 return file;
7237}
7238
7239static int
7240io_check_tty(rb_io_t *fptr)
7241{
7242 int t = isatty(fptr->fd);
7243 if (t)
7244 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7245 return t;
7246}
7247
7248static VALUE rb_io_internal_encoding(VALUE);
7249static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7250
7251static int
7252io_strip_bom(VALUE io)
7253{
7254 VALUE b1, b2, b3, b4;
7255 rb_io_t *fptr;
7256
7257 GetOpenFile(io, fptr);
7258 if (!(fptr->mode & FMODE_READABLE)) return 0;
7259 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7260 switch (b1) {
7261 case INT2FIX(0xEF):
7262 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7263 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7264 if (b3 == INT2FIX(0xBF)) {
7265 return rb_utf8_encindex();
7266 }
7267 rb_io_ungetbyte(io, b3);
7268 }
7269 rb_io_ungetbyte(io, b2);
7270 break;
7271
7272 case INT2FIX(0xFE):
7273 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7274 if (b2 == INT2FIX(0xFF)) {
7275 return ENCINDEX_UTF_16BE;
7276 }
7277 rb_io_ungetbyte(io, b2);
7278 break;
7279
7280 case INT2FIX(0xFF):
7281 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7282 if (b2 == INT2FIX(0xFE)) {
7283 b3 = rb_io_getbyte(io);
7284 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7285 if (b4 == INT2FIX(0)) {
7286 return ENCINDEX_UTF_32LE;
7287 }
7288 rb_io_ungetbyte(io, b4);
7289 }
7290 rb_io_ungetbyte(io, b3);
7291 return ENCINDEX_UTF_16LE;
7292 }
7293 rb_io_ungetbyte(io, b2);
7294 break;
7295
7296 case INT2FIX(0):
7297 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7298 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7299 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7300 if (b4 == INT2FIX(0xFF)) {
7301 return ENCINDEX_UTF_32BE;
7302 }
7303 rb_io_ungetbyte(io, b4);
7304 }
7305 rb_io_ungetbyte(io, b3);
7306 }
7307 rb_io_ungetbyte(io, b2);
7308 break;
7309 }
7310 rb_io_ungetbyte(io, b1);
7311 return 0;
7312}
7313
7314static rb_encoding *
7315io_set_encoding_by_bom(VALUE io)
7316{
7317 int idx = io_strip_bom(io);
7318 rb_io_t *fptr;
7319 rb_encoding *extenc = NULL;
7320
7321 GetOpenFile(io, fptr);
7322 if (idx) {
7323 extenc = rb_enc_from_index(idx);
7324 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7325 rb_io_internal_encoding(io), Qnil);
7326 }
7327 else {
7328 fptr->encs.enc2 = NULL;
7329 }
7330 return extenc;
7331}
7332
7333static VALUE
7334rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7335 const struct rb_io_encoding *convconfig, mode_t perm)
7336{
7337 VALUE pathv;
7338 rb_io_t *fptr;
7339 struct rb_io_encoding cc;
7340 if (!convconfig) {
7341 /* Set to default encodings */
7342 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7343 cc.ecflags = 0;
7344 cc.ecopts = Qnil;
7345 convconfig = &cc;
7346 }
7347 validate_enc_binmode(&fmode, convconfig->ecflags,
7348 convconfig->enc, convconfig->enc2);
7349
7350 MakeOpenFile(io, fptr);
7351 fptr->mode = fmode;
7352 fptr->encs = *convconfig;
7353 pathv = rb_str_new_frozen(filename);
7354#ifdef O_TMPFILE
7355 if (!(oflags & O_TMPFILE)) {
7356 fptr->pathv = pathv;
7357 }
7358#else
7359 fptr->pathv = pathv;
7360#endif
7361 fptr->fd = rb_sysopen(pathv, oflags, perm);
7362 io_check_tty(fptr);
7363 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7364
7365 return io;
7366}
7367
7368static VALUE
7369rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7370{
7371 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7372 const char *p = strchr(modestr, ':');
7373 struct rb_io_encoding convconfig;
7374
7375 if (p) {
7376 parse_mode_enc(p+1, rb_usascii_encoding(),
7377 &convconfig.enc, &convconfig.enc2, &fmode);
7378 }
7379 else {
7380 rb_encoding *e;
7381 /* Set to default encodings */
7382
7383 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7384 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7385 }
7386
7387 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7390#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7391 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7392 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7393 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7394#endif
7395 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7396 convconfig.ecopts = Qnil;
7397
7398 return rb_file_open_generic(io, filename,
7399 rb_io_fmode_oflags(fmode),
7400 fmode,
7401 &convconfig,
7402 0666);
7403}
7404
7405VALUE
7406rb_file_open_str(VALUE fname, const char *modestr)
7407{
7408 FilePathValue(fname);
7409 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7410}
7411
7412VALUE
7413rb_file_open(const char *fname, const char *modestr)
7414{
7415 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7416}
7417
7418#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7419static struct pipe_list {
7420 rb_io_t *fptr;
7421 struct pipe_list *next;
7422} *pipe_list;
7423
7424static void
7425pipe_add_fptr(rb_io_t *fptr)
7426{
7427 struct pipe_list *list;
7428
7429 list = ALLOC(struct pipe_list);
7430 list->fptr = fptr;
7431 list->next = pipe_list;
7432 pipe_list = list;
7433}
7434
7435static void
7436pipe_del_fptr(rb_io_t *fptr)
7437{
7438 struct pipe_list **prev = &pipe_list;
7439 struct pipe_list *tmp;
7440
7441 while ((tmp = *prev) != 0) {
7442 if (tmp->fptr == fptr) {
7443 *prev = tmp->next;
7444 free(tmp);
7445 return;
7446 }
7447 prev = &tmp->next;
7448 }
7449}
7450
7451#if defined (_WIN32) || defined(__CYGWIN__)
7452static void
7453pipe_atexit(void)
7454{
7455 struct pipe_list *list = pipe_list;
7456 struct pipe_list *tmp;
7457
7458 while (list) {
7459 tmp = list->next;
7460 rb_io_fptr_finalize(list->fptr);
7461 list = tmp;
7462 }
7463}
7464#endif
7465
7466static void
7467pipe_finalize(rb_io_t *fptr, int noraise)
7468{
7469#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7470 int status = 0;
7471 if (fptr->stdio_file) {
7472 status = pclose(fptr->stdio_file);
7473 }
7474 fptr->fd = -1;
7475 fptr->stdio_file = 0;
7476 rb_last_status_set(status, fptr->pid);
7477#else
7478 fptr_finalize(fptr, noraise);
7479#endif
7480 pipe_del_fptr(fptr);
7481}
7482#endif
7483
7484static void
7485fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7486{
7487#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7488 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7489
7490 if (old_finalize == orig->finalize) return;
7491#endif
7492
7493 fptr->finalize = orig->finalize;
7494
7495#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7496 if (old_finalize != pipe_finalize) {
7497 struct pipe_list *list;
7498 for (list = pipe_list; list; list = list->next) {
7499 if (list->fptr == fptr) break;
7500 }
7501 if (!list) pipe_add_fptr(fptr);
7502 }
7503 else {
7504 pipe_del_fptr(fptr);
7505 }
7506#endif
7507}
7508
7509void
7511{
7513 fptr->mode |= FMODE_SYNC;
7514}
7515
7516
7517int
7518rb_pipe(int *pipes)
7519{
7520 int ret;
7521 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7522 if (ret == 0) {
7523 rb_update_max_fd(pipes[0]);
7524 rb_update_max_fd(pipes[1]);
7525 }
7526 return ret;
7527}
7528
7529#ifdef _WIN32
7530#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7531#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7532#endif
7533
7534#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7535struct popen_arg {
7536 VALUE execarg_obj;
7537 struct rb_execarg *eargp;
7538 int modef;
7539 int pair[2];
7540 int write_pair[2];
7541};
7542#endif
7543
7544#ifdef HAVE_WORKING_FORK
7545# ifndef __EMSCRIPTEN__
7546static void
7547popen_redirect(struct popen_arg *p)
7548{
7549 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7550 close(p->write_pair[1]);
7551 if (p->write_pair[0] != 0) {
7552 dup2(p->write_pair[0], 0);
7553 close(p->write_pair[0]);
7554 }
7555 close(p->pair[0]);
7556 if (p->pair[1] != 1) {
7557 dup2(p->pair[1], 1);
7558 close(p->pair[1]);
7559 }
7560 }
7561 else if (p->modef & FMODE_READABLE) {
7562 close(p->pair[0]);
7563 if (p->pair[1] != 1) {
7564 dup2(p->pair[1], 1);
7565 close(p->pair[1]);
7566 }
7567 }
7568 else {
7569 close(p->pair[1]);
7570 if (p->pair[0] != 0) {
7571 dup2(p->pair[0], 0);
7572 close(p->pair[0]);
7573 }
7574 }
7575}
7576# endif
7577
7578#if defined(__linux__)
7579/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7580 * Since /proc may not be available, linux_get_maxfd is just a hint.
7581 * This function, linux_get_maxfd, must be async-signal-safe.
7582 * I.e. opendir() is not usable.
7583 *
7584 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7585 * However they are easy to re-implement in async-signal-safe manner.
7586 * (Also note that there is missing/memcmp.c.)
7587 */
7588static int
7589linux_get_maxfd(void)
7590{
7591 int fd;
7592 char buf[4096], *p, *np, *e;
7593 ssize_t ss;
7594 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7595 if (fd < 0) return fd;
7596 ss = read(fd, buf, sizeof(buf));
7597 if (ss < 0) goto err;
7598 p = buf;
7599 e = buf + ss;
7600 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7601 (np = memchr(p, '\n', e-p)) != NULL) {
7602 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7603 int fdsize;
7604 p += sizeof("FDSize:")-1;
7605 *np = '\0';
7606 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7607 close(fd);
7608 return fdsize;
7609 }
7610 p = np+1;
7611 }
7612 /* fall through */
7613
7614 err:
7615 close(fd);
7616 return (int)ss;
7617}
7618#endif
7619
7620/* This function should be async-signal-safe. */
7621void
7622rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7623{
7624#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7625 int fd, ret;
7626 int max = (int)max_file_descriptor;
7627# ifdef F_MAXFD
7628 /* F_MAXFD is available since NetBSD 2.0. */
7629 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7630 if (ret != -1)
7631 maxhint = max = ret;
7632# elif defined(__linux__)
7633 ret = linux_get_maxfd();
7634 if (maxhint < ret)
7635 maxhint = ret;
7636 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7637# endif
7638 if (max < maxhint)
7639 max = maxhint;
7640 for (fd = lowfd; fd <= max; fd++) {
7641 if (!NIL_P(noclose_fds) &&
7642 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7643 continue;
7644 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7645 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7646 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7647 }
7648# define CONTIGUOUS_CLOSED_FDS 20
7649 if (ret != -1) {
7650 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7651 max = fd + CONTIGUOUS_CLOSED_FDS;
7652 }
7653 }
7654#endif
7655}
7656
7657# ifndef __EMSCRIPTEN__
7658static int
7659popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7660{
7661 struct popen_arg *p = (struct popen_arg*)pp;
7662
7663 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7664}
7665# endif
7666#endif
7667
7668#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7669static VALUE
7670rb_execarg_fixup_v(VALUE execarg_obj)
7671{
7672 rb_execarg_parent_start(execarg_obj);
7673 return Qnil;
7674}
7675#else
7676char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7677#endif
7678
7679#ifndef __EMSCRIPTEN__
7680static VALUE
7681pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7682 const struct rb_io_encoding *convconfig)
7683{
7684 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7685 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7686 rb_pid_t pid = 0;
7687 rb_io_t *fptr;
7688 VALUE port;
7689 rb_io_t *write_fptr;
7690 VALUE write_port;
7691#if defined(HAVE_WORKING_FORK)
7692 int status;
7693 char errmsg[80] = { '\0' };
7694#endif
7695#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7696 int state;
7697 struct popen_arg arg;
7698#endif
7699 int e = 0;
7700#if defined(HAVE_SPAWNV)
7701# define DO_SPAWN(cmd, args) ((args) ? \
7702 spawnv(P_NOWAIT, (cmd), (args)) : \
7703 spawn(P_NOWAIT, (cmd)))
7704# if !defined(HAVE_WORKING_FORK)
7705 char **args = NULL;
7706# endif
7707#endif
7708#if !defined(HAVE_WORKING_FORK)
7709 struct rb_execarg sarg, *sargp = &sarg;
7710#endif
7711 FILE *fp = 0;
7712 int fd = -1;
7713 int write_fd = -1;
7714#if !defined(HAVE_WORKING_FORK)
7715 const char *cmd = 0;
7716
7717 if (prog)
7718 cmd = StringValueCStr(prog);
7719#endif
7720
7721#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7722 arg.execarg_obj = execarg_obj;
7723 arg.eargp = eargp;
7724 arg.modef = fmode;
7725 arg.pair[0] = arg.pair[1] = -1;
7726 arg.write_pair[0] = arg.write_pair[1] = -1;
7727# if !defined(HAVE_WORKING_FORK)
7728 if (eargp && !eargp->use_shell) {
7729 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7730 }
7731# endif
7732 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7734 if (rb_pipe(arg.write_pair) < 0)
7735 rb_sys_fail_str(prog);
7736 if (rb_pipe(arg.pair) < 0) {
7737 e = errno;
7738 close(arg.write_pair[0]);
7739 close(arg.write_pair[1]);
7740 rb_syserr_fail_str(e, prog);
7741 }
7742 if (eargp) {
7743 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7744 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7745 }
7746 break;
7747 case FMODE_READABLE:
7748 if (rb_pipe(arg.pair) < 0)
7749 rb_sys_fail_str(prog);
7750 if (eargp)
7751 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7752 break;
7753 case FMODE_WRITABLE:
7754 if (rb_pipe(arg.pair) < 0)
7755 rb_sys_fail_str(prog);
7756 if (eargp)
7757 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7758 break;
7759 default:
7760 rb_sys_fail_str(prog);
7761 }
7762 if (!NIL_P(execarg_obj)) {
7763 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7764 if (state) {
7765 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7766 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7767 if (0 <= arg.pair[0]) close(arg.pair[0]);
7768 if (0 <= arg.pair[1]) close(arg.pair[1]);
7769 rb_execarg_parent_end(execarg_obj);
7770 rb_jump_tag(state);
7771 }
7772
7773# if defined(HAVE_WORKING_FORK)
7774 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7775# else
7776 rb_execarg_run_options(eargp, sargp, NULL, 0);
7777 while ((pid = DO_SPAWN(cmd, args)) < 0) {
7778 /* exec failed */
7779 switch (e = errno) {
7780 case EAGAIN:
7781# if EWOULDBLOCK != EAGAIN
7782 case EWOULDBLOCK:
7783# endif
7784 rb_thread_sleep(1);
7785 continue;
7786 }
7787 break;
7788 }
7789 if (eargp)
7790 rb_execarg_run_options(sargp, NULL, NULL, 0);
7791# endif
7792 rb_execarg_parent_end(execarg_obj);
7793 }
7794 else {
7795# if defined(HAVE_WORKING_FORK)
7796 pid = rb_call_proc__fork();
7797 if (pid == 0) { /* child */
7798 popen_redirect(&arg);
7799 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7800 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7801 return Qnil;
7802 }
7803# else
7804 rb_notimplement();
7805# endif
7806 }
7807
7808 /* parent */
7809 if (pid < 0) {
7810# if defined(HAVE_WORKING_FORK)
7811 e = errno;
7812# endif
7813 close(arg.pair[0]);
7814 close(arg.pair[1]);
7816 close(arg.write_pair[0]);
7817 close(arg.write_pair[1]);
7818 }
7819# if defined(HAVE_WORKING_FORK)
7820 if (errmsg[0])
7821 rb_syserr_fail(e, errmsg);
7822# endif
7823 rb_syserr_fail_str(e, prog);
7824 }
7825 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7826 close(arg.pair[1]);
7827 fd = arg.pair[0];
7828 close(arg.write_pair[0]);
7829 write_fd = arg.write_pair[1];
7830 }
7831 else if (fmode & FMODE_READABLE) {
7832 close(arg.pair[1]);
7833 fd = arg.pair[0];
7834 }
7835 else {
7836 close(arg.pair[0]);
7837 fd = arg.pair[1];
7838 }
7839#else
7840 cmd = rb_execarg_commandline(eargp, &prog);
7841 if (!NIL_P(execarg_obj)) {
7842 rb_execarg_parent_start(execarg_obj);
7843 rb_execarg_run_options(eargp, sargp, NULL, 0);
7844 }
7845 fp = popen(cmd, modestr);
7846 e = errno;
7847 if (eargp) {
7848 rb_execarg_parent_end(execarg_obj);
7849 rb_execarg_run_options(sargp, NULL, NULL, 0);
7850 }
7851 if (!fp) rb_syserr_fail_path(e, prog);
7852 fd = fileno(fp);
7853#endif
7854
7855 port = io_alloc(rb_cIO);
7856 MakeOpenFile(port, fptr);
7857 fptr->fd = fd;
7858 fptr->stdio_file = fp;
7859 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7860 if (convconfig) {
7861 fptr->encs = *convconfig;
7862#if RUBY_CRLF_ENVIRONMENT
7865 }
7866#endif
7867 }
7868 else {
7869 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7871 }
7872#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7873 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7874 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7875 }
7876#endif
7877 }
7878 fptr->pid = pid;
7879
7880 if (0 <= write_fd) {
7881 write_port = io_alloc(rb_cIO);
7882 MakeOpenFile(write_port, write_fptr);
7883 write_fptr->fd = write_fd;
7884 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7885 fptr->mode &= ~FMODE_WRITABLE;
7886 fptr->tied_io_for_writing = write_port;
7887 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7888 }
7889
7890#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7891 fptr->finalize = pipe_finalize;
7892 pipe_add_fptr(fptr);
7893#endif
7894 return port;
7895}
7896#else
7897static VALUE
7898pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7899 const struct rb_io_encoding *convconfig)
7900{
7901 rb_raise(rb_eNotImpError, "popen() is not available");
7902}
7903#endif
7904
7905static int
7906is_popen_fork(VALUE prog)
7907{
7908 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7909#if !defined(HAVE_WORKING_FORK)
7910 rb_raise(rb_eNotImpError,
7911 "fork() function is unimplemented on this machine");
7912#else
7913 return TRUE;
7914#endif
7915 }
7916 return FALSE;
7917}
7918
7919static VALUE
7920pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
7921 const struct rb_io_encoding *convconfig)
7922{
7923 int argc = 1;
7924 VALUE *argv = &prog;
7925 VALUE execarg_obj = Qnil;
7926
7927 if (!is_popen_fork(prog))
7928 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7929 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7930}
7931
7932static VALUE
7933pipe_close(VALUE io)
7934{
7935 rb_io_t *fptr = io_close_fptr(io);
7936 if (fptr) {
7937 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7938 }
7939 return Qnil;
7940}
7941
7942static VALUE popen_finish(VALUE port, VALUE klass);
7943
7944/*
7945 * call-seq:
7946 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7947 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7948 *
7949 * Executes the given command +cmd+ as a subprocess
7950 * whose $stdin and $stdout are connected to a new stream +io+.
7951 *
7952 * This method has potential security vulnerabilities if called with untrusted input;
7953 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
7954 *
7955 * If no block is given, returns the new stream,
7956 * which depending on given +mode+ may be open for reading, writing, or both.
7957 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7958 *
7959 * If a block is given, the stream is passed to the block
7960 * (again, open for reading, writing, or both);
7961 * when the block exits, the stream is closed,
7962 * the block's value is returned,
7963 * and the global variable <tt>$?</tt> is set to the child's exit status.
7964 *
7965 * Optional argument +mode+ may be any valid \IO mode.
7966 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7967 *
7968 * Required argument +cmd+ determines which of the following occurs:
7969 *
7970 * - The process forks.
7971 * - A specified program runs in a shell.
7972 * - A specified program runs with specified arguments.
7973 * - A specified program runs with specified arguments and a specified +argv0+.
7974 *
7975 * Each of these is detailed below.
7976 *
7977 * The optional hash argument +env+ specifies name/value pairs that are to be added
7978 * to the environment variables for the subprocess:
7979 *
7980 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7981 * pipe.puts 'puts ENV["FOO"]'
7982 * pipe.close_write
7983 * pipe.gets
7984 * end => "bar\n"
7985 *
7986 * Optional keyword arguments +opts+ specify:
7987 *
7988 * - {Open options}[rdoc-ref:IO@Open+Options].
7989 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7990 * - Options for Kernel#spawn.
7991 *
7992 * <b>Forked Process</b>
7993 *
7994 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7995 * IO.popen('-') do |pipe|
7996 * if pipe
7997 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7998 * else
7999 * $stderr.puts "In child, pid is #{$$}\n"
8000 * end
8001 * end
8002 *
8003 * Output:
8004 *
8005 * In parent, child pid is 26253
8006 * In child, pid is 26253
8007 *
8008 * Note that this is not supported on all platforms.
8009 *
8010 * <b>Shell Subprocess</b>
8011 *
8012 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
8013 * the program named +cmd+ is run as a shell command:
8014 *
8015 * IO.popen('uname') do |pipe|
8016 * pipe.readlines
8017 * end
8018 *
8019 * Output:
8020 *
8021 * ["Linux\n"]
8022 *
8023 * Another example:
8024 *
8025 * IO.popen('/bin/sh', 'r+') do |pipe|
8026 * pipe.puts('ls')
8027 * pipe.close_write
8028 * $stderr.puts pipe.readlines.size
8029 * end
8030 *
8031 * Output:
8032 *
8033 * 213
8034 *
8035 * <b>Program Subprocess</b>
8036 *
8037 * When argument +cmd+ is an array of strings,
8038 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
8039 *
8040 * IO.popen(['du', '..', '.']) do |pipe|
8041 * $stderr.puts pipe.readlines.size
8042 * end
8043 *
8044 * Output:
8045 *
8046 * 1111
8047 *
8048 * <b>Program Subprocess with <tt>argv0</tt></b>
8049 *
8050 * When argument +cmd+ is an array whose first element is a 2-element string array
8051 * and whose remaining elements (if any) are strings:
8052 *
8053 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
8054 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
8055 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
8056 *
8057 * Example (sets <tt>$0</tt> to 'foo'):
8058 *
8059 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
8060 *
8061 * <b>Some Special Examples</b>
8062 *
8063 * # Set IO encoding.
8064 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
8065 * euc_jp_string = nkf_io.read
8066 * }
8067 *
8068 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
8069 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
8070 * ls_result_with_error = io.read
8071 * end
8072 *
8073 * # Use mixture of spawn options and IO options.
8074 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
8075 * ls_result_with_error = io.read
8076 * end
8077 *
8078 * f = IO.popen("uname")
8079 * p f.readlines
8080 * f.close
8081 * puts "Parent is #{Process.pid}"
8082 * IO.popen("date") {|f| puts f.gets }
8083 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
8084 * p $?
8085 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
8086 * f.puts "bar"; f.close_write; puts f.gets
8087 * }
8088 *
8089 * Output (from last section):
8090 *
8091 * ["Linux\n"]
8092 * Parent is 21346
8093 * Thu Jan 15 22:41:19 JST 2009
8094 * 21346 is here, f is #<IO:fd 3>
8095 * 21352 is here, f is nil
8096 * #<Process::Status: pid 21352 exit 0>
8097 * <foo>bar;zot;
8098 *
8099 * Raises exceptions that IO.pipe and Kernel.spawn raise.
8100 *
8101 */
8102
8103static VALUE
8104rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
8105{
8106 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
8107
8108 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8109 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8110 switch (argc) {
8111 case 2:
8112 pmode = argv[1];
8113 case 1:
8114 pname = argv[0];
8115 break;
8116 default:
8117 {
8118 int ex = !NIL_P(opt);
8119 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8120 }
8121 }
8122 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8123}
8124
8125VALUE
8126rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8127{
8128 const char *modestr;
8129 VALUE tmp, execarg_obj = Qnil;
8130 int oflags;
8131 enum rb_io_mode fmode;
8132 struct rb_io_encoding convconfig;
8133
8134 tmp = rb_check_array_type(pname);
8135 if (!NIL_P(tmp)) {
8136 long len = RARRAY_LEN(tmp);
8137#if SIZEOF_LONG > SIZEOF_INT
8138 if (len > INT_MAX) {
8139 rb_raise(rb_eArgError, "too many arguments");
8140 }
8141#endif
8142 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8143 RB_GC_GUARD(tmp);
8144 }
8145 else {
8146 StringValue(pname);
8147 execarg_obj = Qnil;
8148 if (!is_popen_fork(pname))
8149 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8150 }
8151 if (!NIL_P(execarg_obj)) {
8152 if (!NIL_P(opt))
8153 opt = rb_execarg_extract_options(execarg_obj, opt);
8154 if (!NIL_P(env))
8155 rb_execarg_setenv(execarg_obj, env);
8156 }
8157 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8158 modestr = rb_io_oflags_modestr(oflags);
8159
8160 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8161}
8162
8163static VALUE
8164popen_finish(VALUE port, VALUE klass)
8165{
8166 if (NIL_P(port)) {
8167 /* child */
8168 if (rb_block_given_p()) {
8169 rb_protect(rb_yield, Qnil, NULL);
8170 rb_io_flush(rb_ractor_stdout());
8171 rb_io_flush(rb_ractor_stderr());
8172 _exit(EXIT_SUCCESS);
8173 }
8174 return Qnil;
8175 }
8176 RBASIC_SET_CLASS(port, klass);
8177 if (rb_block_given_p()) {
8178 return rb_ensure(rb_yield, port, pipe_close, port);
8179 }
8180 return port;
8181}
8182
8183#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8184struct popen_writer_arg {
8185 char *const *argv;
8186 struct popen_arg popen;
8187};
8188
8189static int
8190exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8191{
8192 struct popen_writer_arg *pw = arg;
8193 pw->popen.modef = FMODE_WRITABLE;
8194 popen_redirect(&pw->popen);
8195 execv(pw->argv[0], pw->argv);
8196 strlcpy(errmsg, strerror(errno), buflen);
8197 return -1;
8198}
8199#endif
8200
8201FILE *
8202ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8203{
8204#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8205# ifdef HAVE_WORKING_FORK
8206 struct popen_writer_arg pw;
8207 int *const write_pair = pw.popen.pair;
8208# else
8209 int write_pair[2];
8210# endif
8211
8212 *pid = -1;
8213 if (cloexec_pipe(write_pair, 0, false) == 0) {
8214# ifdef HAVE_WORKING_FORK
8215 pw.argv = argv;
8216 int status;
8217 char errmsg[80] = {'\0'};
8218 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8219# else
8220 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8221 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8222# endif
8223 close(write_pair[0]);
8224 if (*pid < 0) {
8225 close(write_pair[1]);
8226 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8227 }
8228 else {
8229 return fdopen(write_pair[1], "w");
8230 }
8231 }
8232#endif
8233 return NULL;
8234}
8235
8236static VALUE
8237rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8238{
8239 int oflags;
8240 enum rb_io_mode fmode;
8241 struct rb_io_encoding convconfig;
8242 mode_t perm;
8243
8244 FilePathValue(fname);
8245
8246 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8247 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8248
8249 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8250
8251 return io;
8252}
8253
8254/*
8255 * Document-method: File::open
8256 *
8257 * :markup: markdown
8258 *
8259 * call-seq:
8260 * File.open(path, mode = 'r', permissions = 0666, **options) -> file
8261 * File.open(path, mode = 'r', permissions = 0666, **options) {|file| ... } -> object
8262 *
8263 * Creates a new \File object via File.new with the given arguments.
8264 *
8265 * With no block given, returns the \File object.
8266 *
8267 * With a block given, calls the block with the \File object,
8268 * closes the \File object, and returns the block's value:
8269 *
8270 * ```ruby
8271 * File.open('doc/maintainers.md') {|file| file.size } # => 14900
8272 * ```
8273 *
8274 * Note that the \File object is automatically closed
8275 * even if the block raises an exception.
8276 */
8277
8278/*
8279 * Document-method: IO::open
8280 *
8281 * :markup: markdown
8282 *
8283 * call-seq:
8284 * IO.open(fd, mode = 'r', **options) -> io
8285 * IO.open(fd, mode = 'r', **options) {|io| ... } -> object
8286 *
8287 * Creates a new \IO object via IO.new with the given arguments.
8288 *
8289 * With no block given, returns the \IO object.
8290 *
8291 * With a block given, calls the block with the \IO object,
8292 * closes the \IO object, and returns the block’s value:
8293 *
8294 * ```ruby
8295 * fd = File.sysopen('doc/maintainers.md') # => 6
8296 * IO.open(fd) {|io| io.read.size } # => 14897
8297 * ```
8298 */
8299
8300static VALUE
8301rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8302{
8304
8305 if (rb_block_given_p()) {
8306 return rb_ensure(rb_yield, io, io_close, io);
8307 }
8308
8309 return io;
8310}
8311
8312/*
8313 * call-seq:
8314 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8315 *
8316 * Opens the file at the given path with the given mode and permissions;
8317 * returns the integer file descriptor.
8318 *
8319 * If the file is to be readable, it must exist;
8320 * if the file is to be writable and does not exist,
8321 * it is created with the given permissions:
8322 *
8323 * File.write('t.tmp', '') # => 0
8324 * IO.sysopen('t.tmp') # => 8
8325 * IO.sysopen('t.tmp', 'w') # => 9
8326 *
8327 *
8328 */
8329
8330static VALUE
8331rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8332{
8333 VALUE fname, vmode, vperm;
8334 VALUE intmode;
8335 int oflags, fd;
8336 mode_t perm;
8337
8338 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8339 FilePathValue(fname);
8340
8341 if (NIL_P(vmode))
8342 oflags = O_RDONLY;
8343 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8344 oflags = NUM2INT(intmode);
8345 else {
8346 StringValue(vmode);
8347 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8348 }
8349 if (NIL_P(vperm)) perm = 0666;
8350 else perm = NUM2MODET(vperm);
8351
8352 RB_GC_GUARD(fname) = rb_str_new4(fname);
8353 fd = rb_sysopen(fname, oflags, perm);
8354 return INT2NUM(fd);
8355}
8356
8357/*
8358 * call-seq:
8359 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8360 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8361 *
8362 * Creates an IO object connected to the given file.
8363 *
8364 * With no block given, file stream is returned:
8365 *
8366 * open('t.txt') # => #<File:t.txt>
8367 *
8368 * With a block given, calls the block with the open file stream,
8369 * then closes the stream:
8370 *
8371 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8372 *
8373 * Output:
8374 *
8375 * #<File:t.txt>
8376 *
8377 * See File.open for details.
8378 *
8379 */
8380
8381static VALUE
8382rb_f_open(int argc, VALUE *argv, VALUE _)
8383{
8384 ID to_open = 0;
8385 int redirect = FALSE;
8386
8387 if (argc >= 1) {
8388 CONST_ID(to_open, "to_open");
8389 if (rb_respond_to(argv[0], to_open)) {
8390 redirect = TRUE;
8391 }
8392 else {
8393 VALUE tmp = argv[0];
8394 FilePathValue(tmp);
8395 if (NIL_P(tmp)) {
8396 redirect = TRUE;
8397 }
8398 else {
8399 argv[0] = tmp;
8400 }
8401 }
8402 }
8403 if (redirect) {
8404 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8405
8406 if (rb_block_given_p()) {
8407 return rb_ensure(rb_yield, io, io_close, io);
8408 }
8409 return io;
8410 }
8411 return rb_io_s_open(argc, argv, rb_cFile);
8412}
8413
8414static VALUE
8415rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8416 const struct rb_io_encoding *convconfig, mode_t perm)
8417{
8418 return rb_file_open_generic(io_alloc(klass), filename,
8419 oflags, fmode, convconfig, perm);
8420}
8421
8422static VALUE
8423rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8424{
8425 int oflags;
8426 enum rb_io_mode fmode;
8427 struct rb_io_encoding convconfig;
8428 mode_t perm;
8429
8430 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8431 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8432 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8433}
8434
8435static VALUE
8436io_reopen(VALUE io, VALUE nfile)
8437{
8438 rb_io_t *fptr, *orig;
8439 int fd, fd2;
8440 rb_off_t pos = 0;
8441
8442 nfile = rb_io_get_io(nfile);
8443 GetOpenFile(io, fptr);
8444 GetOpenFile(nfile, orig);
8445
8446 if (fptr == orig) return io;
8447 if (RUBY_IO_EXTERNAL_P(fptr)) {
8448 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8449 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8450 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8451 rb_raise(rb_eArgError,
8452 "%s can't change access mode from \"%s\" to \"%s\"",
8453 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8454 rb_io_fmode_modestr(orig->mode));
8455 }
8456 }
8457 flush_before_seek(fptr, true);
8458 /* in flush_before_seek, clear_codeconv called only if rbuf is filled */
8459 clear_codeconv(fptr);
8460 if (orig->mode & FMODE_READABLE) {
8461 pos = io_tell(orig);
8462 }
8463 if (orig->mode & FMODE_WRITABLE) {
8464 if (io_fflush(orig) < 0)
8465 rb_sys_fail_on_write(fptr);
8466 }
8467
8468 /* copy rb_io_t structure */
8469 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8470 fptr->encs = orig->encs;
8471 fptr->pid = orig->pid;
8472 fptr->lineno = orig->lineno;
8473 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8474 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8475 fptr_copy_finalizer(fptr, orig);
8476
8477 fd = fptr->fd;
8478 fd2 = orig->fd;
8479 if (fd != fd2) {
8480 // Interrupt all usage of the old file descriptor:
8481 rb_thread_io_close_interrupt(fptr);
8482 rb_thread_io_close_wait(fptr);
8483
8484 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8485 /* need to keep FILE objects of stdin, stdout and stderr */
8486 if (rb_cloexec_dup2(fd2, fd) < 0)
8487 rb_sys_fail_path(orig->pathv);
8488 rb_update_max_fd(fd);
8489 }
8490 else {
8491 fclose(fptr->stdio_file);
8492 fptr->stdio_file = 0;
8493 fptr->fd = -1;
8494 if (rb_cloexec_dup2(fd2, fd) < 0)
8495 rb_sys_fail_path(orig->pathv);
8496 rb_update_max_fd(fd);
8497 fptr->fd = fd;
8498 }
8499
8500 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8501 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8502 rb_sys_fail_path(fptr->pathv);
8503 }
8504 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8505 rb_sys_fail_path(orig->pathv);
8506 }
8507 }
8508 }
8509
8510 if (fptr->mode & FMODE_BINMODE) {
8511 rb_io_binmode(io);
8512 }
8513
8514 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8515 return io;
8516}
8517
8518#ifdef _WIN32
8519int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8520#else
8521static int
8522rb_freopen(VALUE fname, const char *mode, FILE *fp)
8523{
8524 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8525 RB_GC_GUARD(fname);
8526 return errno;
8527 }
8528 return 0;
8529}
8530#endif
8531
8532/*
8533 * call-seq:
8534 * reopen(other_io) -> self
8535 * reopen(path, mode = 'r', **opts) -> self
8536 *
8537 * Reassociates the stream with another stream,
8538 * which may be of a different class.
8539 * This method may be used to redirect an existing stream
8540 * to a new destination.
8541 *
8542 * With argument +other_io+ given, reassociates with that stream:
8543 *
8544 * # Redirect $stdin from a file.
8545 * f = File.open('t.txt')
8546 * $stdin.reopen(f)
8547 * f.close
8548 *
8549 * # Redirect $stdout to a file.
8550 * f = File.open('t.tmp', 'w')
8551 * $stdout.reopen(f)
8552 * f.close
8553 *
8554 * With argument +path+ given, reassociates with a new stream to that file path:
8555 *
8556 * $stdin.reopen('t.txt')
8557 * $stdout.reopen('t.tmp', 'w')
8558 *
8559 * Optional keyword arguments +opts+ specify:
8560 *
8561 * - {Open Options}[rdoc-ref:IO@Open+Options].
8562 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8563 *
8564 */
8565
8566static VALUE
8567rb_io_reopen(int argc, VALUE *argv, VALUE file)
8568{
8569 VALUE fname, nmode, opt;
8570 int oflags;
8571 rb_io_t *fptr;
8572
8573 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8574 VALUE tmp = rb_io_check_io(fname);
8575 if (!NIL_P(tmp)) {
8576 return io_reopen(file, tmp);
8577 }
8578 }
8579
8580 FilePathValue(fname);
8581 rb_io_taint_check(file);
8582 fptr = RFILE(file)->fptr;
8583 if (!fptr) {
8584 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8585 }
8586
8587 if (!NIL_P(nmode) || !NIL_P(opt)) {
8588 enum rb_io_mode fmode;
8589 struct rb_io_encoding convconfig;
8590
8591 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8592 if (RUBY_IO_EXTERNAL_P(fptr) &&
8593 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8594 (fptr->mode & FMODE_READWRITE)) {
8595 rb_raise(rb_eArgError,
8596 "%s can't change access mode from \"%s\" to \"%s\"",
8597 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8598 rb_io_fmode_modestr(fmode));
8599 }
8600 fptr->mode = fmode;
8601 fptr->encs = convconfig;
8602 }
8603 else {
8604 oflags = rb_io_fmode_oflags(fptr->mode);
8605 }
8606
8607 fptr->pathv = fname;
8608 if (fptr->fd < 0) {
8609 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8610 fptr->stdio_file = 0;
8611 return file;
8612 }
8613
8614 if (fptr->mode & FMODE_WRITABLE) {
8615 if (io_fflush(fptr) < 0)
8616 rb_sys_fail_on_write(fptr);
8617 }
8618 fptr->rbuf.off = fptr->rbuf.len = 0;
8619 clear_codeconv(fptr);
8620
8621 if (fptr->stdio_file) {
8622 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8623 rb_io_oflags_modestr(oflags),
8624 fptr->stdio_file);
8625 if (e) rb_syserr_fail_path(e, fptr->pathv);
8626 fptr->fd = fileno(fptr->stdio_file);
8627 rb_fd_fix_cloexec(fptr->fd);
8628#ifdef USE_SETVBUF
8629 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8630 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8631#endif
8632 if (fptr->stdio_file == stderr) {
8633 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8634 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8635 }
8636 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8637 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8638 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8639 }
8640 }
8641 else {
8642 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8643 int err = 0;
8644 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8645 err = errno;
8646 (void)close(tmpfd);
8647 if (err) {
8648 rb_syserr_fail_path(err, fptr->pathv);
8649 }
8650 }
8651
8652 return file;
8653}
8654
8655/* :nodoc: */
8656static VALUE
8657rb_io_init_copy(VALUE dest, VALUE io)
8658{
8659 rb_io_t *fptr, *orig;
8660 int fd;
8661 VALUE write_io;
8662 rb_off_t pos;
8663
8664 io = rb_io_get_io(io);
8665 if (!OBJ_INIT_COPY(dest, io)) return dest;
8666 GetOpenFile(io, orig);
8667 MakeOpenFile(dest, fptr);
8668
8669 rb_io_flush(io);
8670
8671 /* copy rb_io_t structure */
8672 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8673 fptr->encs = orig->encs;
8674 fptr->pid = orig->pid;
8675 fptr->lineno = orig->lineno;
8676 fptr->timeout = orig->timeout;
8677
8678 ccan_list_head_init(&fptr->blocking_operations);
8679 fptr->closing_ec = NULL;
8680 fptr->wakeup_mutex = Qnil;
8681 fptr->fork_generation = GET_VM()->fork_gen;
8682
8683 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8684 fptr_copy_finalizer(fptr, orig);
8685
8686 fd = ruby_dup(orig->fd);
8687 fptr->fd = fd;
8688 pos = io_tell(orig);
8689 if (0 <= pos)
8690 io_seek(fptr, pos, SEEK_SET);
8691 if (fptr->mode & FMODE_BINMODE) {
8692 rb_io_binmode(dest);
8693 }
8694
8695 write_io = GetWriteIO(io);
8696 if (io != write_io) {
8697 write_io = rb_obj_dup(write_io);
8698 fptr->tied_io_for_writing = write_io;
8699 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8700 }
8701
8702 return dest;
8703}
8704
8705/*
8706 * call-seq:
8707 * printf(format_string, *objects) -> nil
8708 *
8709 * Formats and writes +objects+ to the stream.
8710 *
8711 * For details on +format_string+, see
8712 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8713 *
8714 */
8715
8716VALUE
8717rb_io_printf(int argc, const VALUE *argv, VALUE out)
8718{
8719 rb_io_write(out, rb_f_sprintf(argc, argv));
8720 return Qnil;
8721}
8722
8723/*
8724 * call-seq:
8725 * printf(format_string, *objects) -> nil
8726 * printf(io, format_string, *objects) -> nil
8727 *
8728 * Equivalent to:
8729 *
8730 * io.write(sprintf(format_string, *objects))
8731 *
8732 * For details on +format_string+, see
8733 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8734 *
8735 * With the single argument +format_string+, formats +objects+ into the string,
8736 * then writes the formatted string to $stdout:
8737 *
8738 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8739 *
8740 * Output (on $stdout):
8741 *
8742 * 0024 24 24.00#
8743 *
8744 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8745 * then writes the formatted string to +io+:
8746 *
8747 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8748 *
8749 * Output (on $stderr):
8750 *
8751 * 0024 24 24.00# => nil
8752 *
8753 * With no arguments, does nothing.
8754 *
8755 */
8756
8757static VALUE
8758rb_f_printf(int argc, VALUE *argv, VALUE _)
8759{
8760 VALUE out;
8761
8762 if (argc == 0) return Qnil;
8763 if (RB_TYPE_P(argv[0], T_STRING)) {
8764 out = rb_ractor_stdout();
8765 }
8766 else {
8767 out = argv[0];
8768 argv++;
8769 argc--;
8770 }
8771 rb_io_write(out, rb_f_sprintf(argc, argv));
8772
8773 return Qnil;
8774}
8775
8776extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
8777
8778static void
8779deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8780{
8781 rb_deprecated_str_setter(val, id, &val);
8782 if (!NIL_P(val)) {
8783 if (rb_str_equal(val, rb_default_rs)) {
8784 val = rb_default_rs;
8785 }
8786 else {
8787 val = rb_str_frozen_bare_string(val);
8788 }
8789 }
8790 *var = val;
8791}
8792
8793/*
8794 * call-seq:
8795 * print(*objects) -> nil
8796 *
8797 * Writes the given objects to the stream; returns +nil+.
8798 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8799 * (<tt>$\</tt>), if it is not +nil+.
8800 * See {Line IO}[rdoc-ref:IO@Line+IO].
8801 *
8802 * With argument +objects+ given, for each object:
8803 *
8804 * - Converts via its method +to_s+ if not a string.
8805 * - Writes to the stream.
8806 * - If not the last object, writes the output field separator
8807 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8808 *
8809 * With default separators:
8810 *
8811 * f = File.open('t.tmp', 'w+')
8812 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8813 * p $OUTPUT_RECORD_SEPARATOR
8814 * p $OUTPUT_FIELD_SEPARATOR
8815 * f.print(*objects)
8816 * f.rewind
8817 * p f.read
8818 * f.close
8819 *
8820 * Output:
8821 *
8822 * nil
8823 * nil
8824 * "00.00/10+0izerozero"
8825 *
8826 * With specified separators:
8827 *
8828 * $\ = "\n"
8829 * $, = ','
8830 * f.rewind
8831 * f.print(*objects)
8832 * f.rewind
8833 * p f.read
8834 *
8835 * Output:
8836 *
8837 * "0,0.0,0/1,0+0i,zero,zero\n"
8838 *
8839 * With no argument given, writes the content of <tt>$_</tt>
8840 * (which is usually the most recent user input):
8841 *
8842 * f = File.open('t.tmp', 'w+')
8843 * gets # Sets $_ to the most recent user input.
8844 * f.print
8845 * f.close
8846 *
8847 */
8848
8849VALUE
8850rb_io_print(int argc, const VALUE *argv, VALUE out)
8851{
8852 int i;
8853 VALUE line;
8854
8855 /* if no argument given, print `$_' */
8856 if (argc == 0) {
8857 argc = 1;
8858 line = rb_lastline_get();
8859 argv = &line;
8860 }
8861 if (argc > 1 && !NIL_P(rb_output_fs)) {
8862 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8863 }
8864 for (i=0; i<argc; i++) {
8865 if (!NIL_P(rb_output_fs) && i>0) {
8866 rb_io_write(out, rb_output_fs);
8867 }
8868 rb_io_write(out, argv[i]);
8869 }
8870 if (argc > 0 && !NIL_P(rb_output_rs)) {
8871 rb_io_write(out, rb_output_rs);
8872 }
8873
8874 return Qnil;
8875}
8876
8877/*
8878 * call-seq:
8879 * print(*objects) -> nil
8880 *
8881 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8882 * this method is the straightforward way to write to <tt>$stdout</tt>.
8883 *
8884 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8885 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8886 * (<tt>$\</tt>), if it is not +nil+.
8887 *
8888 * With argument +objects+ given, for each object:
8889 *
8890 * - Converts via its method +to_s+ if not a string.
8891 * - Writes to <tt>stdout</tt>.
8892 * - If not the last object, writes the output field separator
8893 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8894 *
8895 * With default separators:
8896 *
8897 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8898 * $OUTPUT_RECORD_SEPARATOR
8899 * $OUTPUT_FIELD_SEPARATOR
8900 * print(*objects)
8901 *
8902 * Output:
8903 *
8904 * nil
8905 * nil
8906 * 00.00/10+0izerozero
8907 *
8908 * With specified separators:
8909 *
8910 * $OUTPUT_RECORD_SEPARATOR = "\n"
8911 * $OUTPUT_FIELD_SEPARATOR = ','
8912 * print(*objects)
8913 *
8914 * Output:
8915 *
8916 * 0,0.0,0/1,0+0i,zero,zero
8917 *
8918 * With no argument given, writes the content of <tt>$_</tt>
8919 * (which is usually the most recent user input):
8920 *
8921 * gets # Sets $_ to the most recent user input.
8922 * print # Prints $_.
8923 *
8924 */
8925
8926static VALUE
8927rb_f_print(int argc, const VALUE *argv, VALUE _)
8928{
8929 rb_io_print(argc, argv, rb_ractor_stdout());
8930 return Qnil;
8931}
8932
8933/*
8934 * call-seq:
8935 * putc(object) -> object
8936 *
8937 * Writes a character to the stream.
8938 * See {Character IO}[rdoc-ref:IO@Character+IO].
8939 *
8940 * If +object+ is numeric, converts to integer if necessary,
8941 * then writes the character whose code is the
8942 * least significant byte;
8943 * if +object+ is a string, writes the first character:
8944 *
8945 * $stdout.putc "A"
8946 * $stdout.putc 65
8947 *
8948 * Output:
8949 *
8950 * AA
8951 *
8952 */
8953
8954static VALUE
8955rb_io_putc(VALUE io, VALUE ch)
8956{
8957 VALUE str;
8958 if (RB_TYPE_P(ch, T_STRING)) {
8959 str = rb_str_substr(ch, 0, 1);
8960 }
8961 else {
8962 char c = NUM2CHR(ch);
8963 str = rb_str_new(&c, 1);
8964 }
8965 rb_io_write(io, str);
8966 return ch;
8967}
8968
8969#define forward(obj, id, argc, argv) \
8970 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8971#define forward_public(obj, id, argc, argv) \
8972 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8973#define forward_current(id, argc, argv) \
8974 forward_public(ARGF.current_file, id, argc, argv)
8975
8976/*
8977 * call-seq:
8978 * putc(int) -> int
8979 *
8980 * Equivalent to:
8981 *
8982 * $stdout.putc(int)
8983 *
8984 * See IO#putc for important information regarding multi-byte characters.
8985 *
8986 */
8987
8988static VALUE
8989rb_f_putc(VALUE recv, VALUE ch)
8990{
8991 VALUE r_stdout = rb_ractor_stdout();
8992 if (recv == r_stdout) {
8993 return rb_io_putc(recv, ch);
8994 }
8995 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8996}
8997
8998
8999int
9000rb_str_end_with_asciichar(VALUE str, int c)
9001{
9002 long len = RSTRING_LEN(str);
9003 const char *ptr = RSTRING_PTR(str);
9004 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
9005 int n;
9006
9007 if (len == 0) return 0;
9008 if ((n = rb_enc_mbminlen(enc)) == 1) {
9009 return ptr[len - 1] == c;
9010 }
9011 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
9012}
9013
9014static VALUE
9015io_puts_ary(VALUE ary, VALUE out, int recur)
9016{
9017 VALUE tmp;
9018 long i;
9019
9020 if (recur) {
9021 tmp = rb_str_new2("[...]");
9022 rb_io_puts(1, &tmp, out);
9023 return Qtrue;
9024 }
9025 ary = rb_check_array_type(ary);
9026 if (NIL_P(ary)) return Qfalse;
9027 for (i=0; i<RARRAY_LEN(ary); i++) {
9028 tmp = RARRAY_AREF(ary, i);
9029 rb_io_puts(1, &tmp, out);
9030 }
9031 return Qtrue;
9032}
9033
9034/*
9035 * call-seq:
9036 * puts(*objects) -> nil
9037 *
9038 * Writes the given +objects+ to the stream, which must be open for writing;
9039 * returns +nil+.\
9040 * Writes a newline after each that does not already end with a newline sequence.
9041 * If called without arguments, writes a newline.
9042 * See {Line IO}[rdoc-ref:IO@Line+IO].
9043 *
9044 * Note that each added newline is the character <tt>"\n"</tt>,
9045 * not the output record separator (<tt>$\</tt>).
9046 *
9047 * Treatment for each object:
9048 *
9049 * - String: writes the string.
9050 * - Neither string nor array: writes <tt>object.to_s</tt>.
9051 * - Array: writes each element of the array; arrays may be nested.
9052 *
9053 * To keep these examples brief, we define this helper method:
9054 *
9055 * def show(*objects)
9056 * # Puts objects to file.
9057 * f = File.new('t.tmp', 'w+')
9058 * f.puts(objects)
9059 * # Return file content.
9060 * f.rewind
9061 * p f.read
9062 * f.close
9063 * end
9064 *
9065 * # Strings without newlines.
9066 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
9067 * # Strings, some with newlines.
9068 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
9069 *
9070 * # Neither strings nor arrays:
9071 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
9072 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
9073 *
9074 * # Array of strings.
9075 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
9076 * # Nested arrays.
9077 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
9078 *
9079 */
9080
9081VALUE
9082rb_io_puts(int argc, const VALUE *argv, VALUE out)
9083{
9084 VALUE line, args[2];
9085
9086 /* if no argument given, print newline. */
9087 if (argc == 0) {
9088 rb_io_write(out, rb_default_rs);
9089 return Qnil;
9090 }
9091 for (int i = 0; i < argc; i++) {
9092 // Convert the argument to a string:
9093 if (RB_TYPE_P(argv[i], T_STRING)) {
9094 line = argv[i];
9095 }
9096 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9097 continue;
9098 }
9099 else {
9100 line = rb_obj_as_string(argv[i]);
9101 }
9102
9103 // Write the line:
9104 int n = 0;
9105 if (RSTRING_LEN(line) == 0) {
9106 args[n++] = rb_default_rs;
9107 }
9108 else {
9109 args[n++] = line;
9110 if (!rb_str_end_with_asciichar(line, '\n')) {
9111 args[n++] = rb_default_rs;
9112 }
9113 }
9114
9115 rb_io_writev(out, n, args);
9116 }
9117
9118 return Qnil;
9119}
9120
9121/*
9122 * call-seq:
9123 * puts(*objects) -> nil
9124 *
9125 * Equivalent to
9126 *
9127 * $stdout.puts(objects)
9128 */
9129
9130static VALUE
9131rb_f_puts(int argc, VALUE *argv, VALUE recv)
9132{
9133 VALUE r_stdout = rb_ractor_stdout();
9134 if (recv == r_stdout) {
9135 return rb_io_puts(argc, argv, recv);
9136 }
9137 return forward(r_stdout, rb_intern("puts"), argc, argv);
9138}
9139
9140static VALUE
9141rb_p_write(VALUE str)
9142{
9143 VALUE args[2];
9144 args[0] = str;
9145 args[1] = rb_default_rs;
9146 VALUE r_stdout = rb_ractor_stdout();
9147 if (RB_TYPE_P(r_stdout, T_FILE) &&
9148 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9149 io_writev(2, args, r_stdout);
9150 }
9151 else {
9152 rb_io_writev(r_stdout, 2, args);
9153 }
9154 return Qnil;
9155}
9156
9157void
9158rb_p(VALUE obj) /* for debug print within C code */
9159{
9160 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9161}
9162
9163static VALUE
9164rb_p_result(int argc, const VALUE *argv)
9165{
9166 VALUE ret = Qnil;
9167
9168 if (argc == 1) {
9169 ret = argv[0];
9170 }
9171 else if (argc > 1) {
9172 ret = rb_ary_new4(argc, argv);
9173 }
9174 VALUE r_stdout = rb_ractor_stdout();
9175 if (RB_TYPE_P(r_stdout, T_FILE)) {
9176 rb_uninterruptible(rb_io_flush, r_stdout);
9177 }
9178 return ret;
9179}
9180
9181/*
9182 * call-seq:
9183 * p(object) -> obj
9184 * p(*objects) -> array of objects
9185 * p -> nil
9186 *
9187 * For each object +obj+, executes:
9188 *
9189 * $stdout.write(obj.inspect, "\n")
9190 *
9191 * With one object given, returns the object;
9192 * with multiple objects given, returns an array containing the objects;
9193 * with no object given, returns +nil+.
9194 *
9195 * Examples:
9196 *
9197 * r = Range.new(0, 4)
9198 * p r # => 0..4
9199 * p [r, r, r] # => [0..4, 0..4, 0..4]
9200 * p # => nil
9201 *
9202 * Output:
9203 *
9204 * 0..4
9205 * [0..4, 0..4, 0..4]
9206 *
9207 * Kernel#p is designed for debugging purposes.
9208 * Ruby implementations may define Kernel#p to be uninterruptible
9209 * in whole or in part.
9210 * On CRuby, Kernel#p's writing of data is uninterruptible.
9211 */
9212
9213static VALUE
9214rb_f_p(int argc, VALUE *argv, VALUE self)
9215{
9216 int i;
9217 for (i=0; i<argc; i++) {
9218 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9219 rb_uninterruptible(rb_p_write, inspected);
9220 }
9221 return rb_p_result(argc, argv);
9222}
9223
9224/*
9225 * call-seq:
9226 * display(port = $>) -> nil
9227 *
9228 * Writes +self+ on the given port:
9229 *
9230 * 1.display
9231 * "cat".display
9232 * [ 4, 5, 6 ].display
9233 * puts
9234 *
9235 * Output:
9236 *
9237 * 1cat[4, 5, 6]
9238 *
9239 */
9240
9241static VALUE
9242rb_obj_display(int argc, VALUE *argv, VALUE self)
9243{
9244 VALUE out;
9245
9246 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9247 rb_io_write(out, self);
9248
9249 return Qnil;
9250}
9251
9252static int
9253rb_stderr_to_original_p(VALUE err)
9254{
9255 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9256}
9257
9258void
9259rb_write_error2(const char *mesg, long len)
9260{
9261 VALUE out = rb_ractor_stderr();
9262 if (rb_stderr_to_original_p(out)) {
9263#ifdef _WIN32
9264 if (isatty(fileno(stderr))) {
9265 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9266 }
9267#endif
9268 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9269 /* failed to write to stderr, what can we do? */
9270 return;
9271 }
9272 }
9273 else {
9274 rb_io_write(out, rb_str_new(mesg, len));
9275 }
9276}
9277
9278void
9279rb_write_error(const char *mesg)
9280{
9281 rb_write_error2(mesg, strlen(mesg));
9282}
9283
9284void
9285rb_write_error_str(VALUE mesg)
9286{
9287 VALUE out = rb_ractor_stderr();
9288 /* a stopgap measure for the time being */
9289 if (rb_stderr_to_original_p(out)) {
9290 size_t len = (size_t)RSTRING_LEN(mesg);
9291#ifdef _WIN32
9292 if (isatty(fileno(stderr))) {
9293 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9294 }
9295#endif
9296 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9297 RB_GC_GUARD(mesg);
9298 return;
9299 }
9300 }
9301 else {
9302 /* may unlock GVL, and */
9303 rb_io_write(out, mesg);
9304 }
9305}
9306
9307int
9308rb_stderr_tty_p(void)
9309{
9310 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9311 return isatty(fileno(stderr));
9312 return 0;
9313}
9314
9315static void
9316must_respond_to(ID mid, VALUE val, ID id)
9317{
9318 if (!rb_respond_to(val, mid)) {
9319 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9320 rb_id2str(id), rb_id2str(mid),
9321 rb_obj_class(val));
9322 }
9323}
9324
9325static void
9326stdin_setter(VALUE val, ID id, VALUE *ptr)
9327{
9329}
9330
9331static VALUE
9332stdin_getter(ID id, VALUE *ptr)
9333{
9334 return rb_ractor_stdin();
9335}
9336
9337static void
9338stdout_setter(VALUE val, ID id, VALUE *ptr)
9339{
9340 must_respond_to(id_write, val, id);
9342}
9343
9344static VALUE
9345stdout_getter(ID id, VALUE *ptr)
9346{
9347 return rb_ractor_stdout();
9348}
9349
9350static void
9351stderr_setter(VALUE val, ID id, VALUE *ptr)
9352{
9353 must_respond_to(id_write, val, id);
9355}
9356
9357static VALUE
9358stderr_getter(ID id, VALUE *ptr)
9359{
9360 return rb_ractor_stderr();
9361}
9362
9363static VALUE
9364allocate_and_open_new_file(VALUE klass)
9365{
9366 VALUE self = io_alloc(klass);
9367 rb_io_make_open_file(self);
9368 return self;
9369}
9370
9371VALUE
9372rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9373{
9374 int state;
9375 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9376 if (state) {
9377 /* if we raised an exception allocating an IO object, but the caller
9378 intended to transfer ownership of this FD to us, close the fd before
9379 raising the exception. Otherwise, we would leak a FD - the caller
9380 expects GC to close the file, but we never got around to assigning
9381 it to a rb_io. */
9382 if (!(mode & FMODE_EXTERNAL)) {
9383 maygvl_close(descriptor, 0);
9384 }
9385 rb_jump_tag(state);
9386 }
9387
9388
9389 rb_io_t *io = RFILE(self)->fptr;
9390 io->self = self;
9391 io->fd = descriptor;
9392 io->mode = mode;
9393
9394 /* At this point, Ruby fully owns the descriptor, and will close it when
9395 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9396 in the rest of this method. */
9397
9398 if (NIL_P(path)) {
9399 io->pathv = Qnil;
9400 }
9401 else {
9402 StringValue(path);
9403 io->pathv = rb_str_new_frozen(path);
9404 }
9405
9406 io->timeout = timeout;
9407
9408 ccan_list_head_init(&io->blocking_operations);
9409 io->closing_ec = NULL;
9410 io->wakeup_mutex = Qnil;
9411 io->fork_generation = GET_VM()->fork_gen;
9412
9413 if (encoding) {
9414 io->encs = *encoding;
9415 }
9416
9417 rb_update_max_fd(descriptor);
9418
9419 return self;
9420}
9421
9422static VALUE
9423prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9424{
9425 VALUE path_value = Qnil;
9426 rb_encoding *e;
9427 struct rb_io_encoding convconfig;
9428
9429 if (path) {
9430 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9431 }
9432
9433 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9434 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9435 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9438#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9439 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9440 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9441 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9442#endif
9443 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9444 convconfig.ecopts = Qnil;
9445
9446 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9447 rb_io_t*io = RFILE(self)->fptr;
9448
9449 if (!io_check_tty(io)) {
9450#ifdef __CYGWIN__
9451 io->mode |= FMODE_BINMODE;
9452 setmode(fd, O_BINARY);
9453#endif
9454 }
9455
9456 return self;
9457}
9458
9459VALUE
9460rb_io_fdopen(int fd, int oflags, const char *path)
9461{
9462 VALUE klass = rb_cIO;
9463
9464 if (path && strcmp(path, "-")) klass = rb_cFile;
9465 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9466}
9467
9468static VALUE
9469prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9470{
9471 rb_io_t *fptr;
9472 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9473
9474 GetOpenFile(io, fptr);
9476#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9477 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9478 if (fmode & FMODE_READABLE) {
9480 }
9481#endif
9482 fptr->stdio_file = f;
9483
9484 return io;
9485}
9486
9487VALUE
9488rb_io_prep_stdin(void)
9489{
9490 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9491}
9492
9493VALUE
9494rb_io_prep_stdout(void)
9495{
9496 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9497}
9498
9499VALUE
9500rb_io_prep_stderr(void)
9501{
9502 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9503}
9504
9505FILE *
9507{
9508 if (!fptr->stdio_file) {
9509 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9510 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9511 }
9512 return fptr->stdio_file;
9513}
9514
9515static inline void
9516rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9517{
9518 buf->ptr = NULL;
9519 buf->off = 0;
9520 buf->len = 0;
9521 buf->capa = 0;
9522}
9523
9524static inline rb_io_t *
9525rb_io_fptr_new(void)
9526{
9527 rb_io_t *fp = ALLOC(rb_io_t);
9528 fp->self = Qnil;
9529 fp->fd = -1;
9530 fp->stdio_file = NULL;
9531 fp->mode = 0;
9532 fp->pid = 0;
9533 fp->lineno = 0;
9534 fp->pathv = Qnil;
9535 fp->finalize = 0;
9536 rb_io_buffer_init(&fp->wbuf);
9537 rb_io_buffer_init(&fp->rbuf);
9538 rb_io_buffer_init(&fp->cbuf);
9539 fp->readconv = NULL;
9540 fp->writeconv = NULL;
9542 fp->writeconv_pre_ecflags = 0;
9544 fp->writeconv_initialized = 0;
9545 fp->tied_io_for_writing = 0;
9546 fp->encs.enc = NULL;
9547 fp->encs.enc2 = NULL;
9548 fp->encs.ecflags = 0;
9549 fp->encs.ecopts = Qnil;
9550 fp->write_lock = Qnil;
9551 fp->timeout = Qnil;
9552 ccan_list_head_init(&fp->blocking_operations);
9553 fp->closing_ec = NULL;
9554 fp->wakeup_mutex = Qnil;
9555 fp->fork_generation = GET_VM()->fork_gen;
9556 return fp;
9557}
9558
9559rb_io_t *
9560rb_io_make_open_file(VALUE obj)
9561{
9562 rb_io_t *fp = 0;
9563
9564 Check_Type(obj, T_FILE);
9565 if (RFILE(obj)->fptr) {
9566 rb_io_close(obj);
9567 rb_io_fptr_finalize(RFILE(obj)->fptr);
9568 RFILE(obj)->fptr = 0;
9569 }
9570 fp = rb_io_fptr_new();
9571 fp->self = obj;
9572 RFILE(obj)->fptr = fp;
9573 return fp;
9574}
9575
9576static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9577
9578/*
9579 * call-seq:
9580 * IO.new(fd, mode = 'r', **opts) -> io
9581 *
9582 * Creates and returns a new \IO object (file stream) from a file descriptor.
9583 *
9584 * \IO.new may be useful for interaction with low-level libraries.
9585 * For higher-level interactions, it may be simpler to create
9586 * the file stream using File.open.
9587 *
9588 * Argument +fd+ must be a valid file descriptor (integer):
9589 *
9590 * path = 't.tmp'
9591 * fd = IO.sysopen(path) # => 3
9592 * IO.new(fd) # => #<IO:fd 3>
9593 *
9594 * The new \IO object does not inherit encoding
9595 * (because the integer file descriptor does not have an encoding):
9596 *
9597 * File.read('t.ja') # => "こんにちは"
9598 * fd = IO.sysopen('t.ja', 'rb')
9599 * io = IO.new(fd)
9600 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9601 *
9602 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9603 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9604 *
9605 * IO.new(fd, 'w') # => #<IO:fd 3>
9606 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9607 *
9608 * Optional keyword arguments +opts+ specify:
9609 *
9610 * - {Open Options}[rdoc-ref:IO@Open+Options].
9611 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9612 *
9613 * Examples:
9614 *
9615 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9616 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9617 *
9618 */
9619
9620static VALUE
9621rb_io_initialize(int argc, VALUE *argv, VALUE io)
9622{
9623 VALUE fnum, vmode;
9624 VALUE opt;
9625
9626 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9627 return io_initialize(io, fnum, vmode, opt);
9628}
9629
9630static VALUE
9631io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9632{
9633 rb_io_t *fp;
9634 int fd, oflags = O_RDONLY;
9635 enum rb_io_mode fmode;
9636 struct rb_io_encoding convconfig;
9637#if defined(HAVE_FCNTL) && defined(F_GETFL)
9638 int ofmode;
9639#else
9640 struct stat st;
9641#endif
9642
9643 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9644
9645 fd = NUM2INT(fnum);
9646 if (rb_reserved_fd_p(fd)) {
9647 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9648 }
9649#if defined(HAVE_FCNTL) && defined(F_GETFL)
9650 oflags = fcntl(fd, F_GETFL);
9651 if (oflags == -1) rb_sys_fail(0);
9652#else
9653 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9654#endif
9655 rb_update_max_fd(fd);
9656#if defined(HAVE_FCNTL) && defined(F_GETFL)
9657 ofmode = rb_io_oflags_fmode(oflags);
9658 if (NIL_P(vmode)) {
9659 fmode = ofmode;
9660 }
9661 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9662 VALUE error = INT2FIX(EINVAL);
9664 }
9665#endif
9666 VALUE path = Qnil;
9667
9668 if (!NIL_P(opt)) {
9669 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9670 fmode |= FMODE_EXTERNAL;
9671 }
9672
9673 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9674 if (!NIL_P(path)) {
9675 StringValue(path);
9676 path = rb_str_new_frozen(path);
9677 }
9678 }
9679
9680 MakeOpenFile(io, fp);
9681 fp->self = io;
9682 fp->fd = fd;
9683 fp->mode = fmode;
9684 fp->encs = convconfig;
9685 fp->pathv = path;
9686 fp->timeout = Qnil;
9687 ccan_list_head_init(&fp->blocking_operations);
9688 fp->closing_ec = NULL;
9689 fp->wakeup_mutex = Qnil;
9690 fp->fork_generation = GET_VM()->fork_gen;
9691 clear_codeconv(fp);
9692 io_check_tty(fp);
9693 if (fileno(stdin) == fd)
9694 fp->stdio_file = stdin;
9695 else if (fileno(stdout) == fd)
9696 fp->stdio_file = stdout;
9697 else if (fileno(stderr) == fd)
9698 fp->stdio_file = stderr;
9699
9700 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9701 return io;
9702}
9703
9704/*
9705 * call-seq:
9706 * set_encoding_by_bom -> encoding or nil
9707 *
9708 * If the stream begins with a BOM
9709 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9710 * consumes the BOM and sets the external encoding accordingly;
9711 * returns the result encoding if found, or +nil+ otherwise:
9712 *
9713 * File.write('t.tmp', "\u{FEFF}abc")
9714 * io = File.open('t.tmp', 'rb')
9715 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9716 * io.close
9717 *
9718 * File.write('t.tmp', 'abc')
9719 * io = File.open('t.tmp', 'rb')
9720 * io.set_encoding_by_bom # => nil
9721 * io.close
9722 *
9723 * Raises an exception if the stream is not binmode
9724 * or its encoding has already been set.
9725 *
9726 */
9727
9728static VALUE
9729rb_io_set_encoding_by_bom(VALUE io)
9730{
9731 rb_io_t *fptr;
9732
9733 GetOpenFile(io, fptr);
9734 if (!(fptr->mode & FMODE_BINMODE)) {
9735 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9736 }
9737 if (fptr->encs.enc2) {
9738 rb_raise(rb_eArgError, "encoding conversion is set");
9739 }
9740 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9741 rb_raise(rb_eArgError, "encoding is set to %s already",
9742 rb_enc_name(fptr->encs.enc));
9743 }
9744 if (!io_set_encoding_by_bom(io)) return Qnil;
9745 return rb_enc_from_encoding(fptr->encs.enc);
9746}
9747
9748/*
9749 * :markup: markdown
9750 *
9751 * call-seq:
9752 * File.new(path, mode = 'r', permissions = 0666, **options) -> file
9753 *
9754 * Opens the file as specified by the given arguments.
9755 * Creates and returns a new open \File object for that file;
9756 * the opened file is in non-synchronous mode.
9757 *
9758 * Argument `path` must the string path to an existing filesystem entry:
9759 *
9760 * ```ruby
9761 * file = File.new('doc/maintainers.md') # => #<File:doc/maintainers.md>
9762 * file.close # Clean up.
9763 * tty = File.new('/dev/tty') # => #<File:/dev/tty>
9764 * tty.close # Clean up.
9765 * ```
9766 *
9767 * Note that the caller is responsible for closing the file;
9768 * see File.open for automatic closing.
9769 *
9770 * Optional argument `mode` (defaults to `'r'`) must specify a valid mode;
9771 * see [Access Modes](rdoc-ref:File@Access+Modes):
9772 *
9773 * ```ruby
9774 * file = File.new('t.tmp', 'w') # => #<File:t.tmp>
9775 * file.close # Clean up.
9776 * file = File.new('t.tmp', File::RDONLY) # => #<File:t.tmp>
9777 * file.close # Clean up.
9778 * ```
9779 *
9780 * Optional argument `permissions` (defaults to `0666`) must specify valid permissions;
9781 * see [File Permissions](rdoc-ref:File@File+Permissions):
9782 *
9783 * ```ruby
9784 * file = File.new('t.tmp', 'w', 0644) # => #<File:t.tmp>
9785 * file.close # Clean up.
9786 * file = File.new('t.tmp', 'w', 0444) # => #<File:t.tmp>
9787 * file.close # Clean up.
9788 * ```
9789 *
9790 * Optional keyword arguments `options` specify:
9791 *
9792 * - [Open Options](rdoc-ref:IO@Open+Options).
9793 * - [Encoding options](rdoc-ref:encodings.rdoc@Encoding+Options).
9794 *
9795 */
9796
9797static VALUE
9798rb_file_initialize(int argc, VALUE *argv, VALUE io)
9799{
9800 if (RFILE(io)->fptr) {
9801 rb_raise(rb_eRuntimeError, "reinitializing File");
9802 }
9803 VALUE fname, vmode, vperm, opt;
9804 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9805 if (posargc < 3) { /* perm is File only */
9806 VALUE fd = rb_check_to_int(fname);
9807
9808 if (!NIL_P(fd)) {
9809 return io_initialize(io, fd, vmode, opt);
9810 }
9811 }
9812 return rb_open_file(io, fname, vmode, vperm, opt);
9813}
9814
9815/* :nodoc: */
9816static VALUE
9817rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9818{
9819 if (rb_block_given_p()) {
9820 VALUE cname = rb_obj_as_string(klass);
9821
9822 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9823 cname, cname);
9824 }
9825 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9826}
9827
9828
9829/*
9830 * call-seq:
9831 * IO.for_fd(fd, mode = 'r', **opts) -> io
9832 *
9833 * Synonym for IO.new.
9834 *
9835 */
9836
9837static VALUE
9838rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9839{
9840 VALUE io = rb_obj_alloc(klass);
9841 rb_io_initialize(argc, argv, io);
9842 return io;
9843}
9844
9845/*
9846 * call-seq:
9847 * ios.autoclose? -> true or false
9848 *
9849 * Returns +true+ if the underlying file descriptor of _ios_ will be
9850 * closed at its finalization or at calling #close, otherwise +false+.
9851 */
9852
9853static VALUE
9854rb_io_autoclose_p(VALUE io)
9855{
9856 rb_io_t *fptr = RFILE(io)->fptr;
9857 rb_io_check_closed(fptr);
9858 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9859}
9860
9861/*
9862 * call-seq:
9863 * io.autoclose = bool -> true or false
9864 *
9865 * Sets auto-close flag.
9866 *
9867 * f = File.open(File::NULL)
9868 * IO.for_fd(f.fileno).close
9869 * f.gets # raises Errno::EBADF
9870 *
9871 * f = File.open(File::NULL)
9872 * g = IO.for_fd(f.fileno)
9873 * g.autoclose = false
9874 * g.close
9875 * f.gets # won't cause Errno::EBADF
9876 */
9877
9878static VALUE
9879rb_io_set_autoclose(VALUE io, VALUE autoclose)
9880{
9881 rb_io_t *fptr;
9882 GetOpenFile(io, fptr);
9883 if (!RTEST(autoclose))
9884 fptr->mode |= FMODE_EXTERNAL;
9885 else
9886 fptr->mode &= ~FMODE_EXTERNAL;
9887 return autoclose;
9888}
9889
9890static VALUE
9891io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9892{
9893 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9894
9895 if (!RB_TEST(result)) {
9896 return Qnil;
9897 }
9898
9899 int mask = RB_NUM2INT(result);
9900
9901 if (mask & event) {
9902 if (return_io)
9903 return io;
9904 else
9905 return result;
9906 }
9907 else {
9908 return Qfalse;
9909 }
9910}
9911
9912/*
9913 * call-seq:
9914 * io.wait_readable -> truthy or falsy
9915 * io.wait_readable(timeout) -> truthy or falsy
9916 *
9917 * Waits until IO is readable and returns a truthy value, or a falsy
9918 * value when times out. Returns a truthy value immediately when
9919 * buffered data is available.
9920 */
9921
9922static VALUE
9923io_wait_readable(int argc, VALUE *argv, VALUE io)
9924{
9925 rb_io_t *fptr;
9926
9927 RB_IO_POINTER(io, fptr);
9929
9930 if (rb_io_read_pending(fptr)) return Qtrue;
9931
9932 rb_check_arity(argc, 0, 1);
9933 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9934
9935 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9936}
9937
9938/*
9939 * call-seq:
9940 * io.wait_writable -> truthy or falsy
9941 * io.wait_writable(timeout) -> truthy or falsy
9942 *
9943 * Waits until IO is writable and returns a truthy value or a falsy
9944 * value when times out.
9945 */
9946static VALUE
9947io_wait_writable(int argc, VALUE *argv, VALUE io)
9948{
9949 rb_io_t *fptr;
9950
9951 RB_IO_POINTER(io, fptr);
9953
9954 rb_check_arity(argc, 0, 1);
9955 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9956
9957 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9958}
9959
9960/*
9961 * call-seq:
9962 * io.wait_priority -> truthy or falsy
9963 * io.wait_priority(timeout) -> truthy or falsy
9964 *
9965 * Waits until IO is priority and returns a truthy value or a falsy
9966 * value when times out. Priority data is sent and received using
9967 * the Socket::MSG_OOB flag and is typically limited to streams.
9968 */
9969static VALUE
9970io_wait_priority(int argc, VALUE *argv, VALUE io)
9971{
9972 rb_io_t *fptr = NULL;
9973
9974 RB_IO_POINTER(io, fptr);
9976
9977 if (rb_io_read_pending(fptr)) return Qtrue;
9978
9979 rb_check_arity(argc, 0, 1);
9980 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9981
9982 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9983}
9984
9985static int
9986wait_mode_sym(VALUE mode)
9987{
9988 if (mode == ID2SYM(rb_intern("r"))) {
9989 return RB_WAITFD_IN;
9990 }
9991 if (mode == ID2SYM(rb_intern("read"))) {
9992 return RB_WAITFD_IN;
9993 }
9994 if (mode == ID2SYM(rb_intern("readable"))) {
9995 return RB_WAITFD_IN;
9996 }
9997 if (mode == ID2SYM(rb_intern("w"))) {
9998 return RB_WAITFD_OUT;
9999 }
10000 if (mode == ID2SYM(rb_intern("write"))) {
10001 return RB_WAITFD_OUT;
10002 }
10003 if (mode == ID2SYM(rb_intern("writable"))) {
10004 return RB_WAITFD_OUT;
10005 }
10006 if (mode == ID2SYM(rb_intern("rw"))) {
10007 return RB_WAITFD_IN|RB_WAITFD_OUT;
10008 }
10009 if (mode == ID2SYM(rb_intern("read_write"))) {
10010 return RB_WAITFD_IN|RB_WAITFD_OUT;
10011 }
10012 if (mode == ID2SYM(rb_intern("readable_writable"))) {
10013 return RB_WAITFD_IN|RB_WAITFD_OUT;
10014 }
10015
10016 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
10017}
10018
10019static inline enum rb_io_event
10020io_event_from_value(VALUE value)
10021{
10022 int events = RB_NUM2INT(value);
10023
10024 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
10025
10026 return events;
10027}
10028
10029/*
10030 * call-seq:
10031 * io.wait(events, timeout) -> event mask, false or nil
10032 * io.wait(*event_symbols[, timeout]) -> self, true, or false
10033 *
10034 * Waits until the IO becomes ready for the specified events and returns the
10035 * subset of events that become ready, or a falsy value when times out.
10036 *
10037 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
10038 * +IO::PRIORITY+.
10039 *
10040 * Returns an event mask (truthy value) immediately when buffered data is
10041 * available.
10042 *
10043 * The second form: if one or more event symbols (+:read+, +:write+, or
10044 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
10045 * corresponding to those symbols. In this form, +timeout+ is optional, the
10046 * order of the arguments is arbitrary, and returns +io+ if any of the
10047 * events is ready.
10048 */
10049
10050static VALUE
10051io_wait(int argc, VALUE *argv, VALUE io)
10052{
10053 VALUE timeout = Qundef;
10054 enum rb_io_event events = 0;
10055 int return_io = 0;
10056
10057 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
10058 // We'd prefer to return the actual mask, but this form would return the io itself:
10059 return_io = 1;
10060
10061 // Slow/messy path:
10062 for (int i = 0; i < argc; i += 1) {
10063 if (RB_SYMBOL_P(argv[i])) {
10064 events |= wait_mode_sym(argv[i]);
10065 }
10066 else if (UNDEF_P(timeout)) {
10067 rb_time_interval(timeout = argv[i]);
10068 }
10069 else {
10070 rb_raise(rb_eArgError, "timeout given more than once");
10071 }
10072 }
10073
10074 if (UNDEF_P(timeout)) timeout = Qnil;
10075
10076 if (events == 0) {
10077 events = RUBY_IO_READABLE;
10078 }
10079 }
10080 else /* argc == 2 and neither are symbols */ {
10081 // This is the fast path:
10082 events = io_event_from_value(argv[0]);
10083 timeout = argv[1];
10084 }
10085
10086 if (events & RUBY_IO_READABLE) {
10087 rb_io_t *fptr = NULL;
10088 RB_IO_POINTER(io, fptr);
10089
10090 if (rb_io_read_pending(fptr)) {
10091 // This was the original behaviour:
10092 if (return_io) return Qtrue;
10093 // New behaviour always returns an event mask:
10094 else return RB_INT2NUM(RUBY_IO_READABLE);
10095 }
10096 }
10097
10098 return io_wait_event(io, events, timeout, return_io);
10099}
10100
10101static void
10102argf_mark_and_move(void *ptr)
10103{
10104 struct argf *p = ptr;
10105 rb_gc_mark_and_move(&p->filename);
10106 rb_gc_mark_and_move(&p->current_file);
10107 rb_gc_mark_and_move(&p->argv);
10108 rb_gc_mark_and_move(&p->inplace);
10109 rb_gc_mark_and_move(&p->encs.ecopts);
10110}
10111
10112static size_t
10113argf_memsize(const void *ptr)
10114{
10115 const struct argf *p = ptr;
10116 size_t size = sizeof(*p);
10117 return size;
10118}
10119
10120static const rb_data_type_t argf_type = {
10121 "ARGF",
10122 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10123 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10124};
10125
10126static inline void
10127argf_init(VALUE argf, struct argf *p, VALUE v)
10128{
10129 p->filename = Qnil;
10130 p->current_file = Qnil;
10131 p->lineno = 0;
10132 RB_OBJ_WRITE(argf, &p->argv, v);
10133}
10134
10135static VALUE
10136argf_alloc(VALUE klass)
10137{
10138 struct argf *p;
10139 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10140
10141 argf_init(argf, p, Qnil);
10142 return argf;
10143}
10144
10145#undef rb_argv
10146
10147/* :nodoc: */
10148static VALUE
10149argf_initialize(VALUE argf, VALUE argv)
10150{
10151 memset(&ARGF, 0, sizeof(ARGF));
10152 argf_init(argf, &ARGF, argv);
10153
10154 return argf;
10155}
10156
10157/* :nodoc: */
10158static VALUE
10159argf_initialize_copy(VALUE argf, VALUE orig)
10160{
10161 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10162 ARGF = argf_of(orig);
10163 rb_gc_writebarrier_remember(argf);
10164 ARGF_SET(argv, rb_obj_dup(ARGF.argv));
10165 return argf;
10166}
10167
10168/*
10169 * call-seq:
10170 * ARGF.lineno = integer -> integer
10171 *
10172 * Sets the line number of ARGF as a whole to the given Integer.
10173 *
10174 * ARGF sets the line number automatically as you read data, so normally
10175 * you will not need to set it explicitly. To access the current line number
10176 * use ARGF.lineno.
10177 *
10178 * For example:
10179 *
10180 * ARGF.lineno #=> 0
10181 * ARGF.readline #=> "This is line 1\n"
10182 * ARGF.lineno #=> 1
10183 * ARGF.lineno = 0 #=> 0
10184 * ARGF.lineno #=> 0
10185 */
10186static VALUE
10187argf_set_lineno(VALUE argf, VALUE val)
10188{
10189 ARGF.lineno = NUM2INT(val);
10190 ARGF.last_lineno = ARGF.lineno;
10191 return val;
10192}
10193
10194/*
10195 * call-seq:
10196 * ARGF.lineno -> integer
10197 *
10198 * Returns the current line number of ARGF as a whole. This value
10199 * can be set manually with ARGF.lineno=.
10200 *
10201 * For example:
10202 *
10203 * ARGF.lineno #=> 0
10204 * ARGF.readline #=> "This is line 1\n"
10205 * ARGF.lineno #=> 1
10206 */
10207static VALUE
10208argf_lineno(VALUE argf)
10209{
10210 return INT2FIX(ARGF.lineno);
10211}
10212
10213static VALUE
10214argf_forward(int argc, VALUE *argv, VALUE argf)
10215{
10216 return forward_current(rb_frame_this_func(), argc, argv);
10217}
10218
10219#define next_argv() argf_next_argv(argf)
10220#define ARGF_GENERIC_INPUT_P() \
10221 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10222#define ARGF_FORWARD(argc, argv) do {\
10223 if (ARGF_GENERIC_INPUT_P())\
10224 return argf_forward((argc), (argv), argf);\
10225} while (0)
10226#define NEXT_ARGF_FORWARD(argc, argv) do {\
10227 if (!next_argv()) return Qnil;\
10228 ARGF_FORWARD((argc), (argv));\
10229} while (0)
10230
10231static void
10232argf_close(VALUE argf)
10233{
10234 VALUE file = ARGF.current_file;
10235 if (file == rb_stdin) return;
10236 if (RB_TYPE_P(file, T_FILE)) {
10237 rb_io_set_write_io(file, Qnil);
10238 }
10239 io_close(file);
10240 ARGF.init_p = -1;
10241}
10242
10243static int
10244argf_next_argv(VALUE argf)
10245{
10246 char *fn;
10247 rb_io_t *fptr;
10248 int stdout_binmode = 0;
10249 enum rb_io_mode fmode;
10250
10251 VALUE r_stdout = rb_ractor_stdout();
10252
10253 if (RB_TYPE_P(r_stdout, T_FILE)) {
10254 GetOpenFile(r_stdout, fptr);
10255 if (fptr->mode & FMODE_BINMODE)
10256 stdout_binmode = 1;
10257 }
10258
10259 if (ARGF.init_p == 0) {
10260 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10261 ARGF.next_p = 1;
10262 }
10263 else {
10264 ARGF.next_p = -1;
10265 }
10266 ARGF.init_p = 1;
10267 }
10268 else {
10269 if (NIL_P(ARGF.argv)) {
10270 ARGF.next_p = -1;
10271 }
10272 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10273 ARGF.next_p = 1;
10274 }
10275 }
10276
10277 if (ARGF.next_p == 1) {
10278 if (ARGF.init_p == 1) argf_close(argf);
10279 retry:
10280 if (RARRAY_LEN(ARGF.argv) > 0) {
10281 VALUE filename = rb_ary_shift(ARGF.argv);
10282 FilePathValue(filename);
10283 ARGF_SET(filename, filename);
10284 filename = rb_str_encode_ospath(filename);
10285 fn = StringValueCStr(filename);
10286 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10287 ARGF_SET(current_file, rb_stdin);
10288 if (ARGF.inplace) {
10289 rb_warn("Can't do inplace edit for stdio; skipping");
10290 goto retry;
10291 }
10292 }
10293 else {
10294 VALUE write_io = Qnil;
10295 int fr = rb_sysopen(filename, O_RDONLY, 0);
10296
10297 if (ARGF.inplace) {
10298 struct stat st;
10299#ifndef NO_SAFE_RENAME
10300 struct stat st2;
10301#endif
10302 VALUE str;
10303 int fw;
10304
10305 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10306 rb_io_close(r_stdout);
10307 }
10308 fstat(fr, &st);
10309 str = filename;
10310 if (!NIL_P(ARGF.inplace)) {
10311 VALUE suffix = ARGF.inplace;
10312 str = rb_str_dup(str);
10313 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10314 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10315 rb_enc_get(suffix), 0, Qnil))) {
10316 rb_str_append(str, suffix);
10317 }
10318#ifdef NO_SAFE_RENAME
10319 (void)close(fr);
10320 (void)unlink(RSTRING_PTR(str));
10321 if (rename(fn, RSTRING_PTR(str)) < 0) {
10322 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10323 filename, str, strerror(errno));
10324 goto retry;
10325 }
10326 fr = rb_sysopen(str, O_RDONLY, 0);
10327#else
10328 if (rename(fn, RSTRING_PTR(str)) < 0) {
10329 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10330 filename, str, strerror(errno));
10331 close(fr);
10332 goto retry;
10333 }
10334#endif
10335 }
10336 else {
10337#ifdef NO_SAFE_RENAME
10338 rb_fatal("Can't do inplace edit without backup");
10339#else
10340 if (unlink(fn) < 0) {
10341 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10342 filename, strerror(errno));
10343 close(fr);
10344 goto retry;
10345 }
10346#endif
10347 }
10348 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10349#ifndef NO_SAFE_RENAME
10350 fstat(fw, &st2);
10351#ifdef HAVE_FCHMOD
10352 fchmod(fw, st.st_mode);
10353#else
10354 chmod(fn, st.st_mode);
10355#endif
10356 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10357 int err;
10358#ifdef HAVE_FCHOWN
10359 err = fchown(fw, st.st_uid, st.st_gid);
10360#else
10361 err = chown(fn, st.st_uid, st.st_gid);
10362#endif
10363 if (err && getuid() == 0 && st2.st_uid == 0) {
10364 const char *wkfn = RSTRING_PTR(filename);
10365 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10366 filename, str, strerror(errno));
10367 (void)close(fr);
10368 (void)close(fw);
10369 (void)unlink(wkfn);
10370 goto retry;
10371 }
10372 }
10373#endif
10374 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10375 rb_ractor_stdout_set(write_io);
10376 if (stdout_binmode) rb_io_binmode(rb_stdout);
10377 }
10378 fmode = FMODE_READABLE;
10379 if (!ARGF.binmode) {
10380 fmode |= DEFAULT_TEXTMODE;
10381 }
10382 ARGF_SET(current_file, prep_io(fr, fmode, rb_cFile, fn));
10383 if (!NIL_P(write_io)) {
10384 rb_io_set_write_io(ARGF.current_file, write_io);
10385 }
10386 RB_GC_GUARD(filename);
10387 }
10388 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10389 GetOpenFile(ARGF.current_file, fptr);
10390 if (ARGF.encs.enc) {
10391 fptr->encs = ARGF.encs;
10392 clear_codeconv(fptr);
10393 }
10394 else {
10395 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10396 if (!ARGF.binmode) {
10398#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10399 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10400#endif
10401 }
10402 }
10403 ARGF.next_p = 0;
10404 }
10405 else {
10406 ARGF.next_p = 1;
10407 return FALSE;
10408 }
10409 }
10410 else if (ARGF.next_p == -1) {
10411 ARGF_SET(current_file, rb_stdin);
10412 ARGF_SET(filename, rb_str_new2("-"));
10413 if (ARGF.inplace) {
10414 rb_warn("Can't do inplace edit for stdio");
10415 rb_ractor_stdout_set(orig_stdout);
10416 }
10417 }
10418 if (ARGF.init_p == -1) ARGF.init_p = 1;
10419 return TRUE;
10420}
10421
10422static VALUE
10423argf_getline(int argc, VALUE *argv, VALUE argf)
10424{
10425 VALUE line;
10426 long lineno = ARGF.lineno;
10427
10428 retry:
10429 if (!next_argv()) return Qnil;
10430 if (ARGF_GENERIC_INPUT_P()) {
10431 line = forward_current(idGets, argc, argv);
10432 }
10433 else {
10434 if (argc == 0 && rb_rs == rb_default_rs) {
10435 line = rb_io_gets(ARGF.current_file);
10436 }
10437 else {
10438 line = rb_io_getline(argc, argv, ARGF.current_file);
10439 }
10440 if (NIL_P(line) && ARGF.next_p != -1) {
10441 argf_close(argf);
10442 ARGF.next_p = 1;
10443 goto retry;
10444 }
10445 }
10446 if (!NIL_P(line)) {
10447 ARGF.lineno = ++lineno;
10448 ARGF.last_lineno = ARGF.lineno;
10449 }
10450 return line;
10451}
10452
10453static VALUE
10454argf_lineno_getter(ID id, VALUE *var)
10455{
10456 VALUE argf = *var;
10457 return INT2FIX(ARGF.last_lineno);
10458}
10459
10460static void
10461argf_lineno_setter(VALUE val, ID id, VALUE *var)
10462{
10463 VALUE argf = *var;
10464 int n = NUM2INT(val);
10465 ARGF.last_lineno = ARGF.lineno = n;
10466}
10467
10468void
10469rb_reset_argf_lineno(long n)
10470{
10471 ARGF.last_lineno = ARGF.lineno = n;
10472}
10473
10474static VALUE argf_gets(int, VALUE *, VALUE);
10475
10476/*
10477 * call-seq:
10478 * gets(sep=$/ [, getline_args]) -> string or nil
10479 * gets(limit [, getline_args]) -> string or nil
10480 * gets(sep, limit [, getline_args]) -> string or nil
10481 *
10482 * Returns (and assigns to <code>$_</code>) the next line from the list
10483 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10484 * no files are present on the command line. Returns +nil+ at end of
10485 * file. The optional argument specifies the record separator. The
10486 * separator is included with the contents of each record. A separator
10487 * of +nil+ reads the entire contents, and a zero-length separator
10488 * reads the input one paragraph at a time, where paragraphs are
10489 * divided by two consecutive newlines. If the first argument is an
10490 * integer, or optional second argument is given, the returning string
10491 * would not be longer than the given value in bytes. If multiple
10492 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10493 * the contents one file at a time.
10494 *
10495 * ARGV << "testfile"
10496 * print while gets
10497 *
10498 * <em>produces:</em>
10499 *
10500 * This is line one
10501 * This is line two
10502 * This is line three
10503 * And so on...
10504 *
10505 * The style of programming using <code>$_</code> as an implicit
10506 * parameter is gradually losing favor in the Ruby community.
10507 */
10508
10509static VALUE
10510rb_f_gets(int argc, VALUE *argv, VALUE recv)
10511{
10512 if (recv == argf) {
10513 return argf_gets(argc, argv, argf);
10514 }
10515 return forward(argf, idGets, argc, argv);
10516}
10517
10518/*
10519 * call-seq:
10520 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10521 * ARGF.gets(limit [, getline_args]) -> string or nil
10522 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10523 *
10524 * Returns the next line from the current file in ARGF.
10525 *
10526 * By default lines are assumed to be separated by <code>$/</code>;
10527 * to use a different character as a separator, supply it as a String
10528 * for the _sep_ argument.
10529 *
10530 * The optional _limit_ argument specifies how many characters of each line
10531 * to return. By default all characters are returned.
10532 *
10533 * See IO.readlines for details about getline_args.
10534 *
10535 */
10536static VALUE
10537argf_gets(int argc, VALUE *argv, VALUE argf)
10538{
10539 VALUE line;
10540
10541 line = argf_getline(argc, argv, argf);
10542 rb_lastline_set(line);
10543
10544 return line;
10545}
10546
10547VALUE
10549{
10550 VALUE line;
10551
10552 if (rb_rs != rb_default_rs) {
10553 return rb_f_gets(0, 0, argf);
10554 }
10555
10556 retry:
10557 if (!next_argv()) return Qnil;
10558 line = rb_io_gets(ARGF.current_file);
10559 if (NIL_P(line) && ARGF.next_p != -1) {
10560 rb_io_close(ARGF.current_file);
10561 ARGF.next_p = 1;
10562 goto retry;
10563 }
10564 rb_lastline_set(line);
10565 if (!NIL_P(line)) {
10566 ARGF.lineno++;
10567 ARGF.last_lineno = ARGF.lineno;
10568 }
10569
10570 return line;
10571}
10572
10573static VALUE argf_readline(int, VALUE *, VALUE);
10574
10575/*
10576 * call-seq:
10577 * readline(sep = $/, chomp: false) -> string
10578 * readline(limit, chomp: false) -> string
10579 * readline(sep, limit, chomp: false) -> string
10580 *
10581 * Equivalent to method Kernel#gets, except that it raises an exception
10582 * if called at end-of-stream:
10583 *
10584 * $ cat t.txt | ruby -e "p readlines; readline"
10585 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10586 * in `readline': end of file reached (EOFError)
10587 *
10588 * Optional keyword argument +chomp+ specifies whether line separators
10589 * are to be omitted.
10590 */
10591
10592static VALUE
10593rb_f_readline(int argc, VALUE *argv, VALUE recv)
10594{
10595 if (recv == argf) {
10596 return argf_readline(argc, argv, argf);
10597 }
10598 return forward(argf, rb_intern("readline"), argc, argv);
10599}
10600
10601
10602/*
10603 * call-seq:
10604 * ARGF.readline(sep=$/) -> string
10605 * ARGF.readline(limit) -> string
10606 * ARGF.readline(sep, limit) -> string
10607 *
10608 * Returns the next line from the current file in ARGF.
10609 *
10610 * By default lines are assumed to be separated by <code>$/</code>;
10611 * to use a different character as a separator, supply it as a String
10612 * for the _sep_ argument.
10613 *
10614 * The optional _limit_ argument specifies how many characters of each line
10615 * to return. By default all characters are returned.
10616 *
10617 * An EOFError is raised at the end of the file.
10618 */
10619static VALUE
10620argf_readline(int argc, VALUE *argv, VALUE argf)
10621{
10622 VALUE line;
10623
10624 if (!next_argv()) rb_eof_error();
10625 ARGF_FORWARD(argc, argv);
10626 line = argf_gets(argc, argv, argf);
10627 if (NIL_P(line)) {
10628 rb_eof_error();
10629 }
10630
10631 return line;
10632}
10633
10634static VALUE argf_readlines(int, VALUE *, VALUE);
10635
10636/*
10637 * call-seq:
10638 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10639 * readlines(limit, chomp: false, **enc_opts) -> array
10640 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10641 *
10642 * Returns an array containing the lines returned by calling
10643 * Kernel#gets until the end-of-stream is reached;
10644 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10645 *
10646 * With only string argument +sep+ given,
10647 * returns the remaining lines as determined by line separator +sep+,
10648 * or +nil+ if none;
10649 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10650 *
10651 * # Default separator.
10652 * $ cat t.txt | ruby -e "p readlines"
10653 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10654 *
10655 * # Specified separator.
10656 * $ cat t.txt | ruby -e "p readlines 'li'"
10657 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10658 *
10659 * # Get-all separator.
10660 * $ cat t.txt | ruby -e "p readlines nil"
10661 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10662 *
10663 * # Get-paragraph separator.
10664 * $ cat t.txt | ruby -e "p readlines ''"
10665 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10666 *
10667 * With only integer argument +limit+ given,
10668 * limits the number of bytes in the line;
10669 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10670 *
10671 * $cat t.txt | ruby -e "p readlines 10"
10672 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10673 *
10674 * $cat t.txt | ruby -e "p readlines 11"
10675 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10676 *
10677 * $cat t.txt | ruby -e "p readlines 12"
10678 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10679 *
10680 * With arguments +sep+ and +limit+ given,
10681 * combines the two behaviors
10682 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10683 *
10684 * Optional keyword argument +chomp+ specifies whether line separators
10685 * are to be omitted:
10686 *
10687 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10688 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10689 *
10690 * Optional keyword arguments +enc_opts+ specify encoding options;
10691 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10692 *
10693 */
10694
10695static VALUE
10696rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10697{
10698 if (recv == argf) {
10699 return argf_readlines(argc, argv, argf);
10700 }
10701 return forward(argf, rb_intern("readlines"), argc, argv);
10702}
10703
10704/*
10705 * call-seq:
10706 * ARGF.readlines(sep = $/, chomp: false) -> array
10707 * ARGF.readlines(limit, chomp: false) -> array
10708 * ARGF.readlines(sep, limit, chomp: false) -> array
10709 *
10710 * ARGF.to_a(sep = $/, chomp: false) -> array
10711 * ARGF.to_a(limit, chomp: false) -> array
10712 * ARGF.to_a(sep, limit, chomp: false) -> array
10713 *
10714 * Reads each file in ARGF in its entirety, returning an Array containing
10715 * lines from the files. Lines are assumed to be separated by _sep_.
10716 *
10717 * lines = ARGF.readlines
10718 * lines[0] #=> "This is line one\n"
10719 *
10720 * See +IO.readlines+ for a full description of all options.
10721 */
10722static VALUE
10723argf_readlines(int argc, VALUE *argv, VALUE argf)
10724{
10725 long lineno = ARGF.lineno;
10726 VALUE lines, ary;
10727
10728 ary = rb_ary_new();
10729 while (next_argv()) {
10730 if (ARGF_GENERIC_INPUT_P()) {
10731 lines = forward_current(rb_intern("readlines"), argc, argv);
10732 }
10733 else {
10734 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10735 argf_close(argf);
10736 }
10737 ARGF.next_p = 1;
10738 rb_ary_concat(ary, lines);
10739 ARGF.lineno = lineno + RARRAY_LEN(ary);
10740 ARGF.last_lineno = ARGF.lineno;
10741 }
10742 ARGF.init_p = 0;
10743 return ary;
10744}
10745
10746/*
10747 * call-seq:
10748 * `command` -> string
10749 *
10750 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10751 * sets global variable <tt>$?</tt> to the process status.
10752 *
10753 * This method has potential security vulnerabilities if called with untrusted input;
10754 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
10755 *
10756 * Examples:
10757 *
10758 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10759 * $ `echo oops && exit 99` # => "oops\n"
10760 * $ $? # => #<Process::Status: pid 17088 exit 99>
10761 * $ $?.exitstatus # => 99
10762 *
10763 * The built-in syntax <tt>%x{...}</tt> uses this method.
10764 *
10765 */
10766
10767static VALUE
10768rb_f_backquote(VALUE obj, VALUE str)
10769{
10770 VALUE port;
10771 VALUE result;
10772 rb_io_t *fptr;
10773
10774 StringValue(str);
10775 rb_last_status_clear();
10776 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10777 if (NIL_P(port)) return rb_str_new(0,0);
10778
10779 GetOpenFile(port, fptr);
10780 result = read_all(fptr, remain_size(fptr), Qnil);
10781 rb_io_close(port);
10782 rb_io_fptr_cleanup_all(fptr);
10783 RB_GC_GUARD(port);
10784
10785 return result;
10786}
10787
10788#ifdef HAVE_SYS_SELECT_H
10789#include <sys/select.h>
10790#endif
10791
10792static VALUE
10793select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10794{
10795 VALUE res, list;
10796 rb_fdset_t *rp, *wp, *ep;
10797 rb_io_t *fptr;
10798 long i;
10799 int max = 0, n;
10800 int pending = 0;
10801 struct timeval timerec;
10802
10803 if (!NIL_P(read)) {
10804 Check_Type(read, T_ARRAY);
10805 for (i=0; i<RARRAY_LEN(read); i++) {
10806 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10807 rb_fd_set(fptr->fd, &fds[0]);
10808 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10809 pending++;
10810 rb_fd_set(fptr->fd, &fds[3]);
10811 }
10812 if (max < fptr->fd) max = fptr->fd;
10813 }
10814 if (pending) { /* no blocking if there's buffered data */
10815 timerec.tv_sec = timerec.tv_usec = 0;
10816 tp = &timerec;
10817 }
10818 rp = &fds[0];
10819 }
10820 else
10821 rp = 0;
10822
10823 if (!NIL_P(write)) {
10824 Check_Type(write, T_ARRAY);
10825 for (i=0; i<RARRAY_LEN(write); i++) {
10826 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10827 GetOpenFile(write_io, fptr);
10828 rb_fd_set(fptr->fd, &fds[1]);
10829 if (max < fptr->fd) max = fptr->fd;
10830 }
10831 wp = &fds[1];
10832 }
10833 else
10834 wp = 0;
10835
10836 if (!NIL_P(except)) {
10837 Check_Type(except, T_ARRAY);
10838 for (i=0; i<RARRAY_LEN(except); i++) {
10839 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10840 VALUE write_io = GetWriteIO(io);
10841 GetOpenFile(io, fptr);
10842 rb_fd_set(fptr->fd, &fds[2]);
10843 if (max < fptr->fd) max = fptr->fd;
10844 if (io != write_io) {
10845 GetOpenFile(write_io, fptr);
10846 rb_fd_set(fptr->fd, &fds[2]);
10847 if (max < fptr->fd) max = fptr->fd;
10848 }
10849 }
10850 ep = &fds[2];
10851 }
10852 else {
10853 ep = 0;
10854 }
10855
10856 max++;
10857
10858 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10859 if (n < 0) {
10860 rb_sys_fail(0);
10861 }
10862 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10863
10864 res = rb_ary_new2(3);
10865 rb_ary_push(res, rp ? rb_ary_new_capa(RARRAY_LEN(read)) : rb_ary_new());
10866 rb_ary_push(res, wp ? rb_ary_new_capa(RARRAY_LEN(write)) : rb_ary_new());
10867 rb_ary_push(res, ep ? rb_ary_new_capa(RARRAY_LEN(except)) : rb_ary_new());
10868
10869 if (rp) {
10870 list = RARRAY_AREF(res, 0);
10871 for (i=0; i< RARRAY_LEN(read); i++) {
10872 VALUE obj = rb_ary_entry(read, i);
10873 VALUE io = rb_io_get_io(obj);
10874 GetOpenFile(io, fptr);
10875 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10876 rb_fd_isset(fptr->fd, &fds[3])) {
10877 rb_ary_push(list, obj);
10878 }
10879 }
10880 }
10881
10882 if (wp) {
10883 list = RARRAY_AREF(res, 1);
10884 for (i=0; i< RARRAY_LEN(write); i++) {
10885 VALUE obj = rb_ary_entry(write, i);
10886 VALUE io = rb_io_get_io(obj);
10887 VALUE write_io = GetWriteIO(io);
10888 GetOpenFile(write_io, fptr);
10889 if (rb_fd_isset(fptr->fd, &fds[1])) {
10890 rb_ary_push(list, obj);
10891 }
10892 }
10893 }
10894
10895 if (ep) {
10896 list = RARRAY_AREF(res, 2);
10897 for (i=0; i< RARRAY_LEN(except); i++) {
10898 VALUE obj = rb_ary_entry(except, i);
10899 VALUE io = rb_io_get_io(obj);
10900 VALUE write_io = GetWriteIO(io);
10901 GetOpenFile(io, fptr);
10902 if (rb_fd_isset(fptr->fd, &fds[2])) {
10903 rb_ary_push(list, obj);
10904 }
10905 else if (io != write_io) {
10906 GetOpenFile(write_io, fptr);
10907 if (rb_fd_isset(fptr->fd, &fds[2])) {
10908 rb_ary_push(list, obj);
10909 }
10910 }
10911 }
10912 }
10913
10914 return res; /* returns an empty array on interrupt */
10915}
10916
10918 VALUE read, write, except;
10919 struct timeval *timeout;
10920 rb_fdset_t fdsets[4];
10921};
10922
10923static VALUE
10924select_call(VALUE arg)
10925{
10926 struct select_args *p = (struct select_args *)arg;
10927
10928 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10929}
10930
10931static VALUE
10932select_end(VALUE arg)
10933{
10934 struct select_args *p = (struct select_args *)arg;
10935 int i;
10936
10937 for (i = 0; i < numberof(p->fdsets); ++i)
10938 rb_fd_term(&p->fdsets[i]);
10939 return Qnil;
10940}
10941
10942static VALUE sym_normal, sym_sequential, sym_random,
10943 sym_willneed, sym_dontneed, sym_noreuse;
10944
10945#ifdef HAVE_POSIX_FADVISE
10946struct io_advise_struct {
10947 int fd;
10948 int advice;
10949 rb_off_t offset;
10950 rb_off_t len;
10951};
10952
10953static VALUE
10954io_advise_internal(void *arg)
10955{
10956 struct io_advise_struct *ptr = arg;
10957 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10958}
10959
10960static VALUE
10961io_advise_sym_to_const(VALUE sym)
10962{
10963#ifdef POSIX_FADV_NORMAL
10964 if (sym == sym_normal)
10965 return INT2NUM(POSIX_FADV_NORMAL);
10966#endif
10967
10968#ifdef POSIX_FADV_RANDOM
10969 if (sym == sym_random)
10970 return INT2NUM(POSIX_FADV_RANDOM);
10971#endif
10972
10973#ifdef POSIX_FADV_SEQUENTIAL
10974 if (sym == sym_sequential)
10975 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10976#endif
10977
10978#ifdef POSIX_FADV_WILLNEED
10979 if (sym == sym_willneed)
10980 return INT2NUM(POSIX_FADV_WILLNEED);
10981#endif
10982
10983#ifdef POSIX_FADV_DONTNEED
10984 if (sym == sym_dontneed)
10985 return INT2NUM(POSIX_FADV_DONTNEED);
10986#endif
10987
10988#ifdef POSIX_FADV_NOREUSE
10989 if (sym == sym_noreuse)
10990 return INT2NUM(POSIX_FADV_NOREUSE);
10991#endif
10992
10993 return Qnil;
10994}
10995
10996static VALUE
10997do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10998{
10999 int rv;
11000 struct io_advise_struct ias;
11001 VALUE num_adv;
11002
11003 num_adv = io_advise_sym_to_const(advice);
11004
11005 /*
11006 * The platform doesn't support this hint. We don't raise exception, instead
11007 * silently ignore it. Because IO::advise is only hint.
11008 */
11009 if (NIL_P(num_adv))
11010 return Qnil;
11011
11012 ias.fd = fptr->fd;
11013 ias.advice = NUM2INT(num_adv);
11014 ias.offset = offset;
11015 ias.len = len;
11016
11017 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
11018 if (rv && rv != ENOSYS) {
11019 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
11020 it returns the error code. */
11021 VALUE message = rb_sprintf("%"PRIsVALUE" "
11022 "(%"PRI_OFFT_PREFIX"d, "
11023 "%"PRI_OFFT_PREFIX"d, "
11024 "%"PRIsVALUE")",
11025 fptr->pathv, offset, len, advice);
11026 rb_syserr_fail_str(rv, message);
11027 }
11028
11029 return Qnil;
11030}
11031
11032#endif /* HAVE_POSIX_FADVISE */
11033
11034static void
11035advice_arg_check(VALUE advice)
11036{
11037 if (!SYMBOL_P(advice))
11038 rb_raise(rb_eTypeError, "advice must be a Symbol");
11039
11040 if (advice != sym_normal &&
11041 advice != sym_sequential &&
11042 advice != sym_random &&
11043 advice != sym_willneed &&
11044 advice != sym_dontneed &&
11045 advice != sym_noreuse) {
11046 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
11047 }
11048}
11049
11050/*
11051 * call-seq:
11052 * advise(advice, offset = 0, len = 0) -> nil
11053 *
11054 * Invokes Posix system call
11055 * {posix_fadvise(2)}[https://man7.org/linux/man-pages/man2/posix_fadvise.2.html],
11056 * which announces an intention to access data from the current file
11057 * in a particular manner.
11058 *
11059 * The arguments and results are platform-dependent.
11060 *
11061 * The relevant data is specified by:
11062 *
11063 * - +offset+: The offset of the first byte of data.
11064 * - +len+: The number of bytes to be accessed;
11065 * if +len+ is zero, or is larger than the number of bytes remaining,
11066 * all remaining bytes will be accessed.
11067 *
11068 * Argument +advice+ is one of the following symbols:
11069 *
11070 * - +:normal+: The application has no advice to give
11071 * about its access pattern for the specified data.
11072 * If no advice is given for an open file, this is the default assumption.
11073 * - +:sequential+: The application expects to access the specified data sequentially
11074 * (with lower offsets read before higher ones).
11075 * - +:random+: The specified data will be accessed in random order.
11076 * - +:noreuse+: The specified data will be accessed only once.
11077 * - +:willneed+: The specified data will be accessed in the near future.
11078 * - +:dontneed+: The specified data will not be accessed in the near future.
11079 *
11080 * Not implemented on all platforms.
11081 *
11082 */
11083static VALUE
11084rb_io_advise(int argc, VALUE *argv, VALUE io)
11085{
11086 VALUE advice, offset, len;
11087 rb_off_t off, l;
11088 rb_io_t *fptr;
11089
11090 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
11091 advice_arg_check(advice);
11092
11093 io = GetWriteIO(io);
11094 GetOpenFile(io, fptr);
11095
11096 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
11097 l = NIL_P(len) ? 0 : NUM2OFFT(len);
11098
11099#ifdef HAVE_POSIX_FADVISE
11100 return do_io_advise(fptr, advice, off, l);
11101#else
11102 ((void)off, (void)l); /* Ignore all hint */
11103 return Qnil;
11104#endif
11105}
11106
11107static int
11108is_pos_inf(VALUE x)
11109{
11110 double f;
11111 if (!RB_FLOAT_TYPE_P(x))
11112 return 0;
11113 f = RFLOAT_VALUE(x);
11114 return isinf(f) && 0 < f;
11115}
11116
11117/*
11118 * call-seq:
11119 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11120 *
11121 * Invokes system call {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html],
11122 * which monitors multiple file descriptors,
11123 * waiting until one or more of the file descriptors
11124 * becomes ready for some class of I/O operation.
11125 *
11126 * Not implemented on all platforms.
11127 *
11128 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11129 * is an array of IO objects.
11130 *
11131 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11132 * interval in seconds.
11133 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11134 * +nil+ and +Float::INFINITY+ means no timeout.
11135 *
11136 * The method monitors the \IO objects given in all three arrays,
11137 * waiting for some to be ready;
11138 * returns a 3-element array whose elements are:
11139 *
11140 * - An array of the objects in +read_ios+ that are ready for reading.
11141 * - An array of the objects in +write_ios+ that are ready for writing.
11142 * - An array of the objects in +error_ios+ have pending exceptions.
11143 *
11144 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11145 *
11146 * \IO.select peeks the buffer of \IO objects for testing readability.
11147 * If the \IO buffer is not empty, \IO.select immediately notifies
11148 * readability. This "peek" only happens for \IO objects. It does not
11149 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11150 *
11151 * The best way to use \IO.select is invoking it after non-blocking
11152 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11153 * raise an exception which is extended by IO::WaitReadable or
11154 * IO::WaitWritable. The modules notify how the caller should wait
11155 * with \IO.select. If IO::WaitReadable is raised, the caller should
11156 * wait for reading. If IO::WaitWritable is raised, the caller should
11157 * wait for writing.
11158 *
11159 * So, blocking read (#readpartial) can be emulated using
11160 * #read_nonblock and \IO.select as follows:
11161 *
11162 * begin
11163 * result = io_like.read_nonblock(maxlen)
11164 * rescue IO::WaitReadable
11165 * IO.select([io_like])
11166 * retry
11167 * rescue IO::WaitWritable
11168 * IO.select(nil, [io_like])
11169 * retry
11170 * end
11171 *
11172 * Especially, the combination of non-blocking methods and \IO.select is
11173 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11174 * has #to_io method to return underlying IO object. IO.select calls
11175 * #to_io to obtain the file descriptor to wait.
11176 *
11177 * This means that readability notified by \IO.select doesn't mean
11178 * readability from OpenSSL::SSL::SSLSocket object.
11179 *
11180 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11181 * some data. \IO.select doesn't see the buffer. So \IO.select can
11182 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11183 *
11184 * However, several more complicated situations exist.
11185 *
11186 * SSL is a protocol which is sequence of records.
11187 * The record consists of multiple bytes.
11188 * So, the remote side of SSL sends a partial record, IO.select
11189 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11190 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11191 *
11192 * Also, the remote side can request SSL renegotiation which forces
11193 * the local SSL engine to write some data.
11194 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11195 * system call and it can block.
11196 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11197 * IO::WaitWritable instead of blocking.
11198 * So, the caller should wait for ready for writability as above
11199 * example.
11200 *
11201 * The combination of non-blocking methods and \IO.select is also useful
11202 * for streams such as tty, pipe socket socket when multiple processes
11203 * read from a stream.
11204 *
11205 * Finally, Linux kernel developers don't guarantee that
11206 * readability of select(2) means readability of following read(2) even
11207 * for a single process;
11208 * see {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html]
11209 *
11210 * Invoking \IO.select before IO#readpartial works well as usual.
11211 * However it is not the best way to use \IO.select.
11212 *
11213 * The writability notified by select(2) doesn't show
11214 * how many bytes are writable.
11215 * IO#write method blocks until given whole string is written.
11216 * So, <tt>IO#write(two or more bytes)</tt> can block after
11217 * writability is notified by \IO.select. IO#write_nonblock is required
11218 * to avoid the blocking.
11219 *
11220 * Blocking write (#write) can be emulated using #write_nonblock and
11221 * IO.select as follows: IO::WaitReadable should also be rescued for
11222 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11223 *
11224 * while 0 < string.bytesize
11225 * begin
11226 * written = io_like.write_nonblock(string)
11227 * rescue IO::WaitReadable
11228 * IO.select([io_like])
11229 * retry
11230 * rescue IO::WaitWritable
11231 * IO.select(nil, [io_like])
11232 * retry
11233 * end
11234 * string = string.byteslice(written..-1)
11235 * end
11236 *
11237 * Example:
11238 *
11239 * rp, wp = IO.pipe
11240 * mesg = "ping "
11241 * 100.times {
11242 * # IO.select follows IO#read. Not the best way to use IO.select.
11243 * rs, ws, = IO.select([rp], [wp])
11244 * if r = rs[0]
11245 * ret = r.read(5)
11246 * print ret
11247 * case ret
11248 * when /ping/
11249 * mesg = "pong\n"
11250 * when /pong/
11251 * mesg = "ping "
11252 * end
11253 * end
11254 * if w = ws[0]
11255 * w.write(mesg)
11256 * end
11257 * }
11258 *
11259 * Output:
11260 *
11261 * ping pong
11262 * ping pong
11263 * ping pong
11264 * (snipped)
11265 * ping
11266 *
11267 */
11268
11269static VALUE
11270rb_f_select(int argc, VALUE *argv, VALUE obj)
11271{
11272 VALUE scheduler = rb_fiber_scheduler_current();
11273 if (scheduler != Qnil) {
11274 // It's optionally supported.
11275 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11276 if (!UNDEF_P(result)) return result;
11277 }
11278
11279 VALUE timeout;
11280 struct select_args args;
11281 struct timeval timerec;
11282 int i;
11283
11284 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11285 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11286 args.timeout = 0;
11287 }
11288 else {
11289 timerec = rb_time_interval(timeout);
11290 args.timeout = &timerec;
11291 }
11292
11293 for (i = 0; i < numberof(args.fdsets); ++i)
11294 rb_fd_init(&args.fdsets[i]);
11295
11296 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11297}
11298
11299#ifdef IOCTL_REQ_TYPE
11300 typedef IOCTL_REQ_TYPE ioctl_req_t;
11301#else
11302 typedef int ioctl_req_t;
11303# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11304#endif
11305
11306#ifdef HAVE_IOCTL
11307struct ioctl_arg {
11308 int fd;
11309 ioctl_req_t cmd;
11310 long narg;
11311};
11312
11313static VALUE
11314nogvl_ioctl(void *ptr)
11315{
11316 struct ioctl_arg *arg = ptr;
11317
11318 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11319}
11320
11321static int
11322do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11323{
11324 int retval;
11325 struct ioctl_arg arg;
11326
11327 arg.fd = io->fd;
11328 arg.cmd = cmd;
11329 arg.narg = narg;
11330
11331 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11332
11333 return retval;
11334}
11335#endif
11336
11337#define DEFAULT_IOCTL_NARG_LEN (256)
11338
11339#if defined(__linux__) && defined(_IOC_SIZE)
11340static long
11341linux_iocparm_len(ioctl_req_t cmd)
11342{
11343 long len;
11344
11345 if ((cmd & 0xFFFF0000) == 0) {
11346 /* legacy and unstructured ioctl number. */
11347 return DEFAULT_IOCTL_NARG_LEN;
11348 }
11349
11350 len = _IOC_SIZE(cmd);
11351
11352 /* paranoia check for silly drivers which don't keep ioctl convention */
11353 if (len < DEFAULT_IOCTL_NARG_LEN)
11354 len = DEFAULT_IOCTL_NARG_LEN;
11355
11356 return len;
11357}
11358#endif
11359
11360#ifdef HAVE_IOCTL
11361static long
11362ioctl_narg_len(ioctl_req_t cmd)
11363{
11364 long len;
11365
11366#ifdef IOCPARM_MASK
11367#ifndef IOCPARM_LEN
11368#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11369#endif
11370#endif
11371#ifdef IOCPARM_LEN
11372 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11373#elif defined(__linux__) && defined(_IOC_SIZE)
11374 len = linux_iocparm_len(cmd);
11375#else
11376 /* otherwise guess at what's safe */
11377 len = DEFAULT_IOCTL_NARG_LEN;
11378#endif
11379
11380 return len;
11381}
11382#endif
11383
11384#ifdef HAVE_FCNTL
11385#ifdef __linux__
11386typedef long fcntl_arg_t;
11387#else
11388/* posix */
11389typedef int fcntl_arg_t;
11390#endif
11391
11392static long
11393fcntl_narg_len(ioctl_req_t cmd)
11394{
11395 long len;
11396
11397 switch (cmd) {
11398#ifdef F_DUPFD
11399 case F_DUPFD:
11400 len = sizeof(fcntl_arg_t);
11401 break;
11402#endif
11403#ifdef F_DUP2FD /* bsd specific */
11404 case F_DUP2FD:
11405 len = sizeof(int);
11406 break;
11407#endif
11408#ifdef F_DUPFD_CLOEXEC /* linux specific */
11409 case F_DUPFD_CLOEXEC:
11410 len = sizeof(fcntl_arg_t);
11411 break;
11412#endif
11413#ifdef F_GETFD
11414 case F_GETFD:
11415 len = 1;
11416 break;
11417#endif
11418#ifdef F_SETFD
11419 case F_SETFD:
11420 len = sizeof(fcntl_arg_t);
11421 break;
11422#endif
11423#ifdef F_GETFL
11424 case F_GETFL:
11425 len = 1;
11426 break;
11427#endif
11428#ifdef F_SETFL
11429 case F_SETFL:
11430 len = sizeof(fcntl_arg_t);
11431 break;
11432#endif
11433#ifdef F_GETOWN
11434 case F_GETOWN:
11435 len = 1;
11436 break;
11437#endif
11438#ifdef F_SETOWN
11439 case F_SETOWN:
11440 len = sizeof(fcntl_arg_t);
11441 break;
11442#endif
11443#ifdef F_GETOWN_EX /* linux specific */
11444 case F_GETOWN_EX:
11445 len = sizeof(struct f_owner_ex);
11446 break;
11447#endif
11448#ifdef F_SETOWN_EX /* linux specific */
11449 case F_SETOWN_EX:
11450 len = sizeof(struct f_owner_ex);
11451 break;
11452#endif
11453#ifdef F_GETLK
11454 case F_GETLK:
11455 len = sizeof(struct flock);
11456 break;
11457#endif
11458#ifdef F_SETLK
11459 case F_SETLK:
11460 len = sizeof(struct flock);
11461 break;
11462#endif
11463#ifdef F_SETLKW
11464 case F_SETLKW:
11465 len = sizeof(struct flock);
11466 break;
11467#endif
11468#ifdef F_READAHEAD /* bsd specific */
11469 case F_READAHEAD:
11470 len = sizeof(int);
11471 break;
11472#endif
11473#ifdef F_RDAHEAD /* Darwin specific */
11474 case F_RDAHEAD:
11475 len = sizeof(int);
11476 break;
11477#endif
11478#ifdef F_GETSIG /* linux specific */
11479 case F_GETSIG:
11480 len = 1;
11481 break;
11482#endif
11483#ifdef F_SETSIG /* linux specific */
11484 case F_SETSIG:
11485 len = sizeof(fcntl_arg_t);
11486 break;
11487#endif
11488#ifdef F_GETLEASE /* linux specific */
11489 case F_GETLEASE:
11490 len = 1;
11491 break;
11492#endif
11493#ifdef F_SETLEASE /* linux specific */
11494 case F_SETLEASE:
11495 len = sizeof(fcntl_arg_t);
11496 break;
11497#endif
11498#ifdef F_NOTIFY /* linux specific */
11499 case F_NOTIFY:
11500 len = sizeof(fcntl_arg_t);
11501 break;
11502#endif
11503
11504 default:
11505 len = 256;
11506 break;
11507 }
11508
11509 return len;
11510}
11511#else /* HAVE_FCNTL */
11512static long
11513fcntl_narg_len(ioctl_req_t cmd)
11514{
11515 return 0;
11516}
11517#endif /* HAVE_FCNTL */
11518
11519#define NARG_SENTINEL 17
11520
11521static long
11522setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11523{
11524 long narg = 0;
11525 VALUE arg = *argp;
11526
11527 if (!RTEST(arg)) {
11528 narg = 0;
11529 }
11530 else if (FIXNUM_P(arg)) {
11531 narg = FIX2LONG(arg);
11532 }
11533 else if (arg == Qtrue) {
11534 narg = 1;
11535 }
11536 else {
11537 VALUE tmp = rb_check_string_type(arg);
11538
11539 if (NIL_P(tmp)) {
11540 narg = NUM2LONG(arg);
11541 }
11542 else {
11543 char *ptr;
11544 long len, slen;
11545
11546 *argp = arg = tmp;
11547 len = narg_len(cmd);
11548 rb_str_modify(arg);
11549
11550 slen = RSTRING_LEN(arg);
11551 /* expand for data + sentinel. */
11552 if (slen < len+1) {
11553 rb_str_resize(arg, len+1);
11554 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11555 slen = len+1;
11556 }
11557 /* a little sanity check here */
11558 ptr = RSTRING_PTR(arg);
11559 ptr[slen - 1] = NARG_SENTINEL;
11560 narg = (long)(SIGNED_VALUE)ptr;
11561 }
11562 }
11563
11564 return narg;
11565}
11566
11567static VALUE
11568finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11569{
11570 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11571 if (RB_TYPE_P(arg, T_STRING)) {
11572 char *ptr;
11573 long slen;
11574 RSTRING_GETMEM(arg, ptr, slen);
11575 if (ptr[slen-1] != NARG_SENTINEL)
11576 rb_raise(rb_eArgError, "return value overflowed string");
11577 ptr[slen-1] = '\0';
11578 }
11579
11580 return INT2NUM(retval);
11581}
11582
11583#ifdef HAVE_IOCTL
11584static VALUE
11585rb_ioctl(VALUE io, VALUE req, VALUE arg)
11586{
11587 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11588 rb_io_t *fptr;
11589 long narg;
11590 int retval;
11591
11592 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11593 GetOpenFile(io, fptr);
11594 retval = do_ioctl(fptr, cmd, narg);
11595 return finish_narg(retval, arg, fptr);
11596}
11597
11598/*
11599 * call-seq:
11600 * ioctl(integer_cmd, argument) -> integer
11601 *
11602 * Invokes Posix system call {ioctl(2)}[https://man7.org/linux/man-pages/man2/ioctl.2.html],
11603 * which issues a low-level command to an I/O device.
11604 *
11605 * Issues a low-level command to an I/O device.
11606 * The arguments and returned value are platform-dependent.
11607 * The effect of the call is platform-dependent.
11608 *
11609 * If argument +argument+ is an integer, it is passed directly;
11610 * if it is a string, it is interpreted as a binary sequence of bytes.
11611 *
11612 * Not implemented on all platforms.
11613 *
11614 */
11615
11616static VALUE
11617rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11618{
11619 VALUE req, arg;
11620
11621 rb_scan_args(argc, argv, "11", &req, &arg);
11622 return rb_ioctl(io, req, arg);
11623}
11624#else
11625#define rb_io_ioctl rb_f_notimplement
11626#endif
11627
11628#ifdef HAVE_FCNTL
11629struct fcntl_arg {
11630 int fd;
11631 int cmd;
11632 long narg;
11633};
11634
11635static VALUE
11636nogvl_fcntl(void *ptr)
11637{
11638 struct fcntl_arg *arg = ptr;
11639
11640#if defined(F_DUPFD)
11641 if (arg->cmd == F_DUPFD)
11642 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11643#endif
11644 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11645}
11646
11647static int
11648do_fcntl(struct rb_io *io, int cmd, long narg)
11649{
11650 int retval;
11651 struct fcntl_arg arg;
11652
11653 arg.fd = io->fd;
11654 arg.cmd = cmd;
11655 arg.narg = narg;
11656
11657 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11658 if (retval != -1) {
11659 switch (cmd) {
11660#if defined(F_DUPFD)
11661 case F_DUPFD:
11662#endif
11663#if defined(F_DUPFD_CLOEXEC)
11664 case F_DUPFD_CLOEXEC:
11665#endif
11666 rb_update_max_fd(retval);
11667 }
11668 }
11669
11670 return retval;
11671}
11672
11673static VALUE
11674rb_fcntl(VALUE io, VALUE req, VALUE arg)
11675{
11676 int cmd = NUM2INT(req);
11677 rb_io_t *fptr;
11678 long narg;
11679 int retval;
11680
11681 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11682 GetOpenFile(io, fptr);
11683 retval = do_fcntl(fptr, cmd, narg);
11684 return finish_narg(retval, arg, fptr);
11685}
11686
11687/*
11688 * call-seq:
11689 * fcntl(integer_cmd, argument) -> integer
11690 *
11691 * Invokes Posix system call {fcntl(2)}[https://man7.org/linux/man-pages/man2/fcntl.2.html],
11692 * which provides a mechanism for issuing low-level commands to control or query
11693 * a file-oriented I/O stream. Arguments and results are platform
11694 * dependent.
11695 *
11696 * If +argument+ is a number, its value is passed directly;
11697 * if it is a string, it is interpreted as a binary sequence of bytes.
11698 * (Array#pack might be a useful way to build this string.)
11699 *
11700 * Not implemented on all platforms.
11701 *
11702 */
11703
11704static VALUE
11705rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11706{
11707 VALUE req, arg;
11708
11709 rb_scan_args(argc, argv, "11", &req, &arg);
11710 return rb_fcntl(io, req, arg);
11711}
11712#else
11713#define rb_io_fcntl rb_f_notimplement
11714#endif
11715
11716#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11717/*
11718 * call-seq:
11719 * syscall(integer_callno, *arguments) -> integer
11720 *
11721 * Invokes Posix system call {syscall(2)}[https://man7.org/linux/man-pages/man2/syscall.2.html],
11722 * which calls a specified function.
11723 *
11724 * Calls the operating system function identified by +integer_callno+;
11725 * returns the result of the function or raises SystemCallError if it failed.
11726 * The effect of the call is platform-dependent.
11727 * The arguments and returned value are platform-dependent.
11728 *
11729 * For each of +arguments+: if it is an integer, it is passed directly;
11730 * if it is a string, it is interpreted as a binary sequence of bytes.
11731 * There may be as many as nine such arguments.
11732 *
11733 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11734 * are platform-dependent.
11735 *
11736 * Note: Method +syscall+ is essentially unsafe and unportable.
11737 * The DL (Fiddle) library is preferred for safer and a bit
11738 * more portable programming.
11739 *
11740 * Not implemented on all platforms.
11741 *
11742 */
11743
11744static VALUE
11745rb_f_syscall(int argc, VALUE *argv, VALUE _)
11746{
11747 VALUE arg[8];
11748#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11749# define SYSCALL __syscall
11750# define NUM2SYSCALLID(x) NUM2LONG(x)
11751# define RETVAL2NUM(x) LONG2NUM(x)
11752# if SIZEOF_LONG == 8
11753 long num, retval = -1;
11754# elif SIZEOF_LONG_LONG == 8
11755 long long num, retval = -1;
11756# else
11757# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11758# endif
11759#elif defined(__linux__)
11760# define SYSCALL syscall
11761# define NUM2SYSCALLID(x) NUM2LONG(x)
11762# define RETVAL2NUM(x) LONG2NUM(x)
11763 /*
11764 * Linux man page says, syscall(2) function prototype is below.
11765 *
11766 * int syscall(int number, ...);
11767 *
11768 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11769 */
11770 long num, retval = -1;
11771#else
11772# define SYSCALL syscall
11773# define NUM2SYSCALLID(x) NUM2INT(x)
11774# define RETVAL2NUM(x) INT2NUM(x)
11775 int num, retval = -1;
11776#endif
11777 int i;
11778
11779 if (RTEST(ruby_verbose)) {
11781 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11782 }
11783
11784 if (argc == 0)
11785 rb_raise(rb_eArgError, "too few arguments for syscall");
11786 if (argc > numberof(arg))
11787 rb_raise(rb_eArgError, "too many arguments for syscall");
11788 num = NUM2SYSCALLID(argv[0]); ++argv;
11789 for (i = argc - 1; i--; ) {
11790 VALUE v = rb_check_string_type(argv[i]);
11791
11792 if (!NIL_P(v)) {
11793 StringValue(v);
11794 rb_str_modify(v);
11795 arg[i] = (VALUE)StringValueCStr(v);
11796 }
11797 else {
11798 arg[i] = (VALUE)NUM2LONG(argv[i]);
11799 }
11800 }
11801
11802 switch (argc) {
11803 case 1:
11804 retval = SYSCALL(num);
11805 break;
11806 case 2:
11807 retval = SYSCALL(num, arg[0]);
11808 break;
11809 case 3:
11810 retval = SYSCALL(num, arg[0],arg[1]);
11811 break;
11812 case 4:
11813 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11814 break;
11815 case 5:
11816 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11817 break;
11818 case 6:
11819 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11820 break;
11821 case 7:
11822 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11823 break;
11824 case 8:
11825 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11826 break;
11827 }
11828
11829 if (retval == -1)
11830 rb_sys_fail(0);
11831 return RETVAL2NUM(retval);
11832#undef SYSCALL
11833#undef NUM2SYSCALLID
11834#undef RETVAL2NUM
11835}
11836#else
11837#define rb_f_syscall rb_f_notimplement
11838#endif
11839
11840static VALUE
11841io_new_instance(VALUE args)
11842{
11843 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11844}
11845
11846static rb_encoding *
11847find_encoding(VALUE v)
11848{
11849 rb_encoding *enc = rb_find_encoding(v);
11850 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11851 return enc;
11852}
11853
11854static void
11855io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11856{
11857 rb_encoding *enc, *enc2;
11858 int ecflags = fptr->encs.ecflags;
11859 VALUE ecopts, tmp;
11860
11861 if (!NIL_P(v2)) {
11862 enc2 = find_encoding(v1);
11863 tmp = rb_check_string_type(v2);
11864 if (!NIL_P(tmp)) {
11865 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11866 /* Special case - "-" => no transcoding */
11867 enc = enc2;
11868 enc2 = NULL;
11869 }
11870 else
11871 enc = find_encoding(v2);
11872 if (enc == enc2) {
11873 /* Special case - "-" => no transcoding */
11874 enc2 = NULL;
11875 }
11876 }
11877 else {
11878 enc = find_encoding(v2);
11879 if (enc == enc2) {
11880 /* Special case - "-" => no transcoding */
11881 enc2 = NULL;
11882 }
11883 }
11884 if (enc2 == rb_ascii8bit_encoding()) {
11885 /* If external is ASCII-8BIT, no transcoding */
11886 enc = enc2;
11887 enc2 = NULL;
11888 }
11889 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11890 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11891 }
11892 else {
11893 if (NIL_P(v1)) {
11894 /* Set to default encodings */
11895 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11896 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11897 ecopts = Qnil;
11898 }
11899 else {
11900 tmp = rb_check_string_type(v1);
11901 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11902 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11903 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11904 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11905 }
11906 else {
11907 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11908 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11909 ecopts = Qnil;
11910 }
11911 }
11912 }
11913 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11914 fptr->encs.enc = enc;
11915 fptr->encs.enc2 = enc2;
11916 fptr->encs.ecflags = ecflags;
11917 fptr->encs.ecopts = ecopts;
11918 clear_codeconv(fptr);
11919
11920}
11921
11923 rb_io_t *fptr;
11924 VALUE v1;
11925 VALUE v2;
11926 VALUE opt;
11927};
11928
11929static VALUE
11930io_encoding_set_v(VALUE v)
11931{
11932 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11933 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11934 return Qnil;
11935}
11936
11937static VALUE
11938pipe_pair_close(VALUE rw)
11939{
11940 VALUE *rwp = (VALUE *)rw;
11941 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11942}
11943
11944/*
11945 * call-seq:
11946 * IO.pipe(**opts) -> [read_io, write_io]
11947 * IO.pipe(enc, **opts) -> [read_io, write_io]
11948 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11949 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11950 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11951 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11952 *
11953 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11954 * connected to each other.
11955 *
11956 * If argument +enc_string+ is given, it must be a string containing one of:
11957 *
11958 * - The name of the encoding to be used as the external encoding.
11959 * - The colon-separated names of two encodings to be used as the external
11960 * and internal encodings.
11961 *
11962 * If argument +int_enc+ is given, it must be an Encoding object
11963 * or encoding name string that specifies the internal encoding to be used;
11964 * if argument +ext_enc+ is also given, it must be an Encoding object
11965 * or encoding name string that specifies the external encoding to be used.
11966 *
11967 * The string read from +read_io+ is tagged with the external encoding;
11968 * if an internal encoding is also specified, the string is converted
11969 * to, and tagged with, that encoding.
11970 *
11971 * If any encoding is specified,
11972 * optional hash arguments specify the conversion option.
11973 *
11974 * Optional keyword arguments +opts+ specify:
11975 *
11976 * - {Open Options}[rdoc-ref:IO@Open+Options].
11977 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11978 *
11979 * With no block given, returns the two endpoints in an array:
11980 *
11981 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11982 *
11983 * With a block given, calls the block with the two endpoints;
11984 * closes both endpoints and returns the value of the block:
11985 *
11986 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11987 *
11988 * Output:
11989 *
11990 * #<IO:fd 6>
11991 * #<IO:fd 7>
11992 *
11993 * Not available on all platforms.
11994 *
11995 * In the example below, the two processes close the ends of the pipe
11996 * that they are not using. This is not just a cosmetic nicety. The
11997 * read end of a pipe will not generate an end of file condition if
11998 * there are any writers with the pipe still open. In the case of the
11999 * parent process, the <tt>rd.read</tt> will never return if it
12000 * does not first issue a <tt>wr.close</tt>:
12001 *
12002 * rd, wr = IO.pipe
12003 *
12004 * if fork
12005 * wr.close
12006 * puts "Parent got: <#{rd.read}>"
12007 * rd.close
12008 * Process.wait
12009 * else
12010 * rd.close
12011 * puts 'Sending message to parent'
12012 * wr.write "Hi Dad"
12013 * wr.close
12014 * end
12015 *
12016 * <em>produces:</em>
12017 *
12018 * Sending message to parent
12019 * Parent got: <Hi Dad>
12020 *
12021 */
12022
12023static VALUE
12024rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
12025{
12026 int pipes[2], state;
12027 VALUE r, w, args[3], v1, v2;
12028 VALUE opt;
12029 rb_io_t *fptr, *fptr2;
12030 struct io_encoding_set_args ies_args;
12031 enum rb_io_mode fmode = 0;
12032 VALUE ret;
12033
12034 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
12035 if (rb_pipe(pipes) < 0)
12036 rb_sys_fail(0);
12037
12038 args[0] = klass;
12039 args[1] = INT2NUM(pipes[0]);
12040 args[2] = INT2FIX(O_RDONLY);
12041 r = rb_protect(io_new_instance, (VALUE)args, &state);
12042 if (state) {
12043 close(pipes[0]);
12044 close(pipes[1]);
12045 rb_jump_tag(state);
12046 }
12047 GetOpenFile(r, fptr);
12048
12049 ies_args.fptr = fptr;
12050 ies_args.v1 = v1;
12051 ies_args.v2 = v2;
12052 ies_args.opt = opt;
12053 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
12054 if (state) {
12055 close(pipes[1]);
12056 io_close(r);
12057 rb_jump_tag(state);
12058 }
12059
12060 args[1] = INT2NUM(pipes[1]);
12061 args[2] = INT2FIX(O_WRONLY);
12062 w = rb_protect(io_new_instance, (VALUE)args, &state);
12063 if (state) {
12064 close(pipes[1]);
12065 if (!NIL_P(r)) rb_io_close(r);
12066 rb_jump_tag(state);
12067 }
12068 GetOpenFile(w, fptr2);
12069 rb_io_synchronized(fptr2);
12070
12071 extract_binmode(opt, &fmode);
12072
12073 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
12076 }
12077
12078#if DEFAULT_TEXTMODE
12079 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12080 fptr->mode &= ~FMODE_TEXTMODE;
12081 setmode(fptr->fd, O_BINARY);
12082 }
12083#if RUBY_CRLF_ENVIRONMENT
12086 }
12087#endif
12088#endif
12089 fptr->mode |= fmode;
12090#if DEFAULT_TEXTMODE
12091 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12092 fptr2->mode &= ~FMODE_TEXTMODE;
12093 setmode(fptr2->fd, O_BINARY);
12094 }
12095#endif
12096 fptr2->mode |= fmode;
12097
12098 ret = rb_assoc_new(r, w);
12099 if (rb_block_given_p()) {
12100 VALUE rw[2];
12101 rw[0] = r;
12102 rw[1] = w;
12103 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12104 }
12105 return ret;
12106}
12107
12109 int argc;
12110 VALUE *argv;
12111 VALUE io;
12112};
12113
12114static void
12115open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12116{
12117 VALUE path, v;
12118 VALUE vmode = Qnil, vperm = Qnil;
12119
12120 path = *argv++;
12121 argc--;
12122 FilePathValue(path);
12123 arg->io = 0;
12124 arg->argc = argc;
12125 arg->argv = argv;
12126 if (NIL_P(opt)) {
12127 vmode = INT2NUM(O_RDONLY);
12128 vperm = INT2FIX(0666);
12129 }
12130 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12131 int n;
12132
12133 v = rb_to_array_type(v);
12134 n = RARRAY_LENINT(v);
12135 rb_check_arity(n, 0, 3); /* rb_io_open */
12136 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12137 }
12138 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12139}
12140
12141static VALUE
12142io_s_foreach(VALUE v)
12143{
12144 struct getline_arg *arg = (void *)v;
12145 VALUE str;
12146
12147 if (arg->limit == 0)
12148 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12149 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12150 rb_lastline_set(str);
12151 rb_yield(str);
12152 }
12154 return Qnil;
12155}
12156
12157/*
12158 * call-seq:
12159 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12160 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12161 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12162 * IO.foreach(...) -> an_enumerator
12163 *
12164 * Calls the block with each successive line read from the stream.
12165 *
12166 * The first argument must be a string that is the path to a file.
12167 *
12168 * With only argument +path+ given, parses lines from the file at the given +path+,
12169 * as determined by the default line separator,
12170 * and calls the block with each successive line:
12171 *
12172 * File.foreach('t.txt') {|line| p line }
12173 *
12174 * Output: the same as above.
12175 *
12176 * For both forms, command and path, the remaining arguments are the same.
12177 *
12178 * With argument +sep+ given, parses lines as determined by that line separator
12179 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12180 *
12181 * File.foreach('t.txt', 'li') {|line| p line }
12182 *
12183 * Output:
12184 *
12185 * "First li"
12186 * "ne\nSecond li"
12187 * "ne\n\nThird li"
12188 * "ne\nFourth li"
12189 * "ne\n"
12190 *
12191 * Each paragraph:
12192 *
12193 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12194 *
12195 * Output:
12196 *
12197 * "First line\nSecond line\n\n"
12198 * "Third line\nFourth line\n"
12199 *
12200 * With argument +limit+ given, parses lines as determined by the default
12201 * line separator and the given line-length limit
12202 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12203 *
12204 * File.foreach('t.txt', 7) {|line| p line }
12205 *
12206 * Output:
12207 *
12208 * "First l"
12209 * "ine\n"
12210 * "Second "
12211 * "line\n"
12212 * "\n"
12213 * "Third l"
12214 * "ine\n"
12215 * "Fourth l"
12216 * "line\n"
12217 *
12218 * With arguments +sep+ and +limit+ given,
12219 * combines the two behaviors
12220 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12221 *
12222 * Optional keyword arguments +opts+ specify:
12223 *
12224 * - {Open Options}[rdoc-ref:IO@Open+Options].
12225 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12226 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12227 *
12228 * Returns an Enumerator if no block is given.
12229 *
12230 */
12231
12232static VALUE
12233rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12234{
12235 VALUE opt;
12236 int orig_argc = argc;
12237 struct foreach_arg arg;
12238 struct getline_arg garg;
12239
12240 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12241 RETURN_ENUMERATOR(self, orig_argc, argv);
12242 extract_getline_args(argc-1, argv+1, &garg);
12243 open_key_args(self, argc, argv, opt, &arg);
12244 if (NIL_P(arg.io)) return Qnil;
12245 extract_getline_opts(opt, &garg);
12246 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12247 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12248}
12249
12250static VALUE
12251io_s_readlines(VALUE v)
12252{
12253 struct getline_arg *arg = (void *)v;
12254 return io_readlines(arg, arg->io);
12255}
12256
12257/*
12258 * call-seq:
12259 * IO.readlines(path, sep = $/, **opts) -> array
12260 * IO.readlines(path, limit, **opts) -> array
12261 * IO.readlines(path, sep, limit, **opts) -> array
12262 *
12263 * Returns an array of all lines read from the stream.
12264 *
12265 * The first argument must be a string that is the path to a file.
12266 *
12267 * With only argument +path+ given, parses lines from the file at the given +path+,
12268 * as determined by the default line separator,
12269 * and returns those lines in an array:
12270 *
12271 * IO.readlines('t.txt')
12272 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12273 *
12274 * With argument +sep+ given, parses lines as determined by that line separator
12275 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12276 *
12277 * # Ordinary separator.
12278 * IO.readlines('t.txt', 'li')
12279 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12280 * # Get-paragraphs separator.
12281 * IO.readlines('t.txt', '')
12282 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12283 * # Get-all separator.
12284 * IO.readlines('t.txt', nil)
12285 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12286 *
12287 * With argument +limit+ given, parses lines as determined by the default
12288 * line separator and the given line-length limit
12289 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12290 *
12291 * IO.readlines('t.txt', 7)
12292 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12293 *
12294 * With arguments +sep+ and +limit+ given,
12295 * combines the two behaviors
12296 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12297 *
12298 * Optional keyword arguments +opts+ specify:
12299 *
12300 * - {Open Options}[rdoc-ref:IO@Open+Options].
12301 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12302 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12303 *
12304 */
12305
12306static VALUE
12307rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12308{
12309 VALUE opt;
12310 struct foreach_arg arg;
12311 struct getline_arg garg;
12312
12313 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12314 extract_getline_args(argc-1, argv+1, &garg);
12315 open_key_args(io, argc, argv, opt, &arg);
12316 if (NIL_P(arg.io)) return Qnil;
12317 extract_getline_opts(opt, &garg);
12318 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12319 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12320}
12321
12322static VALUE
12323io_s_read(VALUE v)
12324{
12325 struct foreach_arg *arg = (void *)v;
12326 return io_read(arg->argc, arg->argv, arg->io);
12327}
12328
12329struct seek_arg {
12330 VALUE io;
12331 VALUE offset;
12332 int mode;
12333};
12334
12335static VALUE
12336seek_before_access(VALUE argp)
12337{
12338 struct seek_arg *arg = (struct seek_arg *)argp;
12339 rb_io_binmode(arg->io);
12340 return rb_io_seek(arg->io, arg->offset, arg->mode);
12341}
12342
12343/*
12344 * call-seq:
12345 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12346 *
12347 * Opens the stream, reads and returns some or all of its content,
12348 * and closes the stream; returns +nil+ if no bytes were read.
12349 *
12350 * The first argument must be a string that is the path to a file.
12351 *
12352 * With only argument +path+ given, reads in text mode and returns the entire content
12353 * of the file at the given path:
12354 *
12355 * File.read('t.txt')
12356 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
12357 * File.read('t.ja')
12358 * # => "こんにちは"
12359 * File.read('t.dat')
12360 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12361 *
12362 * On Windows, text mode can terminate reading and leave bytes in the file
12363 * unread when encountering certain special bytes. Consider using
12364 * IO.binread if all bytes in the file should be read.
12365 *
12366 * With argument +length+, returns +length+ bytes if available:
12367 *
12368 * File.read('t.txt', 7)
12369 * # => "First l"
12370 * File.read('t.ja', 7)
12371 * # => "\xE3\x81\x93\xE3\x82\x93\xE3"
12372 * File.read('t.dat', 7)
12373 * # => "\xFE\xFF\x99\x90\x99\x91\x99"
12374 *
12375 * Returns all bytes if +length+ is larger than the files size:
12376 *
12377 * File.read('t.txt', 700)
12378 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12379 * File.read('t.ja', 700)
12380 * # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
12381 * File.read('t.dat', 700)
12382 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12383 *
12384 * With arguments +length+ and +offset+, returns +length+ bytes
12385 * if available, beginning at the given +offset+:
12386 *
12387 * File.read('t.txt', 10, 2)
12388 * # => "rst line\r\n"
12389 * File.read('t.ja', 10, 2)
12390 * # => "\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1"
12391 * File.read('t.dat', 10, 2)
12392 * # => "\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12393 *
12394 * Returns +nil+ if +offset+ is past the end of the stream:
12395 *
12396 * File.read('t.txt', 10, 200)
12397 * # => nil
12398 *
12399 * Optional keyword arguments +opts+ specify:
12400 *
12401 * - {Open Options}[rdoc-ref:IO@Open+Options].
12402 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12403 *
12404 */
12405
12406static VALUE
12407rb_io_s_read(int argc, VALUE *argv, VALUE io)
12408{
12409 VALUE opt, offset;
12410 long off;
12411 struct foreach_arg arg;
12412
12413 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12414 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12415 rb_raise(rb_eArgError, "negative offset %ld given", off);
12416 }
12417 open_key_args(io, argc, argv, opt, &arg);
12418 if (NIL_P(arg.io)) return Qnil;
12419 if (!NIL_P(offset)) {
12420 struct seek_arg sarg;
12421 int state = 0;
12422 sarg.io = arg.io;
12423 sarg.offset = offset;
12424 sarg.mode = SEEK_SET;
12425 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12426 if (state) {
12427 rb_io_close(arg.io);
12428 rb_jump_tag(state);
12429 }
12430 if (arg.argc == 2) arg.argc = 1;
12431 }
12432 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12433}
12434
12435/*
12436 * call-seq:
12437 * IO.binread(path, length = nil, offset = 0) -> string or nil
12438 *
12439 * Behaves like IO.read, except that the stream is opened in binary mode
12440 * with ASCII-8BIT encoding.
12441 *
12442 */
12443
12444static VALUE
12445rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12446{
12447 VALUE offset;
12448 struct foreach_arg arg;
12449 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12450 enum {
12451 oflags = O_RDONLY
12452#ifdef O_BINARY
12453 |O_BINARY
12454#endif
12455 };
12456 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12457
12458 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12459 FilePathValue(argv[0]);
12460 convconfig.enc = rb_ascii8bit_encoding();
12461 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12462 if (NIL_P(arg.io)) return Qnil;
12463 arg.argv = argv+1;
12464 arg.argc = (argc > 1) ? 1 : 0;
12465 if (!NIL_P(offset)) {
12466 struct seek_arg sarg;
12467 int state = 0;
12468 sarg.io = arg.io;
12469 sarg.offset = offset;
12470 sarg.mode = SEEK_SET;
12471 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12472 if (state) {
12473 rb_io_close(arg.io);
12474 rb_jump_tag(state);
12475 }
12476 }
12477 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12478}
12479
12480static VALUE
12481io_s_write0(VALUE v)
12482{
12483 struct write_arg *arg = (void *)v;
12484 return io_write(arg->io,arg->str,arg->nosync);
12485}
12486
12487static VALUE
12488io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12489{
12490 VALUE string, offset, opt;
12491 struct foreach_arg arg;
12492 struct write_arg warg;
12493
12494 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12495
12496 if (NIL_P(opt)) opt = rb_hash_new();
12497 else opt = rb_hash_dup(opt);
12498
12499
12500 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12501 int mode = O_WRONLY|O_CREAT;
12502#ifdef O_BINARY
12503 if (binary) mode |= O_BINARY;
12504#endif
12505 if (NIL_P(offset)) mode |= O_TRUNC;
12506 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12507 }
12508 open_key_args(klass, argc, argv, opt, &arg);
12509
12510#ifndef O_BINARY
12511 if (binary) rb_io_binmode_m(arg.io);
12512#endif
12513
12514 if (NIL_P(arg.io)) return Qnil;
12515 if (!NIL_P(offset)) {
12516 struct seek_arg sarg;
12517 int state = 0;
12518 sarg.io = arg.io;
12519 sarg.offset = offset;
12520 sarg.mode = SEEK_SET;
12521 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12522 if (state) {
12523 rb_io_close(arg.io);
12524 rb_jump_tag(state);
12525 }
12526 }
12527
12528 warg.io = arg.io;
12529 warg.str = string;
12530 warg.nosync = 0;
12531
12532 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12533}
12534
12535/*
12536 * call-seq:
12537 * IO.write(path, data, offset = 0, **opts) -> nonnegative_integer
12538 *
12539 * Opens the stream, writes the given +data+ to it,
12540 * and closes the stream; returns the number of bytes written.
12541 *
12542 * The first argument must be a string that is the path to a file.
12543 *
12544 * With only arguments +path+ and +data+ given,
12545 * writes the given data to the file at that path:
12546 *
12547 * path = 't.tmp'
12548 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n") # => 47
12549 * File.write(path, 'こんにちは') # => 15
12550 * File.write(path, "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94") # => 12
12551 *
12552 * When +offset+ is zero (the default), the entire file content is overwritten:
12553 *
12554 * File.read(path) # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12555 * File.write(path, 'foo')
12556 * File.read(path) # => "foo"
12557 *
12558 * When +offset+ in within the file content, the file content is partly overwritten,
12559 * beginning at byte +offset+:
12560 *
12561 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12562 * File.write(path, 'LINE', 6)
12563 * File.read(path) # => "First LINE\nSecond line\n\nFourth line\nFifth line\n"
12564 *
12565 * When the file contains multi-byte characters,
12566 * the effect of writing may disturb some characters:
12567 *
12568 * File.write(path, "こんにちは")
12569 * File.write(path, 'FOO', 3) # Replace one 3-byte character.
12570 * File.read(path) # => "こFOOにちは"
12571 * File.write(path, 'BAR', 7) # Replace bytes in two different 3-byte characters.
12572 * File.read(path) # => "こFOO\xE3BAR\x81\xA1は"
12573 *
12574 * If +offset+ is outside the file content,
12575 * the file is padded with null characters <tt>"\u0000"</tt>:
12576 *
12577 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12578 * File.write(path, 'FOO', 55)
12579 * File.read(path)
12580 * # => "First line\nSecond line\n\nFourth line\nFifth line\n\u0000\u0000\u0000FOO"
12581 *
12582 * Optional keyword arguments +opts+ specify:
12583 *
12584 * - {Open Options}[rdoc-ref:IO@Open+Options].
12585 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12586 *
12587 */
12588
12589static VALUE
12590rb_io_s_write(int argc, VALUE *argv, VALUE io)
12591{
12592 return io_s_write(argc, argv, io, 0);
12593}
12594
12595/*
12596 * call-seq:
12597 * IO.binwrite(path, string, offset = 0, **opts) -> integer
12598 *
12599 * Behaves like IO.write, except that the stream is opened in binary mode
12600 * with ASCII-8BIT encoding.
12601 *
12602 */
12603
12604static VALUE
12605rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12606{
12607 return io_s_write(argc, argv, io, 1);
12608}
12609
12611 VALUE src;
12612 VALUE dst;
12613 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12614 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12615
12616 rb_io_t *src_fptr;
12617 rb_io_t *dst_fptr;
12618 unsigned close_src : 1;
12619 unsigned close_dst : 1;
12620 int error_no;
12621 rb_off_t total;
12622 const char *syserr;
12623 const char *notimp;
12624 VALUE th;
12625 struct stat src_stat;
12626 struct stat dst_stat;
12627#ifdef HAVE_FCOPYFILE
12628 copyfile_state_t copyfile_state;
12629#endif
12630};
12631
12632static void *
12633exec_interrupts(void *arg)
12634{
12635 VALUE th = (VALUE)arg;
12636 rb_thread_execute_interrupts(th);
12637 return NULL;
12638}
12639
12640/*
12641 * returns TRUE if the preceding system call was interrupted
12642 * so we can continue. If the thread was interrupted, we
12643 * reacquire the GVL to execute interrupts before continuing.
12644 */
12645static int
12646maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12647{
12648 switch (errno) {
12649 case EINTR:
12650#if defined(ERESTART)
12651 case ERESTART:
12652#endif
12653 if (rb_thread_interrupted(stp->th)) {
12654 if (has_gvl)
12655 rb_thread_execute_interrupts(stp->th);
12656 else
12657 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12658 }
12659 return TRUE;
12660 }
12661 return FALSE;
12662}
12663
12665 VALUE scheduler;
12666
12667 rb_io_t *fptr;
12668 short events;
12669
12670 VALUE result;
12671};
12672
12673static void *
12674fiber_scheduler_wait_for(void * _arguments)
12675{
12676 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12677
12678 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12679
12680 return NULL;
12681}
12682
12683#if USE_POLL
12684# define IOWAIT_SYSCALL "poll"
12685STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12686STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12687static int
12688nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12689{
12691 if (scheduler != Qnil) {
12692 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12693 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12694 return RTEST(args.result);
12695 }
12696
12697 int fd = fptr->fd;
12698 if (fd == -1) return 0;
12699
12700 struct pollfd fds;
12701
12702 fds.fd = fd;
12703 fds.events = events;
12704
12705 int timeout_milliseconds = -1;
12706
12707 if (timeout) {
12708 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12709 }
12710
12711 return poll(&fds, 1, timeout_milliseconds);
12712}
12713#else /* !USE_POLL */
12714# define IOWAIT_SYSCALL "select"
12715static int
12716nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12717{
12719 if (scheduler != Qnil) {
12720 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12721 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12722 return RTEST(args.result);
12723 }
12724
12725 int fd = fptr->fd;
12726
12727 if (fd == -1) {
12728 errno = EBADF;
12729 return -1;
12730 }
12731
12732 rb_fdset_t fds;
12733 int ret;
12734
12735 rb_fd_init(&fds);
12736 rb_fd_set(fd, &fds);
12737
12738 switch (events) {
12739 case RB_WAITFD_IN:
12740 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12741 break;
12742 case RB_WAITFD_OUT:
12743 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12744 break;
12745 default:
12746 VM_UNREACHABLE(nogvl_wait_for);
12747 }
12748
12749 rb_fd_term(&fds);
12750
12751 // On timeout, this returns 0.
12752 return ret;
12753}
12754#endif /* !USE_POLL */
12755
12756static int
12757maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12758{
12759 int ret;
12760
12761 do {
12762 if (has_gvl) {
12764 }
12765 else {
12766 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12767 }
12768 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12769
12770 if (ret < 0) {
12771 stp->syserr = IOWAIT_SYSCALL;
12772 stp->error_no = errno;
12773 return ret;
12774 }
12775 return 0;
12776}
12777
12778static int
12779nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12780{
12781 int ret;
12782
12783 do {
12784 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12785 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12786
12787 if (ret < 0) {
12788 stp->syserr = IOWAIT_SYSCALL;
12789 stp->error_no = errno;
12790 return ret;
12791 }
12792 return 0;
12793}
12794
12795#ifdef USE_COPY_FILE_RANGE
12796
12797static ssize_t
12798simple_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)
12799{
12800#ifdef HAVE_COPY_FILE_RANGE
12801 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12802#else
12803 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12804#endif
12805}
12806
12807static int
12808nogvl_copy_file_range(struct copy_stream_struct *stp)
12809{
12810 ssize_t ss;
12811 rb_off_t src_size;
12812 rb_off_t copy_length, src_offset, *src_offset_ptr;
12813
12814 if (!S_ISREG(stp->src_stat.st_mode))
12815 return 0;
12816
12817 src_size = stp->src_stat.st_size;
12818 src_offset = stp->src_offset;
12819 if (src_offset >= (rb_off_t)0) {
12820 src_offset_ptr = &src_offset;
12821 }
12822 else {
12823 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12824 }
12825
12826 copy_length = stp->copy_length;
12827 if (copy_length < (rb_off_t)0) {
12828 if (src_offset < (rb_off_t)0) {
12829 rb_off_t current_offset;
12830 errno = 0;
12831 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12832 if (current_offset < (rb_off_t)0 && errno) {
12833 stp->syserr = "lseek";
12834 stp->error_no = errno;
12835 return (int)current_offset;
12836 }
12837 copy_length = src_size - current_offset;
12838 }
12839 else {
12840 copy_length = src_size - src_offset;
12841 }
12842 }
12843
12844 retry_copy_file_range:
12845# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12846 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12847 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12848# else
12849 ss = (ssize_t)copy_length;
12850# endif
12851 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12852 if (0 < ss) {
12853 stp->total += ss;
12854 copy_length -= ss;
12855 if (0 < copy_length) {
12856 goto retry_copy_file_range;
12857 }
12858 }
12859 if (ss < 0) {
12860 if (maygvl_copy_stream_continue_p(0, stp)) {
12861 goto retry_copy_file_range;
12862 }
12863 switch (errno) {
12864 case EINVAL:
12865 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12866 docker container) */
12867#ifdef ENOSYS
12868 case ENOSYS:
12869#endif
12870#ifdef EXDEV
12871 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12872#endif
12873 return 0;
12874 case EAGAIN:
12875#if EWOULDBLOCK != EAGAIN
12876 case EWOULDBLOCK:
12877#endif
12878 {
12879 int ret = nogvl_copy_stream_wait_write(stp);
12880 if (ret < 0) return ret;
12881 }
12882 goto retry_copy_file_range;
12883 case EBADF:
12884 {
12885 int e = errno;
12886 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12887
12888 if (flags != -1 && flags & O_APPEND) {
12889 return 0;
12890 }
12891 errno = e;
12892 }
12893 }
12894 stp->syserr = "copy_file_range";
12895 stp->error_no = errno;
12896 return (int)ss;
12897 }
12898 return 1;
12899}
12900#endif
12901
12902#ifdef HAVE_FCOPYFILE
12903static int
12904nogvl_fcopyfile(struct copy_stream_struct *stp)
12905{
12906 rb_off_t cur, ss = 0;
12907 const rb_off_t src_offset = stp->src_offset;
12908 int ret;
12909
12910 if (stp->copy_length >= (rb_off_t)0) {
12911 /* copy_length can't be specified in fcopyfile(3) */
12912 return 0;
12913 }
12914
12915 if (!S_ISREG(stp->src_stat.st_mode))
12916 return 0;
12917
12918 if (!S_ISREG(stp->dst_stat.st_mode))
12919 return 0;
12920 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12921 return 0;
12922 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12923 /* fcopyfile(3) appends src IO to dst IO and then truncates
12924 * dst IO to src IO's original size. */
12925 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12926 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12927 if (end > (rb_off_t)0) return 0;
12928 }
12929
12930 if (src_offset > (rb_off_t)0) {
12931 rb_off_t r;
12932
12933 /* get current offset */
12934 errno = 0;
12935 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12936 if (cur < (rb_off_t)0 && errno) {
12937 stp->error_no = errno;
12938 return 1;
12939 }
12940
12941 errno = 0;
12942 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12943 if (r < (rb_off_t)0 && errno) {
12944 stp->error_no = errno;
12945 return 1;
12946 }
12947 }
12948
12949 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12950 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12951 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12952
12953 if (ret == 0) { /* success */
12954 stp->total = ss;
12955 if (src_offset > (rb_off_t)0) {
12956 rb_off_t r;
12957 errno = 0;
12958 /* reset offset */
12959 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12960 if (r < (rb_off_t)0 && errno) {
12961 stp->error_no = errno;
12962 return 1;
12963 }
12964 }
12965 }
12966 else {
12967 switch (errno) {
12968 case ENOTSUP:
12969 case EPERM:
12970 case EINVAL:
12971 return 0;
12972 }
12973 stp->syserr = "fcopyfile";
12974 stp->error_no = errno;
12975 return (int)ret;
12976 }
12977 return 1;
12978}
12979#endif
12980
12981#ifdef HAVE_SENDFILE
12982
12983# ifdef __linux__
12984# define USE_SENDFILE
12985
12986# ifdef HAVE_SYS_SENDFILE_H
12987# include <sys/sendfile.h>
12988# endif
12989
12990static ssize_t
12991simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12992{
12993 return sendfile(out_fd, in_fd, offset, (size_t)count);
12994}
12995
12996# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12997/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12998 * without cpuset -l 0.
12999 */
13000# define USE_SENDFILE
13001
13002static ssize_t
13003simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13004{
13005 int r;
13006 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
13007 rb_off_t sbytes;
13008# ifdef __APPLE__
13009 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
13010 sbytes = count;
13011# else
13012 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
13013# endif
13014 if (r != 0 && sbytes == 0) return r;
13015 if (offset) {
13016 *offset += sbytes;
13017 }
13018 else {
13019 lseek(in_fd, sbytes, SEEK_CUR);
13020 }
13021 return (ssize_t)sbytes;
13022}
13023
13024# endif
13025
13026#endif
13027
13028#ifdef USE_SENDFILE
13029static int
13030nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
13031{
13032 ssize_t ss;
13033 rb_off_t src_size;
13034 rb_off_t copy_length;
13035 rb_off_t src_offset;
13036 int use_pread;
13037
13038 if (!S_ISREG(stp->src_stat.st_mode))
13039 return 0;
13040
13041 src_size = stp->src_stat.st_size;
13042#ifndef __linux__
13043 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
13044 return 0;
13045#endif
13046
13047 src_offset = stp->src_offset;
13048 use_pread = src_offset >= (rb_off_t)0;
13049
13050 copy_length = stp->copy_length;
13051 if (copy_length < (rb_off_t)0) {
13052 if (use_pread)
13053 copy_length = src_size - src_offset;
13054 else {
13055 rb_off_t cur;
13056 errno = 0;
13057 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13058 if (cur < (rb_off_t)0 && errno) {
13059 stp->syserr = "lseek";
13060 stp->error_no = errno;
13061 return (int)cur;
13062 }
13063 copy_length = src_size - cur;
13064 }
13065 }
13066
13067 retry_sendfile:
13068# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13069 /* we are limited by the 32-bit ssize_t return value on 32-bit */
13070 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13071# else
13072 ss = (ssize_t)copy_length;
13073# endif
13074 if (use_pread) {
13075 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
13076 }
13077 else {
13078 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
13079 }
13080 if (0 < ss) {
13081 stp->total += ss;
13082 copy_length -= ss;
13083 if (0 < copy_length) {
13084 goto retry_sendfile;
13085 }
13086 }
13087 if (ss < 0) {
13088 if (maygvl_copy_stream_continue_p(0, stp))
13089 goto retry_sendfile;
13090 switch (errno) {
13091 case EINVAL:
13092#ifdef ENOSYS
13093 case ENOSYS:
13094#endif
13095#ifdef EOPNOTSUP
13096 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
13097 see also: [Feature #16965] */
13098 case EOPNOTSUP:
13099#endif
13100 return 0;
13101 case EAGAIN:
13102#if EWOULDBLOCK != EAGAIN
13103 case EWOULDBLOCK:
13104#endif
13105 {
13106 int ret;
13107#ifndef __linux__
13108 /*
13109 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
13110 * select() reports regular files to always be "ready", so
13111 * there is no need to select() on it.
13112 * Other OSes may have the same limitation for sendfile() which
13113 * allow us to bypass maygvl_copy_stream_wait_read()...
13114 */
13115 ret = maygvl_copy_stream_wait_read(0, stp);
13116 if (ret < 0) return ret;
13117#endif
13118 ret = nogvl_copy_stream_wait_write(stp);
13119 if (ret < 0) return ret;
13120 }
13121 goto retry_sendfile;
13122 }
13123 stp->syserr = "sendfile";
13124 stp->error_no = errno;
13125 return (int)ss;
13126 }
13127 return 1;
13128}
13129#endif
13130
13131static ssize_t
13132maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13133{
13134 if (has_gvl)
13135 return rb_io_read_memory(fptr, buf, count);
13136 else
13137 return read(fptr->fd, buf, count);
13138}
13139
13140static ssize_t
13141maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13142{
13143 ssize_t ss;
13144 retry_read:
13145 if (offset < (rb_off_t)0) {
13146 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13147 }
13148 else {
13149 ss = pread(stp->src_fptr->fd, buf, len, offset);
13150 }
13151 if (ss == 0) {
13152 return 0;
13153 }
13154 if (ss < 0) {
13155 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13156 goto retry_read;
13157 switch (errno) {
13158 case EAGAIN:
13159#if EWOULDBLOCK != EAGAIN
13160 case EWOULDBLOCK:
13161#endif
13162 {
13163 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13164 if (ret < 0) return ret;
13165 }
13166 goto retry_read;
13167#ifdef ENOSYS
13168 case ENOSYS:
13169 stp->notimp = "pread";
13170 return ss;
13171#endif
13172 }
13173 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13174 stp->error_no = errno;
13175 }
13176 return ss;
13177}
13178
13179static int
13180nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13181{
13182 ssize_t ss;
13183 int off = 0;
13184 while (len) {
13185 ss = write(stp->dst_fptr->fd, buf+off, len);
13186 if (ss < 0) {
13187 if (maygvl_copy_stream_continue_p(0, stp))
13188 continue;
13189 if (io_again_p(errno)) {
13190 int ret = nogvl_copy_stream_wait_write(stp);
13191 if (ret < 0) return ret;
13192 continue;
13193 }
13194 stp->syserr = "write";
13195 stp->error_no = errno;
13196 return (int)ss;
13197 }
13198 off += (int)ss;
13199 len -= (int)ss;
13200 stp->total += ss;
13201 }
13202 return 0;
13203}
13204
13205static void
13206nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13207{
13208 char buf[1024*16];
13209 size_t len;
13210 ssize_t ss;
13211 int ret;
13212 rb_off_t copy_length;
13213 rb_off_t src_offset;
13214 int use_eof;
13215 int use_pread;
13216
13217 copy_length = stp->copy_length;
13218 use_eof = copy_length < (rb_off_t)0;
13219 src_offset = stp->src_offset;
13220 use_pread = src_offset >= (rb_off_t)0;
13221
13222 if (use_pread && stp->close_src) {
13223 rb_off_t r;
13224 errno = 0;
13225 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13226 if (r < (rb_off_t)0 && errno) {
13227 stp->syserr = "lseek";
13228 stp->error_no = errno;
13229 return;
13230 }
13231 src_offset = (rb_off_t)-1;
13232 use_pread = 0;
13233 }
13234
13235 while (use_eof || 0 < copy_length) {
13236 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13237 len = (size_t)copy_length;
13238 }
13239 else {
13240 len = sizeof(buf);
13241 }
13242 if (use_pread) {
13243 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13244 if (0 < ss)
13245 src_offset += ss;
13246 }
13247 else {
13248 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13249 }
13250 if (ss <= 0) /* EOF or error */
13251 return;
13252
13253 ret = nogvl_copy_stream_write(stp, buf, ss);
13254 if (ret < 0)
13255 return;
13256
13257 if (!use_eof)
13258 copy_length -= ss;
13259 }
13260}
13261
13262static void *
13263nogvl_copy_stream_func(void *arg)
13264{
13265 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13266#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13267 int ret;
13268#endif
13269
13270#ifdef USE_COPY_FILE_RANGE
13271 ret = nogvl_copy_file_range(stp);
13272 if (ret != 0)
13273 goto finish; /* error or success */
13274#endif
13275
13276#ifdef HAVE_FCOPYFILE
13277 ret = nogvl_fcopyfile(stp);
13278 if (ret != 0)
13279 goto finish; /* error or success */
13280#endif
13281
13282#ifdef USE_SENDFILE
13283 ret = nogvl_copy_stream_sendfile(stp);
13284 if (ret != 0)
13285 goto finish; /* error or success */
13286#endif
13287
13288 nogvl_copy_stream_read_write(stp);
13289
13290#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13291 finish:
13292#endif
13293 return 0;
13294}
13295
13296static VALUE
13297copy_stream_fallback_body(VALUE arg)
13298{
13299 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13300 const int buflen = 16*1024;
13301 VALUE n;
13302 VALUE buf = rb_str_buf_new(buflen);
13303 rb_off_t rest = stp->copy_length;
13304 rb_off_t off = stp->src_offset;
13305 ID read_method = id_readpartial;
13306
13307 if (!stp->src_fptr) {
13308 if (!rb_respond_to(stp->src, read_method)) {
13309 read_method = id_read;
13310 }
13311 }
13312
13313 while (1) {
13314 long numwrote;
13315 long l;
13316 rb_str_make_independent(buf);
13317 if (stp->copy_length < (rb_off_t)0) {
13318 l = buflen;
13319 }
13320 else {
13321 if (rest == 0) {
13322 rb_str_resize(buf, 0);
13323 break;
13324 }
13325 l = buflen < rest ? buflen : (long)rest;
13326 }
13327 if (!stp->src_fptr) {
13328 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13329
13330 if (read_method == id_read && NIL_P(rc))
13331 break;
13332 }
13333 else {
13334 ssize_t ss;
13335 rb_str_resize(buf, buflen);
13336 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13337 rb_str_resize(buf, ss > 0 ? ss : 0);
13338 if (ss < 0)
13339 return Qnil;
13340 if (ss == 0)
13341 rb_eof_error();
13342 if (off >= (rb_off_t)0)
13343 off += ss;
13344 }
13345 n = rb_io_write(stp->dst, buf);
13346 numwrote = NUM2LONG(n);
13347 stp->total += numwrote;
13348 rest -= numwrote;
13349 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13350 break;
13351 }
13352 }
13353
13354 return Qnil;
13355}
13356
13357static VALUE
13358copy_stream_fallback(struct copy_stream_struct *stp)
13359{
13360 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13361 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13362 }
13363 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13364 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13365 rb_eEOFError, (VALUE)0);
13366 return Qnil;
13367}
13368
13369static VALUE
13370copy_stream_body(VALUE arg)
13371{
13372 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13373 VALUE src_io = stp->src, dst_io = stp->dst;
13374 const int common_oflags = 0
13375#ifdef O_NOCTTY
13376 | O_NOCTTY
13377#endif
13378 ;
13379
13380 stp->th = rb_thread_current();
13381
13382 stp->total = 0;
13383
13384 if (src_io == argf ||
13385 !(RB_TYPE_P(src_io, T_FILE) ||
13386 RB_TYPE_P(src_io, T_STRING) ||
13387 rb_respond_to(src_io, rb_intern("to_path")))) {
13388 stp->src_fptr = NULL;
13389 }
13390 else {
13391 int stat_ret;
13392 VALUE tmp_io = rb_io_check_io(src_io);
13393 if (!NIL_P(tmp_io)) {
13394 src_io = tmp_io;
13395 }
13396 else if (!RB_TYPE_P(src_io, T_FILE)) {
13397 VALUE args[2];
13398 FilePathValue(src_io);
13399 args[0] = src_io;
13400 args[1] = INT2NUM(O_RDONLY|common_oflags);
13401 src_io = rb_class_new_instance(2, args, rb_cFile);
13402 stp->src = src_io;
13403 stp->close_src = 1;
13404 }
13405 RB_IO_POINTER(src_io, stp->src_fptr);
13406 rb_io_check_byte_readable(stp->src_fptr);
13407
13408 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13409 if (stat_ret < 0) {
13410 stp->syserr = "fstat";
13411 stp->error_no = errno;
13412 return Qnil;
13413 }
13414 }
13415
13416 if (dst_io == argf ||
13417 !(RB_TYPE_P(dst_io, T_FILE) ||
13418 RB_TYPE_P(dst_io, T_STRING) ||
13419 rb_respond_to(dst_io, rb_intern("to_path")))) {
13420 stp->dst_fptr = NULL;
13421 }
13422 else {
13423 int stat_ret;
13424 VALUE tmp_io = rb_io_check_io(dst_io);
13425 if (!NIL_P(tmp_io)) {
13426 dst_io = GetWriteIO(tmp_io);
13427 }
13428 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13429 VALUE args[3];
13430 FilePathValue(dst_io);
13431 args[0] = dst_io;
13432 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13433 args[2] = INT2FIX(0666);
13434 dst_io = rb_class_new_instance(3, args, rb_cFile);
13435 stp->dst = dst_io;
13436 stp->close_dst = 1;
13437 }
13438 else {
13439 dst_io = GetWriteIO(dst_io);
13440 stp->dst = dst_io;
13441 }
13442 RB_IO_POINTER(dst_io, stp->dst_fptr);
13443 rb_io_check_writable(stp->dst_fptr);
13444
13445 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13446 if (stat_ret < 0) {
13447 stp->syserr = "fstat";
13448 stp->error_no = errno;
13449 return Qnil;
13450 }
13451 }
13452
13453#ifdef O_BINARY
13454 if (stp->src_fptr)
13455 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13456#endif
13457 if (stp->dst_fptr)
13458 io_ascii8bit_binmode(stp->dst_fptr);
13459
13460 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13461 size_t len = stp->src_fptr->rbuf.len;
13462 VALUE str;
13463 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13464 len = (size_t)stp->copy_length;
13465 }
13466 str = rb_str_buf_new(len);
13467 rb_str_resize(str,len);
13468 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13469 if (stp->dst_fptr) { /* IO or filename */
13470 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13471 rb_sys_fail_on_write(stp->dst_fptr);
13472 }
13473 else /* others such as StringIO */
13474 rb_io_write(dst_io, str);
13475 rb_str_resize(str, 0);
13476 stp->total += len;
13477 if (stp->copy_length >= (rb_off_t)0)
13478 stp->copy_length -= len;
13479 }
13480
13481 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13482 rb_raise(rb_eIOError, "flush failed");
13483 }
13484
13485 if (stp->copy_length == 0)
13486 return Qnil;
13487
13488 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13489 return copy_stream_fallback(stp);
13490 }
13491
13492 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13493 return Qnil;
13494}
13495
13496static VALUE
13497copy_stream_finalize(VALUE arg)
13498{
13499 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13500
13501#ifdef HAVE_FCOPYFILE
13502 if (stp->copyfile_state) {
13503 copyfile_state_free(stp->copyfile_state);
13504 }
13505#endif
13506
13507 if (stp->close_src) {
13508 rb_io_close_m(stp->src);
13509 }
13510 if (stp->close_dst) {
13511 rb_io_close_m(stp->dst);
13512 }
13513 if (stp->syserr) {
13514 rb_syserr_fail(stp->error_no, stp->syserr);
13515 }
13516 if (stp->notimp) {
13517 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13518 }
13519 return Qnil;
13520}
13521
13522/*
13523 * call-seq:
13524 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13525 *
13526 * Copies from the given +src+ to the given +dst+,
13527 * returning the number of bytes copied.
13528 *
13529 * - The given +src+ must be one of the following:
13530 *
13531 * - The path to a readable file, from which source data is to be read.
13532 * - An \IO-like object, opened for reading and capable of responding
13533 * to method +:readpartial+ or method +:read+.
13534 *
13535 * - The given +dst+ must be one of the following:
13536 *
13537 * - The path to a writable file, to which data is to be written.
13538 * - An \IO-like object, opened for writing and capable of responding
13539 * to method +:write+.
13540 *
13541 * The examples here use file <tt>t.txt</tt> as source:
13542 *
13543 * File.read('t.txt')
13544 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13545 * File.read('t.txt').size # => 47
13546 *
13547 * If only arguments +src+ and +dst+ are given,
13548 * the entire source stream is copied:
13549 *
13550 * # Paths.
13551 * IO.copy_stream('t.txt', 't.tmp') # => 47
13552 *
13553 * # IOs (recall that a File is also an IO).
13554 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13555 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13556 * IO.copy_stream(src_io, dst_io) # => 47
13557 * src_io.close
13558 * dst_io.close
13559 *
13560 * With argument +src_length+ a non-negative integer,
13561 * no more than that many bytes are copied:
13562 *
13563 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13564 * File.read('t.tmp') # => "First line"
13565 *
13566 * With argument +src_offset+ also given,
13567 * the source stream is read beginning at that offset:
13568 *
13569 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13570 * IO.read('t.tmp') # => "Second line"
13571 *
13572 */
13573static VALUE
13574rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13575{
13576 VALUE src, dst, length, src_offset;
13577 struct copy_stream_struct st;
13578
13579 MEMZERO(&st, struct copy_stream_struct, 1);
13580
13581 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13582
13583 st.src = src;
13584 st.dst = dst;
13585
13586 st.src_fptr = NULL;
13587 st.dst_fptr = NULL;
13588
13589 if (NIL_P(length))
13590 st.copy_length = (rb_off_t)-1;
13591 else
13592 st.copy_length = NUM2OFFT(length);
13593
13594 if (NIL_P(src_offset))
13595 st.src_offset = (rb_off_t)-1;
13596 else
13597 st.src_offset = NUM2OFFT(src_offset);
13598
13599 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13600
13601 return OFFT2NUM(st.total);
13602}
13603
13604/*
13605 * call-seq:
13606 * external_encoding -> encoding or nil
13607 *
13608 * Returns the Encoding object that represents the encoding of the stream,
13609 * or +nil+ if the stream is in write mode and no encoding is specified.
13610 *
13611 * See {Encodings}[rdoc-ref:File@Encodings].
13612 *
13613 */
13614
13615static VALUE
13616rb_io_external_encoding(VALUE io)
13617{
13618 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13619
13620 if (fptr->encs.enc2) {
13621 return rb_enc_from_encoding(fptr->encs.enc2);
13622 }
13623 if (fptr->mode & FMODE_WRITABLE) {
13624 if (fptr->encs.enc)
13625 return rb_enc_from_encoding(fptr->encs.enc);
13626 return Qnil;
13627 }
13628 return rb_enc_from_encoding(io_read_encoding(fptr));
13629}
13630
13631/*
13632 * call-seq:
13633 * internal_encoding -> encoding or nil
13634 *
13635 * Returns the Encoding object that represents the encoding of the internal string,
13636 * if conversion is specified,
13637 * or +nil+ otherwise.
13638 *
13639 * See {Encodings}[rdoc-ref:File@Encodings].
13640 *
13641 */
13642
13643static VALUE
13644rb_io_internal_encoding(VALUE io)
13645{
13646 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13647
13648 if (!fptr->encs.enc2) return Qnil;
13649 return rb_enc_from_encoding(io_read_encoding(fptr));
13650}
13651
13652/*
13653 * call-seq:
13654 * set_encoding(ext_enc) -> self
13655 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13656 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13657 *
13658 * See {Encodings}[rdoc-ref:File@Encodings].
13659 *
13660 * Argument +ext_enc+, if given, must be an Encoding object
13661 * or a String with the encoding name;
13662 * it is assigned as the encoding for the stream.
13663 *
13664 * Argument +int_enc+, if given, must be an Encoding object
13665 * or a String with the encoding name;
13666 * it is assigned as the encoding for the internal string.
13667 *
13668 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13669 * containing two colon-separated encoding names;
13670 * corresponding Encoding objects are assigned as the external
13671 * and internal encodings for the stream.
13672 *
13673 * If the external encoding of a string is binary/ASCII-8BIT,
13674 * the internal encoding of the string is set to nil, since no
13675 * transcoding is needed.
13676 *
13677 * Optional keyword arguments +enc_opts+ specify
13678 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13679 *
13680 */
13681
13682static VALUE
13683rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13684{
13685 rb_io_t *fptr;
13686 VALUE v1, v2, opt;
13687
13688 if (!RB_TYPE_P(io, T_FILE)) {
13689 return forward(io, id_set_encoding, argc, argv);
13690 }
13691
13692 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13693 GetOpenFile(io, fptr);
13694 io_encoding_set(fptr, v1, v2, opt);
13695 return io;
13696}
13697
13698void
13699rb_stdio_set_default_encoding(void)
13700{
13701 VALUE val = Qnil;
13702
13703#ifdef _WIN32
13704 if (isatty(fileno(stdin))) {
13705 rb_encoding *external = rb_locale_encoding();
13706 rb_encoding *internal = rb_default_internal_encoding();
13707 if (!internal) internal = rb_default_external_encoding();
13708 io_encoding_set(RFILE(rb_stdin)->fptr,
13709 rb_enc_from_encoding(external),
13710 rb_enc_from_encoding(internal),
13711 Qnil);
13712 }
13713 else
13714#endif
13715 rb_io_set_encoding(1, &val, rb_stdin);
13716 rb_io_set_encoding(1, &val, rb_stdout);
13717 rb_io_set_encoding(1, &val, rb_stderr);
13718}
13719
13720static inline int
13721global_argf_p(VALUE arg)
13722{
13723 return arg == argf;
13724}
13725
13726typedef VALUE (*argf_encoding_func)(VALUE io);
13727
13728static VALUE
13729argf_encoding(VALUE argf, argf_encoding_func func)
13730{
13731 if (!RTEST(ARGF.current_file)) {
13732 return rb_enc_default_external();
13733 }
13734 return func(rb_io_check_io(ARGF.current_file));
13735}
13736
13737/*
13738 * call-seq:
13739 * ARGF.external_encoding -> encoding
13740 *
13741 * Returns the external encoding for files read from ARGF as an Encoding
13742 * object. The external encoding is the encoding of the text as stored in a
13743 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13744 * represent this text within Ruby.
13745 *
13746 * To set the external encoding use ARGF.set_encoding.
13747 *
13748 * For example:
13749 *
13750 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13751 *
13752 */
13753static VALUE
13754argf_external_encoding(VALUE argf)
13755{
13756 return argf_encoding(argf, rb_io_external_encoding);
13757}
13758
13759/*
13760 * call-seq:
13761 * ARGF.internal_encoding -> encoding
13762 *
13763 * Returns the internal encoding for strings read from ARGF as an
13764 * Encoding object.
13765 *
13766 * If ARGF.set_encoding has been called with two encoding names, the second
13767 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13768 * value is returned. Failing that, if a default external encoding was
13769 * specified on the command-line, that value is used. If the encoding is
13770 * unknown, +nil+ is returned.
13771 */
13772static VALUE
13773argf_internal_encoding(VALUE argf)
13774{
13775 return argf_encoding(argf, rb_io_internal_encoding);
13776}
13777
13778/*
13779 * call-seq:
13780 * ARGF.set_encoding(ext_enc) -> ARGF
13781 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13782 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13783 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13784 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13785 *
13786 * If single argument is specified, strings read from ARGF are tagged with
13787 * the encoding specified.
13788 *
13789 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13790 * the read string is converted from the first encoding (external encoding)
13791 * to the second encoding (internal encoding), then tagged with the second
13792 * encoding.
13793 *
13794 * If two arguments are specified, they must be encoding objects or encoding
13795 * names. Again, the first specifies the external encoding; the second
13796 * specifies the internal encoding.
13797 *
13798 * If the external encoding and the internal encoding are specified, the
13799 * optional Hash argument can be used to adjust the conversion process. The
13800 * structure of this hash is explained in the String#encode documentation.
13801 *
13802 * For example:
13803 *
13804 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13805 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13806 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13807 * # to UTF-8.
13808 */
13809static VALUE
13810argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13811{
13812 rb_io_t *fptr;
13813
13814 if (!next_argv()) {
13815 rb_raise(rb_eArgError, "no stream to set encoding");
13816 }
13817 rb_io_set_encoding(argc, argv, ARGF.current_file);
13818 GetOpenFile(ARGF.current_file, fptr);
13819 ARGF.encs = fptr->encs;
13820 RB_OBJ_WRITTEN(argf, Qundef, ARGF.encs.ecopts);
13821 return argf;
13822}
13823
13824/*
13825 * call-seq:
13826 * ARGF.tell -> Integer
13827 * ARGF.pos -> Integer
13828 *
13829 * Returns the current offset (in bytes) of the current file in ARGF.
13830 *
13831 * ARGF.pos #=> 0
13832 * ARGF.gets #=> "This is line one\n"
13833 * ARGF.pos #=> 17
13834 *
13835 */
13836static VALUE
13837argf_tell(VALUE argf)
13838{
13839 if (!next_argv()) {
13840 rb_raise(rb_eArgError, "no stream to tell");
13841 }
13842 ARGF_FORWARD(0, 0);
13843 return rb_io_tell(ARGF.current_file);
13844}
13845
13846/*
13847 * call-seq:
13848 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13849 *
13850 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13851 * the value of _whence_. See IO#seek for further details.
13852 */
13853static VALUE
13854argf_seek_m(int argc, VALUE *argv, VALUE argf)
13855{
13856 if (!next_argv()) {
13857 rb_raise(rb_eArgError, "no stream to seek");
13858 }
13859 ARGF_FORWARD(argc, argv);
13860 return rb_io_seek_m(argc, argv, ARGF.current_file);
13861}
13862
13863/*
13864 * call-seq:
13865 * ARGF.pos = position -> Integer
13866 *
13867 * Seeks to the position given by _position_ (in bytes) in ARGF.
13868 *
13869 * For example:
13870 *
13871 * ARGF.pos = 17
13872 * ARGF.gets #=> "This is line two\n"
13873 */
13874static VALUE
13875argf_set_pos(VALUE argf, VALUE offset)
13876{
13877 if (!next_argv()) {
13878 rb_raise(rb_eArgError, "no stream to set position");
13879 }
13880 ARGF_FORWARD(1, &offset);
13881 return rb_io_set_pos(ARGF.current_file, offset);
13882}
13883
13884/*
13885 * call-seq:
13886 * ARGF.rewind -> 0
13887 *
13888 * Positions the current file to the beginning of input, resetting
13889 * ARGF.lineno to zero.
13890 *
13891 * ARGF.readline #=> "This is line one\n"
13892 * ARGF.rewind #=> 0
13893 * ARGF.lineno #=> 0
13894 * ARGF.readline #=> "This is line one\n"
13895 */
13896static VALUE
13897argf_rewind(VALUE argf)
13898{
13899 VALUE ret;
13900 int old_lineno;
13901
13902 if (!next_argv()) {
13903 rb_raise(rb_eArgError, "no stream to rewind");
13904 }
13905 ARGF_FORWARD(0, 0);
13906 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13907 ret = rb_io_rewind(ARGF.current_file);
13908 if (!global_argf_p(argf)) {
13909 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13910 }
13911 return ret;
13912}
13913
13914/*
13915 * call-seq:
13916 * ARGF.fileno -> integer
13917 * ARGF.to_i -> integer
13918 *
13919 * Returns an integer representing the numeric file descriptor for
13920 * the current file. Raises an ArgumentError if there isn't a current file.
13921 *
13922 * ARGF.fileno #=> 3
13923 */
13924static VALUE
13925argf_fileno(VALUE argf)
13926{
13927 if (!next_argv()) {
13928 rb_raise(rb_eArgError, "no stream");
13929 }
13930 ARGF_FORWARD(0, 0);
13931 return rb_io_fileno(ARGF.current_file);
13932}
13933
13934/*
13935 * call-seq:
13936 * ARGF.to_io -> IO
13937 *
13938 * Returns an IO object representing the current file. This will be a
13939 * File object unless the current file is a stream such as STDIN.
13940 *
13941 * For example:
13942 *
13943 * ARGF.to_io #=> #<File:glark.txt>
13944 * ARGF.to_io #=> #<IO:<STDIN>>
13945 */
13946static VALUE
13947argf_to_io(VALUE argf)
13948{
13949 next_argv();
13950 ARGF_FORWARD(0, 0);
13951 return ARGF.current_file;
13952}
13953
13954/*
13955 * call-seq:
13956 * ARGF.eof? -> true or false
13957 * ARGF.eof -> true or false
13958 *
13959 * Returns true if the current file in ARGF is at end of file, i.e. it has
13960 * no data to read. The stream must be opened for reading or an IOError
13961 * will be raised.
13962 *
13963 * $ echo "eof" | ruby argf.rb
13964 *
13965 * ARGF.eof? #=> false
13966 * 3.times { ARGF.readchar }
13967 * ARGF.eof? #=> false
13968 * ARGF.readchar #=> "\n"
13969 * ARGF.eof? #=> true
13970 */
13971
13972static VALUE
13973argf_eof(VALUE argf)
13974{
13975 next_argv();
13976 if (RTEST(ARGF.current_file)) {
13977 if (ARGF.init_p == 0) return Qtrue;
13978 next_argv();
13979 ARGF_FORWARD(0, 0);
13980 if (rb_io_eof(ARGF.current_file)) {
13981 return Qtrue;
13982 }
13983 }
13984 return Qfalse;
13985}
13986
13987/*
13988 * call-seq:
13989 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13990 *
13991 * Reads _length_ bytes from ARGF. The files named on the command line
13992 * are concatenated and treated as a single file by this method, so when
13993 * called without arguments the contents of this pseudo file are returned in
13994 * their entirety.
13995 *
13996 * _length_ must be a non-negative integer or +nil+.
13997 *
13998 * If _length_ is a positive integer, +read+ tries to read
13999 * _length_ bytes without any conversion (binary mode).
14000 * It returns +nil+ if an EOF is encountered before anything can be read.
14001 * Fewer than _length_ bytes are returned if an EOF is encountered during
14002 * the read.
14003 * In the case of an integer _length_, the resulting string is always
14004 * in ASCII-8BIT encoding.
14005 *
14006 * If _length_ is omitted or is +nil+, it reads until EOF
14007 * and the encoding conversion is applied, if applicable.
14008 * A string is returned even if EOF is encountered before any data is read.
14009 *
14010 * If _length_ is zero, it returns an empty string (<code>""</code>).
14011 *
14012 * If the optional _outbuf_ argument is present,
14013 * it must reference a String, which will receive the data.
14014 * The _outbuf_ will contain only the received data after the method call
14015 * even if it is not empty at the beginning.
14016 *
14017 * For example:
14018 *
14019 * $ echo "small" > small.txt
14020 * $ echo "large" > large.txt
14021 * $ ./glark.rb small.txt large.txt
14022 *
14023 * ARGF.read #=> "small\nlarge"
14024 * ARGF.read(200) #=> "small\nlarge"
14025 * ARGF.read(2) #=> "sm"
14026 * ARGF.read(0) #=> ""
14027 *
14028 * Note that this method behaves like the fread() function in C.
14029 * This means it retries to invoke read(2) system calls to read data
14030 * with the specified length.
14031 * If you need the behavior like a single read(2) system call,
14032 * consider ARGF#readpartial or ARGF#read_nonblock.
14033 */
14034
14035static VALUE
14036argf_read(int argc, VALUE *argv, VALUE argf)
14037{
14038 VALUE tmp, str, length;
14039 long len = 0;
14040
14041 rb_scan_args(argc, argv, "02", &length, &str);
14042 if (!NIL_P(length)) {
14043 len = NUM2LONG(argv[0]);
14044 }
14045 if (!NIL_P(str)) {
14046 StringValue(str);
14047 rb_str_resize(str,0);
14048 argv[1] = Qnil;
14049 }
14050
14051 retry:
14052 if (!next_argv()) {
14053 return str;
14054 }
14055 if (ARGF_GENERIC_INPUT_P()) {
14056 tmp = argf_forward(argc, argv, argf);
14057 }
14058 else {
14059 tmp = io_read(argc, argv, ARGF.current_file);
14060 }
14061 if (NIL_P(str)) str = tmp;
14062 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
14063 if (NIL_P(tmp) || NIL_P(length)) {
14064 if (ARGF.next_p != -1) {
14065 argf_close(argf);
14066 ARGF.next_p = 1;
14067 goto retry;
14068 }
14069 }
14070 else if (argc >= 1) {
14071 long slen = RSTRING_LEN(str);
14072 if (slen < len) {
14073 argv[0] = LONG2NUM(len - slen);
14074 goto retry;
14075 }
14076 }
14077 return str;
14078}
14079
14081 int argc;
14082 VALUE *argv;
14083 VALUE argf;
14084};
14085
14086static VALUE
14087argf_forward_call(VALUE arg)
14088{
14089 struct argf_call_arg *p = (struct argf_call_arg *)arg;
14090 argf_forward(p->argc, p->argv, p->argf);
14091 return Qnil;
14092}
14093
14094static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
14095 int nonblock);
14096
14097/*
14098 * call-seq:
14099 * ARGF.readpartial(maxlen) -> string
14100 * ARGF.readpartial(maxlen, outbuf) -> outbuf
14101 *
14102 * Reads at most _maxlen_ bytes from the ARGF stream.
14103 *
14104 * If the optional _outbuf_ argument is present,
14105 * it must reference a String, which will receive the data.
14106 * The _outbuf_ will contain only the received data after the method call
14107 * even if it is not empty at the beginning.
14108 *
14109 * It raises EOFError on end of ARGF stream.
14110 * Since ARGF stream is a concatenation of multiple files,
14111 * internally EOF is occur for each file.
14112 * ARGF.readpartial returns empty strings for EOFs except the last one and
14113 * raises EOFError for the last one.
14114 *
14115 */
14116
14117static VALUE
14118argf_readpartial(int argc, VALUE *argv, VALUE argf)
14119{
14120 return argf_getpartial(argc, argv, argf, Qnil, 0);
14121}
14122
14123/*
14124 * call-seq:
14125 * ARGF.read_nonblock(maxlen[, options]) -> string
14126 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14127 *
14128 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14129 */
14130
14131static VALUE
14132argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14133{
14134 VALUE opts;
14135
14136 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14137
14138 if (!NIL_P(opts))
14139 argc--;
14140
14141 return argf_getpartial(argc, argv, argf, opts, 1);
14142}
14143
14144static VALUE
14145argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14146{
14147 VALUE tmp, str, length;
14148 int no_exception;
14149
14150 rb_scan_args(argc, argv, "11", &length, &str);
14151 if (!NIL_P(str)) {
14152 StringValue(str);
14153 argv[1] = str;
14154 }
14155 no_exception = no_exception_p(opts);
14156
14157 if (!next_argv()) {
14158 if (!NIL_P(str)) {
14159 rb_str_resize(str, 0);
14160 }
14161 rb_eof_error();
14162 }
14163 if (ARGF_GENERIC_INPUT_P()) {
14164 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14165 struct argf_call_arg arg;
14166 arg.argc = argc;
14167 arg.argv = argv;
14168 arg.argf = argf;
14169 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14170 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14171 }
14172 else {
14173 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14174 }
14175 if (NIL_P(tmp)) {
14176 if (ARGF.next_p == -1) {
14177 return io_nonblock_eof(no_exception);
14178 }
14179 argf_close(argf);
14180 ARGF.next_p = 1;
14181 if (RARRAY_LEN(ARGF.argv) == 0) {
14182 return io_nonblock_eof(no_exception);
14183 }
14184 if (NIL_P(str))
14185 str = rb_str_new(NULL, 0);
14186 return str;
14187 }
14188 return tmp;
14189}
14190
14191/*
14192 * call-seq:
14193 * ARGF.getc -> String or nil
14194 *
14195 * Reads the next character from ARGF and returns it as a String. Returns
14196 * +nil+ at the end of the stream.
14197 *
14198 * ARGF treats the files named on the command line as a single file created
14199 * by concatenating their contents. After returning the last character of the
14200 * first file, it returns the first character of the second file, and so on.
14201 *
14202 * For example:
14203 *
14204 * $ echo "foo" > file
14205 * $ ruby argf.rb file
14206 *
14207 * ARGF.getc #=> "f"
14208 * ARGF.getc #=> "o"
14209 * ARGF.getc #=> "o"
14210 * ARGF.getc #=> "\n"
14211 * ARGF.getc #=> nil
14212 * ARGF.getc #=> nil
14213 */
14214static VALUE
14215argf_getc(VALUE argf)
14216{
14217 VALUE ch;
14218
14219 retry:
14220 if (!next_argv()) return Qnil;
14221 if (ARGF_GENERIC_INPUT_P()) {
14222 ch = forward_current(rb_intern("getc"), 0, 0);
14223 }
14224 else {
14225 ch = rb_io_getc(ARGF.current_file);
14226 }
14227 if (NIL_P(ch) && ARGF.next_p != -1) {
14228 argf_close(argf);
14229 ARGF.next_p = 1;
14230 goto retry;
14231 }
14232
14233 return ch;
14234}
14235
14236/*
14237 * call-seq:
14238 * ARGF.getbyte -> Integer or nil
14239 *
14240 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14241 * the end of the stream.
14242 *
14243 * For example:
14244 *
14245 * $ echo "foo" > file
14246 * $ ruby argf.rb file
14247 *
14248 * ARGF.getbyte #=> 102
14249 * ARGF.getbyte #=> 111
14250 * ARGF.getbyte #=> 111
14251 * ARGF.getbyte #=> 10
14252 * ARGF.getbyte #=> nil
14253 */
14254static VALUE
14255argf_getbyte(VALUE argf)
14256{
14257 VALUE ch;
14258
14259 retry:
14260 if (!next_argv()) return Qnil;
14261 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14262 ch = forward_current(rb_intern("getbyte"), 0, 0);
14263 }
14264 else {
14265 ch = rb_io_getbyte(ARGF.current_file);
14266 }
14267 if (NIL_P(ch) && ARGF.next_p != -1) {
14268 argf_close(argf);
14269 ARGF.next_p = 1;
14270 goto retry;
14271 }
14272
14273 return ch;
14274}
14275
14276/*
14277 * call-seq:
14278 * ARGF.readchar -> String or nil
14279 *
14280 * Reads the next character from ARGF and returns it as a String. Raises
14281 * an EOFError after the last character of the last file has been read.
14282 *
14283 * For example:
14284 *
14285 * $ echo "foo" > file
14286 * $ ruby argf.rb file
14287 *
14288 * ARGF.readchar #=> "f"
14289 * ARGF.readchar #=> "o"
14290 * ARGF.readchar #=> "o"
14291 * ARGF.readchar #=> "\n"
14292 * ARGF.readchar #=> end of file reached (EOFError)
14293 */
14294static VALUE
14295argf_readchar(VALUE argf)
14296{
14297 VALUE ch;
14298
14299 retry:
14300 if (!next_argv()) rb_eof_error();
14301 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14302 ch = forward_current(rb_intern("getc"), 0, 0);
14303 }
14304 else {
14305 ch = rb_io_getc(ARGF.current_file);
14306 }
14307 if (NIL_P(ch) && ARGF.next_p != -1) {
14308 argf_close(argf);
14309 ARGF.next_p = 1;
14310 goto retry;
14311 }
14312
14313 return ch;
14314}
14315
14316/*
14317 * call-seq:
14318 * ARGF.readbyte -> Integer
14319 *
14320 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14321 * an EOFError after the last byte of the last file has been read.
14322 *
14323 * For example:
14324 *
14325 * $ echo "foo" > file
14326 * $ ruby argf.rb file
14327 *
14328 * ARGF.readbyte #=> 102
14329 * ARGF.readbyte #=> 111
14330 * ARGF.readbyte #=> 111
14331 * ARGF.readbyte #=> 10
14332 * ARGF.readbyte #=> end of file reached (EOFError)
14333 */
14334static VALUE
14335argf_readbyte(VALUE argf)
14336{
14337 VALUE c;
14338
14339 NEXT_ARGF_FORWARD(0, 0);
14340 c = argf_getbyte(argf);
14341 if (NIL_P(c)) {
14342 rb_eof_error();
14343 }
14344 return c;
14345}
14346
14347#define FOREACH_ARGF() while (next_argv())
14348
14349static VALUE
14350argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14351{
14352 const VALUE current = ARGF.current_file;
14353 rb_yield_values2(argc, argv);
14354 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14356 }
14357 return Qnil;
14358}
14359
14360#define ARGF_block_call(mid, argc, argv, func, argf) \
14361 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14362 func, argf, rb_keyword_given_p())
14363
14364static void
14365argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14366{
14367 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14368 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14369}
14370
14371static VALUE
14372argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14373{
14374 if (!global_argf_p(argf)) {
14375 ARGF.last_lineno = ++ARGF.lineno;
14376 }
14377 return argf_block_call_i(i, argf, argc, argv, blockarg);
14378}
14379
14380static void
14381argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14382{
14383 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14384 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14385}
14386
14387/*
14388 * call-seq:
14389 * ARGF.each(sep=$/) {|line| block } -> ARGF
14390 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14391 * ARGF.each(...) -> an_enumerator
14392 *
14393 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14394 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14395 * ARGF.each_line(...) -> an_enumerator
14396 *
14397 * Returns an enumerator which iterates over each line (separated by _sep_,
14398 * which defaults to your platform's newline character) of each file in
14399 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14400 * block, otherwise an enumerator is returned.
14401 * The optional _limit_ argument is an Integer specifying the maximum
14402 * length of each line; longer lines will be split according to this limit.
14403 *
14404 * This method allows you to treat the files supplied on the command line as
14405 * a single file consisting of the concatenation of each named file. After
14406 * the last line of the first file has been returned, the first line of the
14407 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14408 * used to determine the filename of the current line and line number of the
14409 * whole input, respectively.
14410 *
14411 * For example, the following code prints out each line of each named file
14412 * prefixed with its line number, displaying the filename once per file:
14413 *
14414 * ARGF.each_line do |line|
14415 * puts ARGF.filename if ARGF.file.lineno == 1
14416 * puts "#{ARGF.file.lineno}: #{line}"
14417 * end
14418 *
14419 * While the following code prints only the first file's name at first, and
14420 * the contents with line number counted through all named files.
14421 *
14422 * ARGF.each_line do |line|
14423 * puts ARGF.filename if ARGF.lineno == 1
14424 * puts "#{ARGF.lineno}: #{line}"
14425 * end
14426 */
14427static VALUE
14428argf_each_line(int argc, VALUE *argv, VALUE argf)
14429{
14430 RETURN_ENUMERATOR(argf, argc, argv);
14431 FOREACH_ARGF() {
14432 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14433 }
14434 return argf;
14435}
14436
14437/*
14438 * call-seq:
14439 * ARGF.each_byte {|byte| block } -> ARGF
14440 * ARGF.each_byte -> an_enumerator
14441 *
14442 * Iterates over each byte of each file in +ARGV+.
14443 * A byte is returned as an Integer in the range 0..255.
14444 *
14445 * This method allows you to treat the files supplied on the command line as
14446 * a single file consisting of the concatenation of each named file. After
14447 * the last byte of the first file has been returned, the first byte of the
14448 * second file is returned. The ARGF.filename method can be used to
14449 * determine the filename of the current byte.
14450 *
14451 * If no block is given, an enumerator is returned instead.
14452 *
14453 * For example:
14454 *
14455 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14456 *
14457 */
14458static VALUE
14459argf_each_byte(VALUE argf)
14460{
14461 RETURN_ENUMERATOR(argf, 0, 0);
14462 FOREACH_ARGF() {
14463 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14464 }
14465 return argf;
14466}
14467
14468/*
14469 * call-seq:
14470 * ARGF.each_char {|char| block } -> ARGF
14471 * ARGF.each_char -> an_enumerator
14472 *
14473 * Iterates over each character of each file in ARGF.
14474 *
14475 * This method allows you to treat the files supplied on the command line as
14476 * a single file consisting of the concatenation of each named file. After
14477 * the last character of the first file has been returned, the first
14478 * character of the second file is returned. The ARGF.filename method can
14479 * be used to determine the name of the file in which the current character
14480 * appears.
14481 *
14482 * If no block is given, an enumerator is returned instead.
14483 */
14484static VALUE
14485argf_each_char(VALUE argf)
14486{
14487 RETURN_ENUMERATOR(argf, 0, 0);
14488 FOREACH_ARGF() {
14489 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14490 }
14491 return argf;
14492}
14493
14494/*
14495 * call-seq:
14496 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14497 * ARGF.each_codepoint -> an_enumerator
14498 *
14499 * Iterates over each codepoint of each file in ARGF.
14500 *
14501 * This method allows you to treat the files supplied on the command line as
14502 * a single file consisting of the concatenation of each named file. After
14503 * the last codepoint of the first file has been returned, the first
14504 * codepoint of the second file is returned. The ARGF.filename method can
14505 * be used to determine the name of the file in which the current codepoint
14506 * appears.
14507 *
14508 * If no block is given, an enumerator is returned instead.
14509 */
14510static VALUE
14511argf_each_codepoint(VALUE argf)
14512{
14513 RETURN_ENUMERATOR(argf, 0, 0);
14514 FOREACH_ARGF() {
14515 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14516 }
14517 return argf;
14518}
14519
14520/*
14521 * call-seq:
14522 * ARGF.filename -> String
14523 * ARGF.path -> String
14524 *
14525 * Returns the current filename. "-" is returned when the current file is
14526 * STDIN.
14527 *
14528 * For example:
14529 *
14530 * $ echo "foo" > foo
14531 * $ echo "bar" > bar
14532 * $ echo "glark" > glark
14533 *
14534 * $ ruby argf.rb foo bar glark
14535 *
14536 * ARGF.filename #=> "foo"
14537 * ARGF.read(5) #=> "foo\nb"
14538 * ARGF.filename #=> "bar"
14539 * ARGF.skip
14540 * ARGF.filename #=> "glark"
14541 */
14542static VALUE
14543argf_filename(VALUE argf)
14544{
14545 next_argv();
14546 return ARGF.filename;
14547}
14548
14549static VALUE
14550argf_filename_getter(ID id, VALUE *var)
14551{
14552 return argf_filename(*var);
14553}
14554
14555/*
14556 * call-seq:
14557 * ARGF.file -> IO or File object
14558 *
14559 * Returns the current file as an IO or File object.
14560 * <code>$stdin</code> is returned when the current file is STDIN.
14561 *
14562 * For example:
14563 *
14564 * $ echo "foo" > foo
14565 * $ echo "bar" > bar
14566 *
14567 * $ ruby argf.rb foo bar
14568 *
14569 * ARGF.file #=> #<File:foo>
14570 * ARGF.read(5) #=> "foo\nb"
14571 * ARGF.file #=> #<File:bar>
14572 */
14573static VALUE
14574argf_file(VALUE argf)
14575{
14576 next_argv();
14577 return ARGF.current_file;
14578}
14579
14580/*
14581 * call-seq:
14582 * ARGF.binmode -> ARGF
14583 *
14584 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14585 * be reset to non-binary mode. This option has the following effects:
14586 *
14587 * * Newline conversion is disabled.
14588 * * Encoding conversion is disabled.
14589 * * Content is treated as ASCII-8BIT.
14590 */
14591static VALUE
14592argf_binmode_m(VALUE argf)
14593{
14594 ARGF.binmode = 1;
14595 next_argv();
14596 ARGF_FORWARD(0, 0);
14597 rb_io_ascii8bit_binmode(ARGF.current_file);
14598 return argf;
14599}
14600
14601/*
14602 * call-seq:
14603 * ARGF.binmode? -> true or false
14604 *
14605 * Returns true if ARGF is being read in binary mode; false otherwise.
14606 * To enable binary mode use ARGF.binmode.
14607 *
14608 * For example:
14609 *
14610 * ARGF.binmode? #=> false
14611 * ARGF.binmode
14612 * ARGF.binmode? #=> true
14613 */
14614static VALUE
14615argf_binmode_p(VALUE argf)
14616{
14617 return RBOOL(ARGF.binmode);
14618}
14619
14620/*
14621 * call-seq:
14622 * ARGF.skip -> ARGF
14623 *
14624 * Sets the current file to the next file in ARGV. If there aren't any more
14625 * files it has no effect.
14626 *
14627 * For example:
14628 *
14629 * $ ruby argf.rb foo bar
14630 * ARGF.filename #=> "foo"
14631 * ARGF.skip
14632 * ARGF.filename #=> "bar"
14633 */
14634static VALUE
14635argf_skip(VALUE argf)
14636{
14637 if (ARGF.init_p && ARGF.next_p == 0) {
14638 argf_close(argf);
14639 ARGF.next_p = 1;
14640 }
14641 return argf;
14642}
14643
14644/*
14645 * call-seq:
14646 * ARGF.close -> ARGF
14647 *
14648 * Closes the current file and skips to the next file in ARGV. If there are
14649 * no more files to open, just closes the current file. STDIN will not be
14650 * closed.
14651 *
14652 * For example:
14653 *
14654 * $ ruby argf.rb foo bar
14655 *
14656 * ARGF.filename #=> "foo"
14657 * ARGF.close
14658 * ARGF.filename #=> "bar"
14659 * ARGF.close
14660 */
14661static VALUE
14662argf_close_m(VALUE argf)
14663{
14664 next_argv();
14665 argf_close(argf);
14666 if (ARGF.next_p != -1) {
14667 ARGF.next_p = 1;
14668 }
14669 ARGF.lineno = 0;
14670 return argf;
14671}
14672
14673/*
14674 * call-seq:
14675 * ARGF.closed? -> true or false
14676 *
14677 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14678 * ARGF.close to actually close the current file.
14679 */
14680static VALUE
14681argf_closed(VALUE argf)
14682{
14683 next_argv();
14684 ARGF_FORWARD(0, 0);
14685 return rb_io_closed_p(ARGF.current_file);
14686}
14687
14688/*
14689 * call-seq:
14690 * ARGF.to_s -> String
14691 *
14692 * Returns "ARGF".
14693 */
14694static VALUE
14695argf_to_s(VALUE argf)
14696{
14697 return rb_str_new2("ARGF");
14698}
14699
14700/*
14701 * call-seq:
14702 * ARGF.inplace_mode -> String
14703 *
14704 * Returns the file extension appended to the names of backup copies of
14705 * modified files under in-place edit mode. This value can be set using
14706 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14707 */
14708static VALUE
14709argf_inplace_mode_get(VALUE argf)
14710{
14711 if (!ARGF.inplace) return Qnil;
14712 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14713 return rb_str_dup(ARGF.inplace);
14714}
14715
14716static VALUE
14717opt_i_get(ID id, VALUE *var)
14718{
14719 return argf_inplace_mode_get(*var);
14720}
14721
14722/*
14723 * call-seq:
14724 * ARGF.inplace_mode = ext -> ARGF
14725 *
14726 * Sets the filename extension for in-place editing mode to the given String.
14727 * The backup copy of each file being edited has this value appended to its
14728 * filename.
14729 *
14730 * For example:
14731 *
14732 * $ ruby argf.rb file.txt
14733 *
14734 * ARGF.inplace_mode = '.bak'
14735 * ARGF.each_line do |line|
14736 * print line.sub("foo","bar")
14737 * end
14738 *
14739 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14740 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14741 * "bar".
14742 */
14743static VALUE
14744argf_inplace_mode_set(VALUE argf, VALUE val)
14745{
14746 if (!RTEST(val)) {
14747 ARGF.inplace = Qfalse;
14748 }
14749 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14750 ARGF.inplace = Qnil;
14751 }
14752 else {
14753 ARGF_SET(inplace, rb_str_new_frozen(val));
14754 }
14755 return argf;
14756}
14757
14758static void
14759opt_i_set(VALUE val, ID id, VALUE *var)
14760{
14761 argf_inplace_mode_set(*var, val);
14762}
14763
14764void
14765ruby_set_inplace_mode(const char *suffix)
14766{
14767 ARGF_SET(inplace, !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix)));
14768}
14769
14770/*
14771 * call-seq:
14772 * ARGF.argv -> ARGV
14773 *
14774 * Returns the +ARGV+ array, which contains the arguments passed to your
14775 * script, one per element.
14776 *
14777 * For example:
14778 *
14779 * $ ruby argf.rb -v glark.txt
14780 *
14781 * ARGF.argv #=> ["-v", "glark.txt"]
14782 *
14783 */
14784static VALUE
14785argf_argv(VALUE argf)
14786{
14787 return ARGF.argv;
14788}
14789
14790static VALUE
14791argf_argv_getter(ID id, VALUE *var)
14792{
14793 return argf_argv(*var);
14794}
14795
14796VALUE
14798{
14799 return ARGF.argv;
14800}
14801
14802/*
14803 * call-seq:
14804 * ARGF.to_write_io -> io
14805 *
14806 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14807 * enabled.
14808 */
14809static VALUE
14810argf_write_io(VALUE argf)
14811{
14812 if (!RTEST(ARGF.current_file)) {
14813 rb_raise(rb_eIOError, "not opened for writing");
14814 }
14815 return GetWriteIO(ARGF.current_file);
14816}
14817
14818/*
14819 * call-seq:
14820 * ARGF.write(*objects) -> integer
14821 *
14822 * Writes each of the given +objects+ if inplace mode.
14823 */
14824static VALUE
14825argf_write(int argc, VALUE *argv, VALUE argf)
14826{
14827 return rb_io_writev(argf_write_io(argf), argc, argv);
14828}
14829
14830void
14831rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14832{
14833 rb_readwrite_syserr_fail(waiting, errno, mesg);
14834}
14835
14836void
14837rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14838{
14839 VALUE arg, c = Qnil;
14840 arg = mesg ? rb_str_new2(mesg) : Qnil;
14841 switch (waiting) {
14842 case RB_IO_WAIT_WRITABLE:
14843 switch (n) {
14844 case EAGAIN:
14845 c = rb_eEAGAINWaitWritable;
14846 break;
14847#if EAGAIN != EWOULDBLOCK
14848 case EWOULDBLOCK:
14849 c = rb_eEWOULDBLOCKWaitWritable;
14850 break;
14851#endif
14852 case EINPROGRESS:
14853 c = rb_eEINPROGRESSWaitWritable;
14854 break;
14855 default:
14857 }
14858 break;
14859 case RB_IO_WAIT_READABLE:
14860 switch (n) {
14861 case EAGAIN:
14862 c = rb_eEAGAINWaitReadable;
14863 break;
14864#if EAGAIN != EWOULDBLOCK
14865 case EWOULDBLOCK:
14866 c = rb_eEWOULDBLOCKWaitReadable;
14867 break;
14868#endif
14869 case EINPROGRESS:
14870 c = rb_eEINPROGRESSWaitReadable;
14871 break;
14872 default:
14874 }
14875 break;
14876 default:
14877 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14878 }
14880}
14881
14882static VALUE
14883get_LAST_READ_LINE(ID _x, VALUE *_y)
14884{
14885 return rb_lastline_get();
14886}
14887
14888static void
14889set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14890{
14891 rb_lastline_set(val);
14892}
14893
14894/*
14895 * Document-class: IOError
14896 *
14897 * Raised when an IO operation fails.
14898 *
14899 * File.open("/etc/hosts") {|f| f << "example"}
14900 * #=> IOError: not opened for writing
14901 *
14902 * File.open("/etc/hosts") {|f| f.close; f.read }
14903 * #=> IOError: closed stream
14904 *
14905 * Note that some IO failures raise <code>SystemCallError</code>s
14906 * and these are not subclasses of IOError:
14907 *
14908 * File.open("does/not/exist")
14909 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14910 */
14911
14912/*
14913 * Document-class: EOFError
14914 *
14915 * Raised by some IO operations when reaching the end of file. Many IO
14916 * methods exist in two forms,
14917 *
14918 * one that returns +nil+ when the end of file is reached, the other
14919 * raises EOFError.
14920 *
14921 * EOFError is a subclass of IOError.
14922 *
14923 * file = File.open("/etc/hosts")
14924 * file.read
14925 * file.gets #=> nil
14926 * file.readline #=> EOFError: end of file reached
14927 * file.close
14928 */
14929
14930/*
14931 * Document-class: ARGF
14932 *
14933 * == \ARGF and +ARGV+
14934 *
14935 * The \ARGF object works with the array at global variable +ARGV+
14936 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14937 *
14938 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14939 *
14940 * Initially, it contains the command-line arguments and options
14941 * that are passed to the Ruby program;
14942 * the program can modify that array as it likes.
14943 *
14944 * - **ARGF** may be thought of as the <b>argument files</b> object.
14945 *
14946 * It can access file streams and/or the <tt>$stdin</tt> stream,
14947 * based on what it finds in +ARGV+.
14948 * This provides a convenient way for the command line
14949 * to specify streams for a Ruby program to read.
14950 *
14951 * == Reading
14952 *
14953 * \ARGF may read from _source_ streams,
14954 * which at any particular time are determined by the content of +ARGV+.
14955 *
14956 * === Simplest Case
14957 *
14958 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14959 * the source is <tt>$stdin</tt>:
14960 *
14961 * - \File +t.rb+:
14962 *
14963 * p ['ARGV', ARGV]
14964 * p ['ARGF.read', ARGF.read]
14965 *
14966 * - Commands and outputs
14967 * (see below for the content of files +foo.txt+ and +bar.txt+):
14968 *
14969 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14970 * ["ARGV", []]
14971 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14972 *
14973 * $ cat foo.txt bar.txt | ruby t.rb
14974 * ["ARGV", []]
14975 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14976 *
14977 * === About the Examples
14978 *
14979 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14980 *
14981 * $ cat foo.txt
14982 * Foo 0
14983 * Foo 1
14984 * $ cat bar.txt
14985 * Bar 0
14986 * Bar 1
14987 * Bar 2
14988 * Bar 3
14989 *
14990 * === Sources in +ARGV+
14991 *
14992 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14993 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14994 * the sources are found in +ARGV+.
14995 *
14996 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14997 * and is one of:
14998 *
14999 * - The string path to a file that may be opened as a stream.
15000 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
15001 *
15002 * Each element that is _not_ one of these
15003 * should be removed from +ARGV+ before \ARGF accesses that source.
15004 *
15005 * In the following example:
15006 *
15007 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
15008 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
15009 *
15010 * Example:
15011 *
15012 * - \File +t.rb+:
15013 *
15014 * # Print arguments (and options, if any) found on command line.
15015 * p ['ARGV', ARGV]
15016 *
15017 * - Command and output:
15018 *
15019 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
15020 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
15021 *
15022 * \ARGF's stream access considers the elements of +ARGV+, left to right:
15023 *
15024 * - \File +t.rb+:
15025 *
15026 * p "ARGV: #{ARGV}"
15027 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
15028 *
15029 * - Command and output:
15030 *
15031 * $ ruby t.rb foo.txt bar.txt
15032 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15033 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15034 *
15035 * Because the value at +ARGV+ is an ordinary array,
15036 * you can manipulate it to control which sources \ARGF considers:
15037 *
15038 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
15039 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
15040 *
15041 * Each element in +ARGV+ is removed when its corresponding source is accessed;
15042 * when all sources have been accessed, the array is empty:
15043 *
15044 * - \File +t.rb+:
15045 *
15046 * until ARGV.empty? && ARGF.eof?
15047 * p "ARGV: #{ARGV}"
15048 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
15049 * end
15050 *
15051 * - Command and output:
15052 *
15053 * $ ruby t.rb foo.txt bar.txt
15054 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15055 * "Line: Foo 0\n"
15056 * "ARGV: [\"bar.txt\"]"
15057 * "Line: Foo 1\n"
15058 * "ARGV: [\"bar.txt\"]"
15059 * "Line: Bar 0\n"
15060 * "ARGV: []"
15061 * "Line: Bar 1\n"
15062 * "ARGV: []"
15063 * "Line: Bar 2\n"
15064 * "ARGV: []"
15065 * "Line: Bar 3\n"
15066 *
15067 * ==== Filepaths in +ARGV+
15068 *
15069 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
15070 *
15071 * This program prints what it reads from files at the paths specified
15072 * on the command line:
15073 *
15074 * - \File +t.rb+:
15075 *
15076 * p ['ARGV', ARGV]
15077 * # Read and print all content from the specified sources.
15078 * p ['ARGF.read', ARGF.read]
15079 *
15080 * - Command and output:
15081 *
15082 * $ ruby t.rb foo.txt bar.txt
15083 * ["ARGV", [foo.txt, bar.txt]
15084 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
15085 *
15086 * ==== Specifying <tt>$stdin</tt> in +ARGV+
15087 *
15088 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
15089 *
15090 * - \File +t.rb+:
15091 *
15092 * p ['ARGV', ARGV]
15093 * p ['ARGF.read', ARGF.read]
15094 *
15095 * - Command and output:
15096 *
15097 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
15098 * ["ARGV", ["-"]]
15099 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15100 *
15101 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored.
15102 *
15103 * - Command and output:
15104 *
15105 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
15106 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15107 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15108 *
15109 * ==== Mixtures and Repetitions in +ARGV+
15110 *
15111 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
15112 * and character <tt>'-'</tt>, including repetitions.
15113 *
15114 * ==== Modifications to +ARGV+
15115 *
15116 * The running Ruby program may make any modifications to the +ARGV+ array;
15117 * the current value of +ARGV+ affects \ARGF reading.
15118 *
15119 * ==== Empty +ARGV+
15120 *
15121 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15122 * or raises an exception, depending on the specific method.
15123 *
15124 * === More Read Methods
15125 *
15126 * As seen above, method ARGF#read reads the content of all sources
15127 * into a single string.
15128 * Other \ARGF methods provide other ways to access that content;
15129 * these include:
15130 *
15131 * - Byte access: #each_byte, #getbyte, #readbyte.
15132 * - Character access: #each_char, #getc, #readchar.
15133 * - Codepoint access: #each_codepoint.
15134 * - Line access: #each_line, #gets, #readline, #readlines.
15135 * - Source access: #read, #read_nonblock, #readpartial.
15136 *
15137 * === About \Enumerable
15138 *
15139 * \ARGF includes module Enumerable.
15140 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15141 *
15142 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15143 * _not_ from +ARGV+;
15144 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15145 * not an array of the strings from +ARGV+:
15146 *
15147 * - \File +t.rb+:
15148 *
15149 * p ['ARGV', ARGV]
15150 * p ['ARGF.entries', ARGF.entries]
15151 *
15152 * - Command and output:
15153 *
15154 * $ ruby t.rb foo.txt bar.txt
15155 * ["ARGV", ["foo.txt", "bar.txt"]]
15156 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15157 *
15158 * == Writing
15159 *
15160 * If <i>inplace mode</i> is in effect,
15161 * \ARGF may write to target streams,
15162 * which at any particular time are determined by the content of ARGV.
15163 *
15164 * Methods about inplace mode:
15165 *
15166 * - #inplace_mode
15167 * - #inplace_mode=
15168 * - #to_write_io
15169 *
15170 * Methods for writing:
15171 *
15172 * - #print
15173 * - #printf
15174 * - #putc
15175 * - #puts
15176 * - #write
15177 *
15178 */
15179
15180/*
15181 * An instance of class \IO (commonly called a _stream_)
15182 * represents an input/output stream in the underlying operating system.
15183 * Class \IO is the basis for input and output in Ruby.
15184 *
15185 * Class File is the only class in the Ruby core that is a subclass of \IO.
15186 * Some classes in the Ruby standard library are also subclasses of \IO;
15187 * these include TCPSocket and UDPSocket.
15188 *
15189 * The global constant ARGF (also accessible as <tt>$<</tt>)
15190 * provides an IO-like stream that allows access to all file paths
15191 * found in ARGV (or found in STDIN if ARGV is empty).
15192 * ARGF is not itself a subclass of \IO.
15193 *
15194 * Class StringIO provides an IO-like stream that handles a String.
15195 * StringIO is not itself a subclass of \IO.
15196 *
15197 * Important objects based on \IO include:
15198 *
15199 * - $stdin.
15200 * - $stdout.
15201 * - $stderr.
15202 * - Instances of class File.
15203 *
15204 * An instance of \IO may be created using:
15205 *
15206 * - IO.new: returns a new \IO object for the given integer file descriptor.
15207 * - IO.open: passes a new \IO object to the given block.
15208 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15209 * of a newly-launched subprocess.
15210 * - Kernel#open: Returns a new \IO object connected to a given source:
15211 * stream, file, or subprocess.
15212 *
15213 * Like a File stream, an \IO stream has:
15214 *
15215 * - A read/write mode, which may be read-only, write-only, or read/write;
15216 * see {Read/Write Mode}[rdoc-ref:File@ReadWrite+Mode].
15217 * - A data mode, which may be text-only or binary;
15218 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15219 * - Internal and external encodings;
15220 * see {Encodings}[rdoc-ref:File@Encodings].
15221 *
15222 * And like other \IO streams, it has:
15223 *
15224 * - A position, which determines where in the stream the next
15225 * read or write is to occur;
15226 * see {Position}[rdoc-ref:IO@Position].
15227 * - A line number, which is a special, line-oriented, "position"
15228 * (different from the position mentioned above);
15229 * see {Line Number}[rdoc-ref:IO@Line+Number].
15230 *
15231 * == Extension <tt>io/console</tt>
15232 *
15233 * Extension <tt>io/console</tt> provides numerous methods
15234 * for interacting with the console;
15235 * requiring it adds numerous methods to class \IO.
15236 *
15237 * == Example Files
15238 *
15239 * Many examples here use these variables:
15240 *
15241 * :include: doc/examples/files.rdoc
15242 *
15243 * == Open Options
15244 *
15245 * A number of \IO methods accept optional keyword arguments
15246 * that determine how a new stream is to be opened:
15247 *
15248 * - +:mode+: Stream mode.
15249 * - +:flags+: Integer file open flags;
15250 * If +mode+ is also given, the two are bitwise-ORed.
15251 * - +:external_encoding+: External encoding for the stream.
15252 * - +:internal_encoding+: Internal encoding for the stream.
15253 * <tt>'-'</tt> is a synonym for the default internal encoding.
15254 * If the value is +nil+ no conversion occurs.
15255 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15256 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15257 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15258 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15259 * when the stream closes; otherwise it remains open.
15260 * - +:path+: If a string value is provided, it is used in #inspect and is available as
15261 * #path method.
15262 *
15263 * Also available are the options offered in String#encode,
15264 * which may control conversion between external and internal encoding.
15265 *
15266 * == Basic \IO
15267 *
15268 * You can perform basic stream \IO with these methods,
15269 * which typically operate on multi-byte strings:
15270 *
15271 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15272 * - IO#write: Writes zero or more strings to the stream;
15273 * each given object that is not already a string is converted via +to_s+.
15274 *
15275 * === Position
15276 *
15277 * An \IO stream has a nonnegative integer _position_,
15278 * which is the byte offset at which the next read or write is to occur.
15279 * A new stream has position zero (and line number zero);
15280 * method +rewind+ resets the position (and line number) to zero.
15281 *
15282 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15283 * Encoding::Converter instances used for that \IO.
15284 *
15285 * The relevant methods:
15286 *
15287 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15288 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15289 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15290 * relative to a given position +whence+
15291 * (indicating the beginning, end, or current position).
15292 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15293 *
15294 * === Open and Closed Streams
15295 *
15296 * A new \IO stream may be open for reading, open for writing, or both.
15297 *
15298 * A stream is automatically closed when claimed by the garbage collector.
15299 *
15300 * Attempted reading or writing on a closed stream raises an exception.
15301 *
15302 * The relevant methods:
15303 *
15304 * - IO#close: Closes the stream for both reading and writing.
15305 * - IO#close_read: Closes the stream for reading.
15306 * - IO#close_write: Closes the stream for writing.
15307 * - IO#closed?: Returns whether the stream is closed.
15308 *
15309 * === End-of-Stream
15310 *
15311 * You can query whether a stream is positioned at its end:
15312 *
15313 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15314 *
15315 * You can reposition to end-of-stream by using method IO#seek:
15316 *
15317 * f = File.new('t.txt')
15318 * f.eof? # => false
15319 * f.seek(0, :END)
15320 * f.eof? # => true
15321 * f.close
15322 *
15323 * Or by reading all stream content (which is slower than using IO#seek):
15324 *
15325 * f.rewind
15326 * f.eof? # => false
15327 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15328 * f.eof? # => true
15329 *
15330 * == Line \IO
15331 *
15332 * Class \IO supports line-oriented
15333 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15334 *
15335 * === Line Input
15336 *
15337 * Class \IO supports line-oriented input for
15338 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input].
15339 *
15340 * ==== Line Input Options
15341 *
15342 * Optional keyword argument +chomp+ (default: +false+)
15343 * specifies whether line separators are to be excluded from the result of a read.
15344 *
15345 * ==== \File Line Input
15346 *
15347 * You can read lines from a file using these methods:
15348 *
15349 * - IO.foreach: Reads each line and passes it to the given block.
15350 * - IO.readlines: Reads and returns all lines in an array.
15351 *
15352 * For each of these methods:
15353 *
15354 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15355 * - Line parsing depends on the effective <i>line separator</i>;
15356 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15357 * - The length of each returned line depends on the effective <i>line limit</i>;
15358 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15359 *
15360 * ==== Stream Line Input
15361 *
15362 * You can read lines from an \IO stream using these methods:
15363 *
15364 * - IO#each_line: Reads each remaining line, passing it to the given block.
15365 * - IO#gets: Returns the next line.
15366 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15367 * - IO#readlines: Returns all remaining lines in an array.
15368 *
15369 * For each of these methods:
15370 *
15371 * - Reading may begin mid-line,
15372 * depending on the stream's _position_;
15373 * see {Position}[rdoc-ref:IO@Position].
15374 * - Line parsing depends on the effective <i>line separator</i>;
15375 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15376 * - The length of each returned line depends on the effective <i>line limit</i>;
15377 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15378 *
15379 * ===== Line Separator
15380 *
15381 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15382 * the string that determines what is considered a line;
15383 * it is sometimes called the <i>input record separator</i>.
15384 *
15385 * The default line separator is taken from global variable <tt>$/</tt>,
15386 * whose initial value is <tt>"\n"</tt>.
15387 *
15388 * Generally, the line to be read next is all data
15389 * from the current {position}[rdoc-ref:IO@Position]
15390 * to the next line separator
15391 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15392 *
15393 * f = File.new('t.txt')
15394 * # Method gets with no sep argument returns the next line, according to $/.
15395 * f.gets # => "First line\n"
15396 * f.gets # => "Second line\n"
15397 * f.gets # => "\n"
15398 * f.gets # => "Fourth line\n"
15399 * f.gets # => "Fifth line\n"
15400 * f.close
15401 *
15402 * You can use a different line separator by passing argument +sep+:
15403 *
15404 * f = File.new('t.txt')
15405 * f.gets('l') # => "First l"
15406 * f.gets('li') # => "ine\nSecond li"
15407 * f.gets('lin') # => "ne\n\nFourth lin"
15408 * f.gets # => "e\n"
15409 * f.close
15410 *
15411 * Or by setting global variable <tt>$/</tt>:
15412 *
15413 * f = File.new('t.txt')
15414 * $/ = 'l'
15415 * f.gets # => "First l"
15416 * f.gets # => "ine\nSecond l"
15417 * f.gets # => "ine\n\nFourth l"
15418 * f.close
15419 *
15420 * ===== Special Line Separator Values
15421 *
15422 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15423 * accepts two special values for parameter +sep+:
15424 *
15425 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15426 *
15427 * f = File.new('t.txt')
15428 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15429 * f.close
15430 *
15431 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15432 * (paragraphs being separated by two consecutive line separators):
15433 *
15434 * f = File.new('t.txt')
15435 * f.gets('') # => "First line\nSecond line\n\n"
15436 * f.gets('') # => "Fourth line\nFifth line\n"
15437 * f.close
15438 *
15439 * ===== Line Limit
15440 *
15441 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15442 * uses an integer <i>line limit</i>,
15443 * which restricts the number of bytes that may be returned.
15444 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15445 * than the limit).
15446 *
15447 * The default limit value is <tt>-1</tt>;
15448 * any negative limit value means that there is no limit.
15449 *
15450 * If there is no limit, the line is determined only by +sep+.
15451 *
15452 * # Text with 1-byte characters.
15453 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15454 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15455 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15456 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15457 * # No more than one line.
15458 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15459 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15460 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15461 *
15462 * # Text with 3-byte characters, which will not be split.
15463 * File.read('t.ja') # => "こんにちは"
15464 * File.open('t.ja') {|f| f.gets(1).size } # => 1
15465 * File.open('t.ja') {|f| f.gets(2).size } # => 1
15466 * File.open('t.ja') {|f| f.gets(3).size } # => 1
15467 * File.open('t.ja') {|f| f.gets(4).size } # => 2
15468 * File.open('t.ja') {|f| f.gets(5).size } # => 2
15469 *
15470 * ===== Line Separator and Line Limit
15471 *
15472 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15473 *
15474 * - Returns the next line as determined by line separator +sep+.
15475 * - But returns no more bytes than are allowed by the limit +limit+.
15476 *
15477 * Example:
15478 *
15479 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15480 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15481 *
15482 * ===== Line Number
15483 *
15484 * A readable \IO stream has a non-negative integer <i>line number</i>:
15485 *
15486 * - IO#lineno: Returns the line number.
15487 * - IO#lineno=: Resets and returns the line number.
15488 *
15489 * Unless modified by a call to method IO#lineno=,
15490 * the line number is the number of lines read
15491 * by certain line-oriented methods,
15492 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15493 *
15494 * - IO.foreach: Increments the line number on each call to the block.
15495 * - IO#each_line: Increments the line number on each call to the block.
15496 * - IO#gets: Increments the line number.
15497 * - IO#readline: Increments the line number.
15498 * - IO#readlines: Increments the line number for each line read.
15499 *
15500 * A new stream is initially has line number zero (and position zero);
15501 * method +rewind+ resets the line number (and position) to zero:
15502 *
15503 * f = File.new('t.txt')
15504 * f.lineno # => 0
15505 * f.gets # => "First line\n"
15506 * f.lineno # => 1
15507 * f.rewind
15508 * f.lineno # => 0
15509 * f.close
15510 *
15511 * Reading lines from a stream usually changes its line number:
15512 *
15513 * f = File.new('t.txt', 'r')
15514 * f.lineno # => 0
15515 * f.readline # => "This is line one.\n"
15516 * f.lineno # => 1
15517 * f.readline # => "This is the second line.\n"
15518 * f.lineno # => 2
15519 * f.readline # => "Here's the third line.\n"
15520 * f.lineno # => 3
15521 * f.eof? # => true
15522 * f.close
15523 *
15524 * Iterating over lines in a stream usually changes its line number:
15525 *
15526 * File.open('t.txt') do |f|
15527 * f.each_line do |line|
15528 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15529 * end
15530 * end
15531 *
15532 * Output:
15533 *
15534 * "position=11 eof?=false lineno=1"
15535 * "position=23 eof?=false lineno=2"
15536 * "position=24 eof?=false lineno=3"
15537 * "position=36 eof?=false lineno=4"
15538 * "position=47 eof?=true lineno=5"
15539 *
15540 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15541 * the line number does not affect where the next read or write will occur:
15542 *
15543 * f = File.new('t.txt')
15544 * f.lineno = 1000
15545 * f.lineno # => 1000
15546 * f.gets # => "First line\n"
15547 * f.lineno # => 1001
15548 * f.close
15549 *
15550 * Associated with the line number is the global variable <tt>$.</tt>:
15551 *
15552 * - When a stream is opened, <tt>$.</tt> is not set;
15553 * its value is left over from previous activity in the process:
15554 *
15555 * $. = 41
15556 * f = File.new('t.txt')
15557 * $. = 41
15558 * # => 41
15559 * f.close
15560 *
15561 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15562 *
15563 * f0 = File.new('t.txt')
15564 * f1 = File.new('t.dat')
15565 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15566 * $. # => 5
15567 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15568 * $. # => 1
15569 * f0.close
15570 * f1.close
15571 *
15572 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15573 *
15574 * f = File.new('t.txt')
15575 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15576 * $. # => 5
15577 * f.rewind
15578 * f.seek(0, :SET)
15579 * $. # => 5
15580 * f.close
15581 *
15582 * === Line Output
15583 *
15584 * You can write to an \IO stream line-by-line using this method:
15585 *
15586 * - IO#puts: Writes objects to the stream.
15587 *
15588 * == Character \IO
15589 *
15590 * You can process an \IO stream character-by-character using these methods:
15591 *
15592 * - IO#getc: Reads and returns the next character from the stream.
15593 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15594 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15595 * - IO#putc: Writes a character to the stream.
15596 * - IO#each_char: Reads each remaining character in the stream,
15597 * passing the character to the given block.
15598 *
15599 * == Byte \IO
15600 *
15601 * You can process an \IO stream byte-by-byte using these methods:
15602 *
15603 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15604 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15605 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15606 * - IO#each_byte: Reads each remaining byte in the stream,
15607 * passing the byte to the given block.
15608 *
15609 * == Codepoint \IO
15610 *
15611 * You can process an \IO stream codepoint-by-codepoint:
15612 *
15613 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15614 *
15615 * == What's Here
15616 *
15617 * First, what's elsewhere. Class \IO:
15618 *
15619 * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
15620 * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
15621 * which provides dozens of additional methods.
15622 *
15623 * Here, class \IO provides methods that are useful for:
15624 *
15625 * - {Creating}[rdoc-ref:IO@Creating]
15626 * - {Reading}[rdoc-ref:IO@Reading]
15627 * - {Writing}[rdoc-ref:IO@Writing]
15628 * - {Positioning}[rdoc-ref:IO@Positioning]
15629 * - {Iterating}[rdoc-ref:IO@Iterating]
15630 * - {Settings}[rdoc-ref:IO@Settings]
15631 * - {Querying}[rdoc-ref:IO@Querying]
15632 * - {Buffering}[rdoc-ref:IO@Buffering]
15633 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15634 * - {Other}[rdoc-ref:IO@Other]
15635 *
15636 * === Creating
15637 *
15638 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15639 * integer file descriptor.
15640 * - ::open: Creates a new \IO object.
15641 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15642 * - ::popen: Creates an \IO object to interact with a subprocess.
15643 * - ::select: Selects which given \IO instances are ready for reading,
15644 * writing, or have pending exceptions.
15645 *
15646 * === Reading
15647 *
15648 * - ::binread: Returns a binary string with all or a subset of bytes
15649 * from the given file.
15650 * - ::read: Returns a string with all or a subset of bytes from the given file.
15651 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15652 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15653 * - #getc: Returns the next character read from +self+ as a string.
15654 * - #gets: Returns the line read from +self+.
15655 * - #pread: Returns all or the next _n_ bytes read from +self+,
15656 * not updating the receiver's offset.
15657 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15658 * for a given _n_.
15659 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15660 * in non-block mode.
15661 * - #readbyte: Returns the next byte read from +self+;
15662 * same as #getbyte, but raises an exception on end-of-stream.
15663 * - #readchar: Returns the next character read from +self+;
15664 * same as #getc, but raises an exception on end-of-stream.
15665 * - #readline: Returns the next line read from +self+;
15666 * same as #getline, but raises an exception of end-of-stream.
15667 * - #readlines: Returns an array of all lines read read from +self+.
15668 * - #readpartial: Returns up to the given number of bytes from +self+.
15669 *
15670 * === Writing
15671 *
15672 * - ::binwrite: Writes the given string to the file at the given filepath,
15673 * in binary mode.
15674 * - ::write: Writes the given string to +self+.
15675 * - #<<: Appends the given string to +self+.
15676 * - #print: Prints last read line or given objects to +self+.
15677 * - #printf: Writes to +self+ based on the given format string and objects.
15678 * - #putc: Writes a character to +self+.
15679 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15680 * - #pwrite: Writes the given string at the given offset,
15681 * not updating the receiver's offset.
15682 * - #write: Writes one or more given strings to +self+.
15683 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15684 *
15685 * === Positioning
15686 *
15687 * - #lineno: Returns the current line number in +self+.
15688 * - #lineno=: Sets the line number is +self+.
15689 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15690 * - #pos=: Sets the byte offset in +self+.
15691 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15692 * - #rewind: Positions +self+ to the beginning of input.
15693 * - #seek: Sets the offset for +self+ relative to given position.
15694 *
15695 * === Iterating
15696 *
15697 * - ::foreach: Yields each line of given file to the block.
15698 * - #each (aliased as #each_line): Calls the given block
15699 * with each successive line in +self+.
15700 * - #each_byte: Calls the given block with each successive byte in +self+
15701 * as an integer.
15702 * - #each_char: Calls the given block with each successive character in +self+
15703 * as a string.
15704 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15705 * as an integer.
15706 *
15707 * === Settings
15708 *
15709 * - #autoclose=: Sets whether +self+ auto-closes.
15710 * - #binmode: Sets +self+ to binary mode.
15711 * - #close: Closes +self+.
15712 * - #close_on_exec=: Sets the close-on-exec flag.
15713 * - #close_read: Closes +self+ for reading.
15714 * - #close_write: Closes +self+ for writing.
15715 * - #set_encoding: Sets the encoding for +self+.
15716 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15717 * Unicode byte-order-mark.
15718 * - #sync=: Sets the sync-mode to the given value.
15719 *
15720 * === Querying
15721 *
15722 * - #autoclose?: Returns whether +self+ auto-closes.
15723 * - #binmode?: Returns whether +self+ is in binary mode.
15724 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15725 * - #closed?: Returns whether +self+ is closed.
15726 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15727 * - #external_encoding: Returns the external encoding object for +self+.
15728 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15729 * - #internal_encoding: Returns the internal encoding object for +self+.
15730 * - #pid: Returns the process ID of a child process associated with +self+,
15731 * if +self+ was created by ::popen.
15732 * - #stat: Returns the File::Stat object containing status information for +self+.
15733 * - #sync: Returns whether +self+ is in sync-mode.
15734 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15735 *
15736 * === Buffering
15737 *
15738 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15739 * - #flush: Flushes any buffered data within +self+ to the underlying
15740 * operating system.
15741 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15742 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15743 * - #ungetc: Prepends buffer for +self+ with given string.
15744 *
15745 * === Low-Level Access
15746 *
15747 * - ::sysopen: Opens the file given by its path,
15748 * returning the integer file descriptor.
15749 * - #advise: Announces the intention to access data from +self+ in a specific way.
15750 * - #fcntl: Passes a low-level command to the file specified
15751 * by the given file descriptor.
15752 * - #ioctl: Passes a low-level command to the device specified
15753 * by the given file descriptor.
15754 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15755 * - #sysseek: Sets the offset for +self+.
15756 * - #syswrite: Writes the given string to +self+ using a low-level write.
15757 *
15758 * === Other
15759 *
15760 * - ::copy_stream: Copies data from a source to a destination,
15761 * each of which is a filepath or an \IO-like object.
15762 * - ::try_convert: Returns a new \IO object resulting from converting
15763 * the given object.
15764 * - #inspect: Returns the string representation of +self+.
15765 *
15766 */
15767
15768void
15769Init_IO(void)
15770{
15771 VALUE rb_cARGF;
15772#ifdef __CYGWIN__
15773#include <sys/cygwin.h>
15774 static struct __cygwin_perfile pf[] =
15775 {
15776 {"", O_RDONLY | O_BINARY},
15777 {"", O_WRONLY | O_BINARY},
15778 {"", O_RDWR | O_BINARY},
15779 {"", O_APPEND | O_BINARY},
15780 {NULL, 0}
15781 };
15782 cygwin_internal(CW_PERFILE, pf);
15783#endif
15784
15785 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
15786 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
15787
15788 id_write = rb_intern_const("write");
15789 id_read = rb_intern_const("read");
15790 id_flush = rb_intern_const("flush");
15791 id_readpartial = rb_intern_const("readpartial");
15792 id_set_encoding = rb_intern_const("set_encoding");
15793 id_fileno = rb_intern_const("fileno");
15794
15795 rb_define_global_function("syscall", rb_f_syscall, -1);
15796
15797 rb_define_global_function("open", rb_f_open, -1);
15798 rb_define_global_function("printf", rb_f_printf, -1);
15799 rb_define_global_function("print", rb_f_print, -1);
15800 rb_define_global_function("putc", rb_f_putc, 1);
15801 rb_define_global_function("puts", rb_f_puts, -1);
15802 rb_define_global_function("gets", rb_f_gets, -1);
15803 rb_define_global_function("readline", rb_f_readline, -1);
15804 rb_define_global_function("select", rb_f_select, -1);
15805
15806 rb_define_global_function("readlines", rb_f_readlines, -1);
15807
15808 rb_define_global_function("`", rb_f_backquote, 1);
15809
15810 rb_define_global_function("p", rb_f_p, -1);
15811 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15812
15813 rb_cIO = rb_define_class("IO", rb_cObject);
15815
15816 /* Can be raised by IO operations when IO#timeout= is set. */
15817 rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
15818
15819 /* Readable event mask for IO#wait. */
15820 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15821 /* Writable event mask for IO#wait. */
15822 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15823 /* Priority event mask for IO#wait. */
15824 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15825
15826 /* exception to wait for reading. see IO.select. */
15827 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
15828 /* exception to wait for writing. see IO.select. */
15829 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
15830 /* exception to wait for reading by EAGAIN. see IO.select. */
15831 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15832 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15833 /* exception to wait for writing by EAGAIN. see IO.select. */
15834 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15835 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15836#if EAGAIN == EWOULDBLOCK
15837 /* same as IO::EAGAINWaitReadable */
15838 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15839 /* same as IO::EAGAINWaitWritable */
15840 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15841#else
15842 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15843 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15844 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15845 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15846 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15847 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15848#endif
15849 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15850 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15851 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15852 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15853 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15854 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15855
15856#if 0
15857 /* This is necessary only for forcing rdoc handle File::open */
15858 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15859#endif
15860
15861 rb_define_alloc_func(rb_cIO, io_alloc);
15862 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15863 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15864 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15865 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15866 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15867 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15868 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15869 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15870 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15871 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15872 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15873 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15874 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15875 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15876 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15877
15878 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15879
15881 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
15882
15883 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15884 rb_vm_register_global_object(rb_default_rs);
15885 rb_rs = rb_default_rs;
15887 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15888 rb_gvar_ractor_local("$/"); // not local but ractor safe
15889 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15890 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15891 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
15892
15893 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15894 rb_gvar_ractor_local("$_");
15895 rb_gvar_box_dynamic("$_");
15896
15897 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15898 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15899
15900 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15901 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15902 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15903 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15904
15905 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15906 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15907 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15908 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15909 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15910
15911 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15912 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15913
15914 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15915 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15916
15917 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15918 rb_define_alias(rb_cIO, "to_i", "fileno");
15919 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15920
15921 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15922 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15923
15924 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15925 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15926 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15927 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15928
15929 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15930 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15931
15932 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15933
15934 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15935 rb_define_method(rb_cIO, "read", io_read, -1);
15936 rb_define_method(rb_cIO, "write", io_write_m, -1);
15937 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15938 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15939 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15940 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15941 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15942 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15943 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15945 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15946 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15947 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15948 /* Set I/O position from the beginning */
15949 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15950 /* Set I/O position from the current position */
15951 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15952 /* Set I/O position from the end */
15953 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15954#ifdef SEEK_DATA
15955 /* Set I/O position to the next location containing data */
15956 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15957#endif
15958#ifdef SEEK_HOLE
15959 /* Set I/O position to the next hole */
15960 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15961#endif
15962 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15963 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15964 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15965 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15966 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15967
15968 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15969 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15970
15971 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15972 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15973 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15974 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15975
15976 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15977 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15978 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15979 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15980 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15981 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15982
15983 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15984 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15985 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15986
15987 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15988 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15989
15990 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15991
15992 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15993 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15994 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15995 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15996
15997 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15998 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15999
16000 rb_define_method(rb_cIO, "wait", io_wait, -1);
16001
16002 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
16003 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
16004 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
16005
16006 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
16007 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
16008 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
16009 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
16010
16011 rb_gvar_ractor_local("$stdin");
16012 rb_gvar_ractor_local("$stdout");
16013 rb_gvar_ractor_local("$>");
16014 rb_gvar_ractor_local("$stderr");
16015
16016 rb_gvar_box_dynamic("$stdin");
16017 rb_gvar_box_dynamic("$stdout");
16018 rb_gvar_box_dynamic("$>");
16019 rb_gvar_box_dynamic("$stderr");
16020
16022 rb_stdin = rb_io_prep_stdin();
16024 rb_stdout = rb_io_prep_stdout();
16026 rb_stderr = rb_io_prep_stderr();
16027
16028 orig_stdout = rb_stdout;
16029 orig_stderr = rb_stderr;
16030
16031 /* Holds the original stdin */
16033 /* Holds the original stdout */
16035 /* Holds the original stderr */
16037
16038#if 0
16039 /* Hack to get rdoc to regard ARGF as a class: */
16040 rb_cARGF = rb_define_class("ARGF", rb_cObject);
16041#endif
16042
16043 rb_cARGF = rb_class_new(rb_cObject);
16044 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
16045 rb_define_alloc_func(rb_cARGF, argf_alloc);
16046
16048
16049 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
16050 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
16051 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
16052 rb_define_alias(rb_cARGF, "inspect", "to_s");
16053 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
16054
16055 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
16056 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
16057 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
16058 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
16059 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
16060 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
16061 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
16062 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
16063 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
16064
16065 rb_define_method(rb_cARGF, "read", argf_read, -1);
16066 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
16067 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
16068 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
16069 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
16070 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
16071 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
16072 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
16073 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
16074 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
16075 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
16076 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
16077 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
16078 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
16079 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
16080 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
16081 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
16082 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
16083 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
16084 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
16085
16086 rb_define_method(rb_cARGF, "write", argf_write, -1);
16087 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
16088 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
16089 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
16090 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
16091
16092 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
16093 rb_define_method(rb_cARGF, "path", argf_filename, 0);
16094 rb_define_method(rb_cARGF, "file", argf_file, 0);
16095 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
16096 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
16097 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
16098
16099 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
16100 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
16101
16102 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
16103 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
16104
16105 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
16106 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
16107 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
16108
16109 argf = rb_class_new_instance(0, 0, rb_cARGF);
16110
16112 /*
16113 * ARGF is a stream designed for use in scripts that process files given
16114 * as command-line arguments or passed in via STDIN.
16115 *
16116 * See ARGF (the class) for more details.
16117 */
16119
16120 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
16121 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
16122 ARGF_SET(filename, rb_str_new2("-"));
16123
16124 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
16125 rb_gvar_ractor_local("$-i");
16126
16127 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16128
16129#if defined (_WIN32) || defined(__CYGWIN__)
16130 atexit(pipe_atexit);
16131#endif
16132
16133 Init_File();
16134
16135 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16136
16137 sym_mode = ID2SYM(rb_intern_const("mode"));
16138 sym_perm = ID2SYM(rb_intern_const("perm"));
16139 sym_flags = ID2SYM(rb_intern_const("flags"));
16140 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16141 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16142 sym_encoding = ID2SYM(rb_id_encoding());
16143 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16144 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16145 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16146 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16147 sym_normal = ID2SYM(rb_intern_const("normal"));
16148 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16149 sym_random = ID2SYM(rb_intern_const("random"));
16150 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16151 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16152 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16153 sym_SET = ID2SYM(rb_intern_const("SET"));
16154 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16155 sym_END = ID2SYM(rb_intern_const("END"));
16156#ifdef SEEK_DATA
16157 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16158#endif
16159#ifdef SEEK_HOLE
16160 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16161#endif
16162 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16163 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16164}
16165
16166static void init_builtin_io(void);
16167#define Init_builtin_io init_builtin_io
16168#include "io.rbinc"
16169#undef Init_builtin_io
16170
16171void
16172Init_builtin_io(void)
16173{
16174 init_builtin_io();
16175
16176 /* Init_IO is called earlier than `loaded_features` is initialized */
16177 rb_provide("io/wait.rb");
16178 rb_provide("io/wait.so");
16179}
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:117
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1769
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:3090
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:3393
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:3380
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:3169
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1676
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:400
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1684
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h: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 ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:111
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:520
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:109
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition ctype.h:103
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:518
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition transcode.h:538
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:519
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1678
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
void rb_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:478
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:510
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1483
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:4084
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:14837
VALUE rb_eIOError
IOError exception.
Definition io.c:193
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1470
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:4174
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:4090
#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:1473
VALUE rb_eEOFError
EOFError exception.
Definition io.c:192
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14831
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2387
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1471
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:468
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1493
@ 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:3333
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:657
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2251
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2292
VALUE rb_cIO
IO class.
Definition io.c:191
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:2280
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:28
VALUE rb_stdin
STDIN constant.
Definition io.c:207
VALUE rb_stderr
STDERR constant.
Definition io.c:207
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:234
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:555
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:668
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:195
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:196
VALUE rb_obj_freeze(VALUE obj)
Same as RB_OBJ_FREEZE(), but returns the given object.
Definition object.c:1308
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:3314
VALUE rb_cFile
File class.
Definition file.c:190
VALUE rb_stdout
STDOUT constant.
Definition io.c:207
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3327
#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:481
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:469
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
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1379
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3946
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c:844
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:1123
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:1090
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:1081
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:242
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8717
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4406
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:515
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:8850
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2452
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9279
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:5278
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5183
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:413
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:9460
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:287
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:367
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:212
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2794
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
Definition io.c:9259
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:337
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6521
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6475
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5342
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7518
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10548
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:521
VALUE rb_output_fs
The field separator character for outputs, or the $,.
Definition io.c:210
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:7406
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:406
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7413
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5878
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:213
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
Definition load.c:710
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:2149
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:2143
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:3761
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
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:3898
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1499
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1682
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1533
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:1023
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1555
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:2023
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3666
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4368
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3485
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:3840
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:3032
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3348
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3467
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2801
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1755
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1515
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c:1887
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1662
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:1697
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:1645
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:3480
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1691
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1668
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:459
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:2141
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:518
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3683
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:3561
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:691
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:4095
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:890
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:6607
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:873
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:919
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:843
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1131
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:6740
#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:1077
#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:1086
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:1683
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:7223
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:6889
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2993
#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:9506
#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:1744
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:1703
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:194
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:3072
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:7014
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:850
#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:5789
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:879
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:5986
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:948
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:2109
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:1058
#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:885
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3527
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1639
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:9372
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:896
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1110
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:1759
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:858
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1604
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7510
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1544
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:1385
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:1454
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:1442
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:1430
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:2319
#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:1423
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1378
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)
Definition rarray.h:402
#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:14797
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9158
#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:4853
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:242
Definition win32.h:230
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
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.