Ruby 4.1.0dev (2026-09-22 revision d1d487f438cc7e1296b5b60c035210cadd94d5b5)
io.c (d1d487f438cc7e1296b5b60c035210cadd94d5b5)
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17#include "ruby/io/buffer.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <stddef.h>
22
23/* non-Linux poll may not work on all FDs */
24#if defined(HAVE_POLL)
25# if defined(__linux__)
26# define USE_POLL 1
27# endif
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29# define USE_POLL 1
30# endif
31#endif
32
33#ifndef USE_POLL
34# define USE_POLL 0
35#endif
36
37#undef free
38#define free(x) xfree(x)
39
40#if defined(DOSISH) || defined(__CYGWIN__)
41#include <io.h>
42#endif
43
44#include <sys/types.h>
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
49#endif
50
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
53#endif
54
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
56# define USE_SETVBUF
57#endif
58
59#ifdef __QNXNTO__
60#include <unix.h>
61#endif
62
63#include <sys/types.h>
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
65#include <sys/ioctl.h>
66#endif
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
68#include <fcntl.h>
69#elif defined(HAVE_SYS_FCNTL_H)
70#include <sys/fcntl.h>
71#endif
72
73#ifdef HAVE_SYS_TIME_H
74# include <sys/time.h>
75#endif
76
77#include <sys/stat.h>
78
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
81#endif
82
83#if !defined NOFILE
84# define NOFILE 64
85#endif
86
87#ifdef HAVE_UNISTD_H
88#include <unistd.h>
89#endif
90
91#ifdef HAVE_SYSCALL_H
92#include <syscall.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
95#endif
96
97#ifdef HAVE_SYS_UIO_H
98#include <sys/uio.h>
99#endif
100
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h> /* for WNOHANG on BSD */
103#endif
104
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
107
108# ifndef COPYFILE_STATE_COPIED
109/*
110 * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
111 * COPYFILE_STATE_COPIED. Since the only use of the former here
112 * requires the latter, we disable the former when the latter is undefined.
113 */
114# undef HAVE_FCOPYFILE
115# endif
116
117#endif
118
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#ifdef _WIN32
2933 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2934 return 0;
2935#endif
2936 return (VALUE)fdatasync(fptr->fd);
2937}
2938
2939/*
2940 * call-seq:
2941 * fdatasync -> 0
2942 *
2943 * Immediately writes to disk all data buffered in the stream,
2944 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2945 * otherwise via <tt>fsync(2)</tt>, if supported;
2946 * otherwise raises an exception.
2947 *
2948 */
2949
2950static VALUE
2951rb_io_fdatasync(VALUE io)
2952{
2953 rb_io_t *fptr;
2954
2955 io = GetWriteIO(io);
2956 GetOpenFile(io, fptr);
2957
2958 if (io_fflush(fptr) < 0)
2959 rb_sys_fail_on_write(fptr);
2960
2961 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2962 return INT2FIX(0);
2963
2964 /* fall back */
2965 return rb_io_fsync(io);
2966}
2967#else
2968#define rb_io_fdatasync rb_io_fsync
2969#endif
2970
2971/*
2972 * call-seq:
2973 * fileno -> integer
2974 *
2975 * Returns the integer file descriptor for the stream:
2976 *
2977 * $stdin.fileno # => 0
2978 * $stdout.fileno # => 1
2979 * $stderr.fileno # => 2
2980 * File.open('t.txt').fileno # => 10
2981 * f.close
2982 *
2983 */
2984
2985static VALUE
2986rb_io_fileno(VALUE io)
2987{
2988 rb_io_t *fptr = RFILE(io)->fptr;
2989 int fd;
2990
2991 rb_io_check_closed(fptr);
2992 fd = fptr->fd;
2993 return INT2FIX(fd);
2994}
2995
2996int
2998{
2999 if (RB_TYPE_P(io, T_FILE)) {
3000 rb_io_t *fptr = RFILE(io)->fptr;
3001 rb_io_check_closed(fptr);
3002 return fptr->fd;
3003 }
3004 else {
3005 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
3006 if (!UNDEF_P(fileno)) {
3007 return RB_NUM2INT(fileno);
3008 }
3009 }
3010
3011 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
3012
3014}
3015
3016int
3017rb_io_mode(VALUE io)
3018{
3019 rb_io_t *fptr;
3020 GetOpenFile(io, fptr);
3021 return fptr->mode;
3022}
3023
3024/*
3025 * call-seq:
3026 * pid -> integer or nil
3027 *
3028 * Returns the process ID of a child process associated with the stream,
3029 * which will have been set by IO#popen, or +nil+ if the stream was not
3030 * created by IO#popen:
3031 *
3032 * pipe = IO.popen("-")
3033 * if pipe
3034 * $stderr.puts "In parent, child pid is #{pipe.pid}"
3035 * else
3036 * $stderr.puts "In child, pid is #{$$}"
3037 * end
3038 *
3039 * Output:
3040 *
3041 * In child, pid is 26209
3042 * In parent, child pid is 26209
3043 *
3044 */
3045
3046static VALUE
3047rb_io_pid(VALUE io)
3048{
3049 rb_io_t *fptr;
3050
3051 GetOpenFile(io, fptr);
3052 if (!fptr->pid)
3053 return Qnil;
3054 return PIDT2NUM(fptr->pid);
3055}
3056
3057/*
3058 * :markup: markdown
3059 *
3060 * call-seq:
3061 * path -> string or nil
3062 *
3063 * Returns the string path associated with `self`,
3064 * or `nil` if there is no associated path:
3065 *
3066 * ```ruby
3067 * path = 'doc/maintainers.md'
3068 * fd = File.open(path).fileno # => 6
3069 * IO.new(fd, path: path).path # => "doc/maintainers.md"
3070 * IO.new(fd).path # => nil
3071 * ```
3072 *
3073 */
3074
3075VALUE
3077{
3078 rb_io_t *fptr = RFILE(io)->fptr;
3079
3080 if (!fptr)
3081 return Qnil;
3082
3083 return rb_obj_dup(fptr->pathv);
3084}
3085
3086/*
3087 * call-seq:
3088 * inspect -> string
3089 *
3090 * Returns a string representation of +self+:
3091 *
3092 * f = File.open('t.txt')
3093 * f.inspect # => "#<File:t.txt>"
3094 * f.close
3095 *
3096 */
3097
3098static VALUE
3099rb_io_inspect(VALUE obj)
3100{
3101 rb_io_t *fptr;
3102 VALUE result;
3103 static const char closed[] = " (closed)";
3104
3105 fptr = RFILE(obj)->fptr;
3106 if (!fptr) return rb_any_to_s(obj);
3107 result = rb_str_new_cstr("#<");
3108 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3109 rb_str_cat2(result, ":");
3110 if (NIL_P(fptr->pathv)) {
3111 if (fptr->fd < 0) {
3112 rb_str_cat(result, closed+1, strlen(closed)-1);
3113 }
3114 else {
3115 rb_str_catf(result, "fd %d", fptr->fd);
3116 }
3117 }
3118 else {
3119 rb_str_append(result, fptr->pathv);
3120 if (fptr->fd < 0) {
3121 rb_str_cat(result, closed, strlen(closed));
3122 }
3123 }
3124 return rb_str_cat2(result, ">");
3125}
3126
3127/*
3128 * call-seq:
3129 * to_io -> self
3130 *
3131 * Returns +self+.
3132 *
3133 */
3134
3135static VALUE
3136rb_io_to_io(VALUE io)
3137{
3138 return io;
3139}
3140
3141/* reading functions */
3142static long
3143read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3144{
3145 int n;
3146
3147 n = READ_DATA_PENDING_COUNT(fptr);
3148 if (n <= 0) return 0;
3149 if (n > len) n = (int)len;
3150 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3151 fptr->rbuf.off += n;
3152 fptr->rbuf.len -= n;
3153 return n;
3154}
3155
3156static long
3157io_bufread(char *ptr, long len, rb_io_t *fptr)
3158{
3159 long offset = 0;
3160 long n = len;
3161 long c;
3162
3163 if (READ_DATA_PENDING(fptr) == 0) {
3164 while (n > 0) {
3165 again:
3166 rb_io_check_closed(fptr);
3167 c = rb_io_read_memory(fptr, ptr+offset, n);
3168 if (c == 0) break;
3169 if (c < 0) {
3170 if (fptr_wait_readable(fptr))
3171 goto again;
3172 return -1;
3173 }
3174 offset += c;
3175 if ((n -= c) <= 0) break;
3176 }
3177 return len - n;
3178 }
3179
3180 while (n > 0) {
3181 c = read_buffered_data(ptr+offset, n, fptr);
3182 if (c > 0) {
3183 offset += c;
3184 if ((n -= c) <= 0) break;
3185 }
3186 rb_io_check_closed(fptr);
3187 if (io_fillbuf(fptr) < 0) {
3188 break;
3189 }
3190 }
3191 return len - n;
3192}
3193
3194static int io_setstrbuf(VALUE *str, long len);
3195
3197 char *str_ptr;
3198 long len;
3199 rb_io_t *fptr;
3200};
3201
3202static VALUE
3203bufread_call(VALUE arg)
3204{
3205 struct bufread_arg *p = (struct bufread_arg *)arg;
3206 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3207 return Qundef;
3208}
3209
3210static long
3211io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3212{
3213 long len;
3214 struct bufread_arg arg;
3215
3216 io_setstrbuf(&str, offset + size);
3217 arg.str_ptr = RSTRING_PTR(str) + offset;
3218 arg.len = size;
3219 arg.fptr = fptr;
3220 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3221 len = arg.len;
3222 if (len < 0) rb_sys_fail_path(fptr->pathv);
3223 return len;
3224}
3225
3226static long
3227remain_size(rb_io_t *fptr)
3228{
3229 struct stat st;
3230 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3231 rb_off_t pos;
3232
3233 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3234#if defined(__HAIKU__)
3235 && (st.st_dev > 3)
3236#endif
3237 )
3238 {
3239 if (io_fflush(fptr) < 0)
3240 rb_sys_fail_on_write(fptr);
3241 pos = lseek(fptr->fd, 0, SEEK_CUR);
3242 if (st.st_size >= pos && pos >= 0) {
3243 siz += st.st_size - pos;
3244 if (siz > LONG_MAX) {
3245 rb_raise(rb_eIOError, "file too big for single read");
3246 }
3247 }
3248 }
3249 else {
3250 siz += BUFSIZ;
3251 }
3252 return (long)siz;
3253}
3254
3255static VALUE
3256io_enc_str(VALUE str, rb_io_t *fptr)
3257{
3258 rb_enc_associate(str, io_read_encoding(fptr));
3259 return str;
3260}
3261
3262static void
3263make_readconv(rb_io_t *fptr, int size)
3264{
3265 if (!fptr->readconv) {
3266 int ecflags;
3267 VALUE ecopts;
3268 const char *sname, *dname;
3269 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3270 ecopts = fptr->encs.ecopts;
3271 if (fptr->encs.enc2) {
3272 sname = rb_enc_name(fptr->encs.enc2);
3273 dname = rb_enc_name(io_read_encoding(fptr));
3274 }
3275 else {
3276 sname = dname = "";
3277 }
3278 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3279 if (!fptr->readconv)
3280 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3281 fptr->cbuf.off = 0;
3282 fptr->cbuf.len = 0;
3283 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3284 fptr->cbuf.capa = size;
3285 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3286 }
3287}
3288
3289#define MORE_CHAR_SUSPENDED Qtrue
3290#define MORE_CHAR_FINISHED Qnil
3291static VALUE
3292fill_cbuf(rb_io_t *fptr, int ec_flags)
3293{
3294 const unsigned char *ss, *sp, *se;
3295 unsigned char *ds, *dp, *de;
3297 int putbackable;
3298 int cbuf_len0;
3299 VALUE exc;
3300
3301 ec_flags |= ECONV_PARTIAL_INPUT;
3302
3303 if (fptr->cbuf.len == fptr->cbuf.capa)
3304 return MORE_CHAR_SUSPENDED; /* cbuf full */
3305 if (fptr->cbuf.len == 0)
3306 fptr->cbuf.off = 0;
3307 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3308 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3309 fptr->cbuf.off = 0;
3310 }
3311
3312 cbuf_len0 = fptr->cbuf.len;
3313
3314 while (1) {
3315 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3316 se = sp + fptr->rbuf.len;
3317 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3318 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3319 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3320 fptr->rbuf.off += (int)(sp - ss);
3321 fptr->rbuf.len -= (int)(sp - ss);
3322 fptr->cbuf.len += (int)(dp - ds);
3323
3324 putbackable = rb_econv_putbackable(fptr->readconv);
3325 if (putbackable) {
3326 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3327 fptr->rbuf.off -= putbackable;
3328 fptr->rbuf.len += putbackable;
3329 }
3330
3331 exc = rb_econv_make_exception(fptr->readconv);
3332 if (!NIL_P(exc))
3333 return exc;
3334
3335 if (cbuf_len0 != fptr->cbuf.len)
3336 return MORE_CHAR_SUSPENDED;
3337
3338 if (res == econv_finished) {
3339 return MORE_CHAR_FINISHED;
3340 }
3341
3342 if (res == econv_source_buffer_empty) {
3343 if (fptr->rbuf.len == 0) {
3344 READ_CHECK(fptr);
3345 if (io_fillbuf(fptr) < 0) {
3346 if (!fptr->readconv) {
3347 return MORE_CHAR_FINISHED;
3348 }
3349 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3350 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3351 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3352 fptr->cbuf.len += (int)(dp - ds);
3354 break;
3355 }
3356 }
3357 }
3358 }
3359 if (cbuf_len0 != fptr->cbuf.len)
3360 return MORE_CHAR_SUSPENDED;
3361
3362 return MORE_CHAR_FINISHED;
3363}
3364
3365static VALUE
3366more_char(rb_io_t *fptr)
3367{
3368 VALUE v;
3369 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3370 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3371 rb_exc_raise(v);
3372 return v;
3373}
3374
3375static VALUE
3376io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3377{
3378 VALUE str = Qnil;
3379 if (strp) {
3380 str = *strp;
3381 if (NIL_P(str)) {
3382 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3383 }
3384 else {
3385 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3386 }
3387 rb_enc_associate(str, fptr->encs.enc);
3388 }
3389 fptr->cbuf.off += len;
3390 fptr->cbuf.len -= len;
3391 /* xxx: set coderange */
3392 if (fptr->cbuf.len == 0)
3393 fptr->cbuf.off = 0;
3394 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3395 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3396 fptr->cbuf.off = 0;
3397 }
3398 return str;
3399}
3400
3401static int
3402io_setstrbuf(VALUE *str, long len)
3403{
3404 if (NIL_P(*str)) {
3405 *str = rb_str_new(0, len);
3406 return TRUE;
3407 }
3408 else {
3409 VALUE s = StringValue(*str);
3410 rb_str_modify(s);
3411
3412 long clen = RSTRING_LEN(s);
3413 if (clen >= len) {
3414 return FALSE;
3415 }
3416 len -= clen;
3417 }
3418 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3420 }
3421 return FALSE;
3422}
3423
3424#define MAX_REALLOC_GAP 4096
3425static void
3426io_shrink_read_string(VALUE str, long n)
3427{
3428 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3429 rb_str_resize(str, n);
3430 }
3431}
3432
3433static void
3434io_set_read_length(VALUE str, long n, int shrinkable)
3435{
3436 if (RSTRING_LEN(str) != n) {
3437 rb_str_modify(str);
3438 rb_str_set_len(str, n);
3439 if (shrinkable) io_shrink_read_string(str, n);
3440 }
3441}
3442
3443static VALUE
3444read_all(rb_io_t *fptr, long siz, VALUE str)
3445{
3446 long bytes;
3447 long n;
3448 long pos;
3449 rb_encoding *enc;
3450 int cr;
3451 int shrinkable;
3452
3453 if (NEED_READCONV(fptr)) {
3454 int first = !NIL_P(str);
3455 SET_BINARY_MODE(fptr);
3456 shrinkable = io_setstrbuf(&str,0);
3457 make_readconv(fptr, 0);
3458 while (1) {
3459 VALUE v;
3460 if (fptr->cbuf.len) {
3461 if (first) rb_str_set_len(str, first = 0);
3462 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3463 }
3464 v = fill_cbuf(fptr, 0);
3465 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3466 if (fptr->cbuf.len) {
3467 if (first) rb_str_set_len(str, first = 0);
3468 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3469 }
3470 rb_exc_raise(v);
3471 }
3472 if (v == MORE_CHAR_FINISHED) {
3473 clear_readconv(fptr);
3474 if (first) rb_str_set_len(str, first = 0);
3475 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3476 return io_enc_str(str, fptr);
3477 }
3478 }
3479 }
3480
3481 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3482 bytes = 0;
3483 pos = 0;
3484
3485 enc = io_read_encoding(fptr);
3486 cr = 0;
3487
3488 if (siz == 0) {
3489 siz = BUFSIZ;
3490 }
3491 else {
3492 // If `siz` is set, we got it from `stat(2)`.
3493 // We attempt to read one extra byte because:
3494 // - If the file was appended to since then, we'll continue reading.
3495 // - If the file is still the same length, we won't issue a second `io_fread`.
3496 siz++;
3497 }
3498 shrinkable = io_setstrbuf(&str, siz);
3499 for (;;) {
3500 READ_CHECK(fptr);
3501 n = io_fread(str, bytes, siz - bytes, fptr);
3502 if (n == 0 && bytes == 0) {
3503 rb_str_set_len(str, 0);
3504 break;
3505 }
3506 bytes += n;
3507 rb_str_set_len(str, bytes);
3508 if (cr != ENC_CODERANGE_BROKEN)
3509 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3510 if (bytes < siz) break;
3511 siz += BUFSIZ;
3512
3513 size_t capa = rb_str_capacity(str);
3514 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3515 if (capa < BUFSIZ) {
3516 capa = BUFSIZ;
3517 }
3518 else if (capa > IO_MAX_BUFFER_GROWTH) {
3519 capa = IO_MAX_BUFFER_GROWTH;
3520 }
3522 }
3523 }
3524 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3525 str = io_enc_str(str, fptr);
3526 ENC_CODERANGE_SET(str, cr);
3527 return str;
3528}
3529
3530void
3532{
3533 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3534 rb_sys_fail_path(fptr->pathv);
3535 }
3536}
3537
3538static VALUE
3539io_read_memory_call(VALUE arg)
3540{
3541 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3542
3543 VALUE scheduler = rb_fiber_scheduler_current();
3544 if (scheduler != Qnil) {
3545 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa);
3546
3547 if (!UNDEF_P(result)) {
3548 // This is actually returned as a pseudo-VALUE and later cast to a long:
3550 }
3551 }
3552
3553 if (iis->nonblock) {
3554 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3555 }
3556 else {
3557 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3558 }
3559}
3560
3561static long
3562io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3563{
3564 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3565}
3566
3567#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3568
3569static VALUE
3570io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3571{
3572 rb_io_t *fptr;
3573 VALUE length, str;
3574 long n, len;
3575 struct io_internal_read_struct iis;
3576 int shrinkable;
3577
3578 rb_scan_args(argc, argv, "11", &length, &str);
3579
3580 if ((len = NUM2LONG(length)) < 0) {
3581 rb_raise(rb_eArgError, "negative length %ld given", len);
3582 }
3583
3584 shrinkable = io_setstrbuf(&str, len);
3585
3586 GetOpenFile(io, fptr);
3588
3589 if (len == 0) {
3590 io_set_read_length(str, 0, shrinkable);
3591 return str;
3592 }
3593
3594 if (!nonblock)
3595 READ_CHECK(fptr);
3596 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3597 if (n <= 0) {
3598 again:
3599 if (nonblock) {
3600 rb_io_set_nonblock(fptr);
3601 }
3602 io_setstrbuf(&str, len);
3603 iis.th = rb_thread_current();
3604 iis.fptr = fptr;
3605 iis.nonblock = nonblock;
3606 iis.fd = fptr->fd;
3607 iis.buf = RSTRING_PTR(str);
3608 iis.capa = len;
3609 iis.timeout = NULL;
3610 n = io_read_memory_locktmp(str, &iis);
3611 if (n < 0) {
3612 int e = errno;
3613 if (!nonblock && fptr_wait_readable(fptr))
3614 goto again;
3615 if (nonblock && (io_again_p(e))) {
3616 if (no_exception)
3617 return sym_wait_readable;
3618 else
3619 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3620 e, "read would block");
3621 }
3622 rb_syserr_fail_path(e, fptr->pathv);
3623 }
3624 }
3625 io_set_read_length(str, n, shrinkable);
3626
3627 if (n == 0)
3628 return Qnil;
3629 else
3630 return str;
3631}
3632
3633/*
3634 * call-seq:
3635 * readpartial(maxlen) -> string
3636 * readpartial(maxlen, out_string) -> out_string
3637 *
3638 * Reads up to +maxlen+ bytes from the stream;
3639 * returns a string (either a new string or the given +out_string+).
3640 * Its encoding is:
3641 *
3642 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3643 * - ASCII-8BIT, otherwise.
3644 *
3645 * - Contains +maxlen+ bytes from the stream, if available.
3646 * - Otherwise contains all available bytes, if any available.
3647 * - Is an empty string if +maxlen+ is zero.
3648 *
3649 * With the single non-negative integer argument +maxlen+ given,
3650 * returns a new string:
3651 *
3652 * f = File.new('t.txt')
3653 * f.readpartial(20) # => "First line\nSecond l"
3654 * f.readpartial(20) # => "ine\n\nFourth line\n"
3655 * f.readpartial(20) # => "Fifth line\n"
3656 * f.readpartial(20) # Raises EOFError.
3657 * f.close
3658 *
3659 * With both argument +maxlen+ and string argument +out_string+ given,
3660 * returns modified +out_string+:
3661 *
3662 * f = File.new('t.txt')
3663 * s = 'foo'
3664 * f.readpartial(20, s) # => "First line\nSecond l"
3665 * s = 'bar'
3666 * f.readpartial(0, s) # => ""
3667 * f.close
3668 *
3669 * This method is useful for a stream such as a pipe, a socket, or a tty.
3670 * It blocks only when no data is immediately available.
3671 * This means that it blocks only when _all_ of the following are true:
3672 *
3673 * - The byte buffer in the stream is empty.
3674 * - The content of the stream is empty.
3675 * - The stream is not at EOF.
3676 *
3677 * When blocked, the method waits for either more data or EOF on the stream:
3678 *
3679 * - If more data is read, the method returns the data.
3680 * - If EOF is reached, the method raises EOFError.
3681 *
3682 * When not blocked, the method responds immediately:
3683 *
3684 * - Returns data from the buffer if there is any.
3685 * - Otherwise returns data from the stream if there is any.
3686 * - Otherwise raises EOFError if the stream has reached EOF.
3687 *
3688 * Note that this method is similar to sysread. The differences are:
3689 *
3690 * - If the byte buffer is not empty, read from the byte buffer
3691 * instead of "sysread for buffered IO (IOError)".
3692 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3693 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3694 * readpartial retries the system call.
3695 *
3696 * The latter means that readpartial is non-blocking-flag insensitive.
3697 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3698 * if the fd is blocking mode.
3699 *
3700 * Examples:
3701 *
3702 * # # Returned Buffer Content Pipe Content
3703 * r, w = IO.pipe #
3704 * w << 'abc' # "" "abc".
3705 * r.readpartial(4096) # => "abc" "" ""
3706 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3707 *
3708 * # # Returned Buffer Content Pipe Content
3709 * r, w = IO.pipe #
3710 * w << 'abc' # "" "abc"
3711 * w.close # "" "abc" EOF
3712 * r.readpartial(4096) # => "abc" "" EOF
3713 * r.readpartial(4096) # raises EOFError
3714 *
3715 * # # Returned Buffer Content Pipe Content
3716 * r, w = IO.pipe #
3717 * w << "abc\ndef\n" # "" "abc\ndef\n"
3718 * r.gets # => "abc\n" "def\n" ""
3719 * w << "ghi\n" # "def\n" "ghi\n"
3720 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3721 * r.readpartial(4096) # => "ghi\n" "" ""
3722 *
3723 */
3724
3725static VALUE
3726io_readpartial(int argc, VALUE *argv, VALUE io)
3727{
3728 VALUE ret;
3729
3730 ret = io_getpartial(argc, argv, io, Qnil, 0);
3731 if (NIL_P(ret))
3732 rb_eof_error();
3733 return ret;
3734}
3735
3736static VALUE
3737io_nonblock_eof(int no_exception)
3738{
3739 if (!no_exception) {
3740 rb_eof_error();
3741 }
3742 return Qnil;
3743}
3744
3745/* :nodoc: */
3746static VALUE
3747io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3748{
3749 rb_io_t *fptr;
3750 long n, len;
3751 struct io_internal_read_struct iis;
3752 int shrinkable;
3753
3754 if ((len = NUM2LONG(length)) < 0) {
3755 rb_raise(rb_eArgError, "negative length %ld given", len);
3756 }
3757
3758 shrinkable = io_setstrbuf(&str, len);
3759 rb_bool_expected(ex, "exception", TRUE);
3760
3761 GetOpenFile(io, fptr);
3763
3764 if (len == 0) {
3765 io_set_read_length(str, 0, shrinkable);
3766 return str;
3767 }
3768
3769 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3770 if (n <= 0) {
3771 rb_fd_set_nonblock(fptr->fd);
3772 shrinkable |= io_setstrbuf(&str, len);
3773 iis.fptr = fptr;
3774 iis.nonblock = 1;
3775 iis.fd = fptr->fd;
3776 iis.buf = RSTRING_PTR(str);
3777 iis.capa = len;
3778 iis.timeout = NULL;
3779 n = io_read_memory_locktmp(str, &iis);
3780 if (n < 0) {
3781 int e = errno;
3782 if (io_again_p(e)) {
3783 if (!ex) return sym_wait_readable;
3784 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3785 e, "read would block");
3786 }
3787 rb_syserr_fail_path(e, fptr->pathv);
3788 }
3789 }
3790 io_set_read_length(str, n, shrinkable);
3791
3792 if (n == 0) {
3793 if (!ex) return Qnil;
3794 rb_eof_error();
3795 }
3796
3797 return str;
3798}
3799
3800/* :nodoc: */
3801static VALUE
3802io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3803{
3804 rb_io_t *fptr;
3805 long n;
3806
3807 if (!RB_TYPE_P(str, T_STRING))
3808 str = rb_obj_as_string(str);
3809 rb_bool_expected(ex, "exception", TRUE);
3810
3811 io = GetWriteIO(io);
3812 GetOpenFile(io, fptr);
3814
3815 if (io_fflush(fptr) < 0)
3816 rb_sys_fail_on_write(fptr);
3817
3818 rb_fd_set_nonblock(fptr->fd);
3819 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3820 RB_GC_GUARD(str);
3821
3822 if (n < 0) {
3823 int e = errno;
3824 if (io_again_p(e)) {
3825 if (!ex) {
3826 return sym_wait_writable;
3827 }
3828 else {
3829 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3830 }
3831 }
3832 rb_syserr_fail_path(e, fptr->pathv);
3833 }
3834
3835 return LONG2FIX(n);
3836}
3837
3838/*
3839 * call-seq:
3840 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3841 *
3842 * Reads bytes from the stream; the stream must be opened for reading
3843 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3844 *
3845 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3846 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3847 *
3848 * Returns a string (either a new string or the given +out_string+)
3849 * containing the bytes read.
3850 * The encoding of the string depends on both +maxLen+ and +out_string+:
3851 *
3852 * - +maxlen+ is +nil+: uses internal encoding of +self+
3853 * (regardless of whether +out_string+ was given).
3854 * - +maxlen+ not +nil+:
3855 *
3856 * - +out_string+ given: encoding of +out_string+ not modified.
3857 * - +out_string+ not given: ASCII-8BIT is used.
3858 *
3859 * <b>Without Argument +out_string+</b>
3860 *
3861 * When argument +out_string+ is omitted,
3862 * the returned value is a new string:
3863 *
3864 * f = File.new('t.txt')
3865 * f.read
3866 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3867 * f.rewind
3868 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3869 * f.read(30) # => "rth line\r\nFifth line\r\n"
3870 * f.read(30) # => nil
3871 * f.close
3872 *
3873 * If +maxlen+ is zero, returns an empty string.
3874 *
3875 * <b> With Argument +out_string+</b>
3876 *
3877 * When argument +out_string+ is given,
3878 * the returned value is +out_string+, whose content is replaced:
3879 *
3880 * f = File.new('t.txt')
3881 * s = 'foo' # => "foo"
3882 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3883 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3884 * f.rewind
3885 * s = 'bar'
3886 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3887 * s # => "First line\r\nSecond line\r\n\r\nFou"
3888 * s = 'baz'
3889 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3890 * s # => "rth line\r\nFifth line\r\n"
3891 * s = 'bat'
3892 * f.read(30, s) # => nil
3893 * s # => ""
3894 * f.close
3895 *
3896 * Note that this method behaves like the fread() function in C.
3897 * This means it retries to invoke read(2) system calls to read data
3898 * with the specified maxlen (or until EOF).
3899 *
3900 * This behavior is preserved even if the stream is in non-blocking mode.
3901 * (This method is non-blocking-flag insensitive as other methods.)
3902 *
3903 * If you need the behavior like a single read(2) system call,
3904 * consider #readpartial, #read_nonblock, and #sysread.
3905 *
3906 * Related: IO#write.
3907 */
3908
3909static VALUE
3910io_read(int argc, VALUE *argv, VALUE io)
3911{
3912 rb_io_t *fptr;
3913 long n, len;
3914 VALUE length, str;
3915 int shrinkable;
3916#if RUBY_CRLF_ENVIRONMENT
3917 int previous_mode;
3918#endif
3919
3920 rb_scan_args(argc, argv, "02", &length, &str);
3921
3922 if (NIL_P(length)) {
3923 GetOpenFile(io, fptr);
3925 return read_all(fptr, remain_size(fptr), str);
3926 }
3927 len = NUM2LONG(length);
3928 if (len < 0) {
3929 rb_raise(rb_eArgError, "negative length %ld given", len);
3930 }
3931
3932 shrinkable = io_setstrbuf(&str,len);
3933
3934 GetOpenFile(io, fptr);
3936 if (len == 0) {
3937 io_set_read_length(str, 0, shrinkable);
3938 return str;
3939 }
3940
3941 READ_CHECK(fptr);
3942#if RUBY_CRLF_ENVIRONMENT
3943 previous_mode = set_binary_mode_with_seek_cur(fptr);
3944#endif
3945 n = io_fread(str, 0, len, fptr);
3946 io_set_read_length(str, n, shrinkable);
3947#if RUBY_CRLF_ENVIRONMENT
3948 if (previous_mode == O_TEXT) {
3949 setmode(fptr->fd, O_TEXT);
3950 }
3951#endif
3952 if (n == 0) return Qnil;
3953
3954 return str;
3955}
3956
3957static void
3958rscheck(const char *rsptr, long rslen, VALUE rs)
3959{
3960 if (!rs) return;
3961 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3962 rb_raise(rb_eRuntimeError, "rs modified");
3963}
3964
3965static const char *
3966search_delim(const char *p, long len, int delim, rb_encoding *enc)
3967{
3968 if (rb_enc_mbminlen(enc) == 1) {
3969 p = memchr(p, delim, len);
3970 if (p) return p + 1;
3971 }
3972 else {
3973 const char *end = p + len;
3974 while (p < end) {
3975 int r = rb_enc_precise_mbclen(p, end, enc);
3976 if (!MBCLEN_CHARFOUND_P(r)) {
3977 p += rb_enc_mbminlen(enc);
3978 continue;
3979 }
3980 int n = MBCLEN_CHARFOUND_LEN(r);
3981 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3982 return p + n;
3983 }
3984 p += n;
3985 }
3986 }
3987 return NULL;
3988}
3989
3990static int
3991appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3992{
3993 VALUE str = *strp;
3994 long limit = *lp;
3995
3996 if (NEED_READCONV(fptr)) {
3997 SET_BINARY_MODE(fptr);
3998 make_readconv(fptr, 0);
3999 do {
4000 const char *p, *e;
4001 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
4002 if (searchlen) {
4003 p = READ_CHAR_PENDING_PTR(fptr);
4004 if (0 < limit && limit < searchlen)
4005 searchlen = (int)limit;
4006 e = search_delim(p, searchlen, delim, enc);
4007 if (e) {
4008 int len = (int)(e-p);
4009 if (NIL_P(str))
4010 *strp = str = rb_str_new(p, len);
4011 else
4012 rb_str_buf_cat(str, p, len);
4013 fptr->cbuf.off += len;
4014 fptr->cbuf.len -= len;
4015 limit -= len;
4016 *lp = limit;
4017 return delim;
4018 }
4019
4020 if (NIL_P(str))
4021 *strp = str = rb_str_new(p, searchlen);
4022 else
4023 rb_str_buf_cat(str, p, searchlen);
4024 fptr->cbuf.off += searchlen;
4025 fptr->cbuf.len -= searchlen;
4026 limit -= searchlen;
4027
4028 if (limit == 0) {
4029 *lp = limit;
4030 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4031 }
4032 }
4033 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4034 clear_readconv(fptr);
4035 *lp = limit;
4036 return EOF;
4037 }
4038
4039 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4040 do {
4041 long pending = READ_DATA_PENDING_COUNT(fptr);
4042 if (pending > 0) {
4043 const char *p = READ_DATA_PENDING_PTR(fptr);
4044 const char *e;
4045 long last;
4046
4047 if (limit > 0 && pending > limit) pending = limit;
4048 e = search_delim(p, pending, delim, enc);
4049 if (e) pending = e - p;
4050 if (!NIL_P(str)) {
4051 last = RSTRING_LEN(str);
4052 rb_str_resize(str, last + pending);
4053 }
4054 else {
4055 last = 0;
4056 *strp = str = rb_str_buf_new(pending);
4057 rb_str_set_len(str, pending);
4058 }
4059 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
4060 limit -= pending;
4061 *lp = limit;
4062 if (e) return delim;
4063 if (limit == 0)
4064 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4065 }
4066 READ_CHECK(fptr);
4067 } while (io_fillbuf(fptr) >= 0);
4068 *lp = limit;
4069 return EOF;
4070}
4071
4072static inline int
4073swallow(rb_io_t *fptr, int term)
4074{
4075 if (NEED_READCONV(fptr)) {
4076 rb_encoding *enc = io_read_encoding(fptr);
4077 int needconv = rb_enc_mbminlen(enc) != 1;
4078 SET_BINARY_MODE(fptr);
4079 make_readconv(fptr, 0);
4080 do {
4081 size_t cnt;
4082 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4083 const char *p = READ_CHAR_PENDING_PTR(fptr);
4084 int i;
4085 if (!needconv) {
4086 if (*p != term) return TRUE;
4087 i = (int)cnt;
4088 while (--i && *++p == term);
4089 }
4090 else {
4091 const char *e = p + cnt;
4092 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
4093 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4094 i = (int)(e - p);
4095 }
4096 io_shift_cbuf(fptr, (int)cnt - i, NULL);
4097 }
4098 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4099 return FALSE;
4100 }
4101
4102 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4103 do {
4104 size_t cnt;
4105 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4106 char buf[1024];
4107 const char *p = READ_DATA_PENDING_PTR(fptr);
4108 int i;
4109 if (cnt > sizeof buf) cnt = sizeof buf;
4110 if (*p != term) return TRUE;
4111 i = (int)cnt;
4112 while (--i && *++p == term);
4113 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4114 rb_sys_fail_path(fptr->pathv);
4115 }
4116 READ_CHECK(fptr);
4117 } while (io_fillbuf(fptr) == 0);
4118 return FALSE;
4119}
4120
4121static VALUE
4122rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4123{
4124 VALUE str = Qnil;
4125 int len = 0;
4126 long pos = 0;
4127 int cr = 0;
4128
4129 do {
4130 int pending = READ_DATA_PENDING_COUNT(fptr);
4131
4132 if (pending > 0) {
4133 const char *p = READ_DATA_PENDING_PTR(fptr);
4134 const char *e;
4135 int chomplen = 0;
4136
4137 e = memchr(p, '\n', pending);
4138 if (e) {
4139 pending = (int)(e - p + 1);
4140 if (chomp) {
4141 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4142 }
4143 }
4144 if (NIL_P(str)) {
4145 str = rb_str_new(p, pending - chomplen);
4146 fptr->rbuf.off += pending;
4147 fptr->rbuf.len -= pending;
4148 }
4149 else {
4150 rb_str_resize(str, len + pending - chomplen);
4151 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4152 fptr->rbuf.off += chomplen;
4153 fptr->rbuf.len -= chomplen;
4154 if (pending == 1 && chomplen == 1 && len > 0) {
4155 if (RSTRING_PTR(str)[len-1] == '\r') {
4156 rb_str_resize(str, --len);
4157 break;
4158 }
4159 }
4160 }
4161 len += pending - chomplen;
4162 if (cr != ENC_CODERANGE_BROKEN)
4163 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4164 if (e) break;
4165 }
4166 READ_CHECK(fptr);
4167 } while (io_fillbuf(fptr) >= 0);
4168 if (NIL_P(str)) return Qnil;
4169
4170 str = io_enc_str(str, fptr);
4171 ENC_CODERANGE_SET(str, cr);
4172 fptr->lineno++;
4173
4174 return str;
4175}
4176
4178 VALUE io;
4179 VALUE rs;
4180 long limit;
4181 unsigned int chomp: 1;
4182};
4183
4184static void
4185extract_getline_opts(VALUE opts, struct getline_arg *args)
4186{
4187 int chomp = FALSE;
4188 if (!NIL_P(opts)) {
4189 static ID kwds[1];
4190 VALUE vchomp;
4191 if (!kwds[0]) {
4192 kwds[0] = rb_intern_const("chomp");
4193 }
4194 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4195 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4196 }
4197 args->chomp = chomp;
4198}
4199
4200static void
4201extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4202{
4203 VALUE rs = rb_rs, lim = Qnil;
4204
4205 if (argc == 1) {
4206 VALUE tmp = Qnil;
4207
4208 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4209 rs = tmp;
4210 }
4211 else {
4212 lim = argv[0];
4213 }
4214 }
4215 else if (2 <= argc) {
4216 rs = argv[0], lim = argv[1];
4217 if (!NIL_P(rs))
4218 StringValue(rs);
4219 }
4220 args->rs = rs;
4221 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4222}
4223
4224static void
4225check_getline_args(VALUE *rsp, long *limit, VALUE io)
4226{
4227 rb_io_t *fptr;
4228 VALUE rs = *rsp;
4229
4230 if (!NIL_P(rs)) {
4231 rb_encoding *enc_rs, *enc_io;
4232
4233 GetOpenFile(io, fptr);
4234 enc_rs = rb_enc_get(rs);
4235 enc_io = io_read_encoding(fptr);
4236 if (enc_io != enc_rs &&
4237 (!is_ascii_string(rs) ||
4238 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4239 if (rs == rb_default_rs) {
4240 rs = rb_enc_str_new(0, 0, enc_io);
4241 rb_str_buf_cat_ascii(rs, "\n");
4242 *rsp = rs;
4243 }
4244 else {
4245 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4246 rb_enc_name(enc_io),
4247 rb_enc_name(enc_rs));
4248 }
4249 }
4250 }
4251}
4252
4253static void
4254prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4255{
4256 VALUE opts;
4257 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4258 extract_getline_args(argc, argv, args);
4259 extract_getline_opts(opts, args);
4260 check_getline_args(&args->rs, &args->limit, io);
4261}
4262
4263static VALUE
4264rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4265{
4266 VALUE str = Qnil;
4267 int nolimit = 0;
4268 rb_encoding *enc;
4269
4271 if (NIL_P(rs) && limit < 0) {
4272 str = read_all(fptr, 0, Qnil);
4273 if (RSTRING_LEN(str) == 0) return Qnil;
4274 }
4275 else if (limit == 0) {
4276 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4277 }
4278 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4279 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4280 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4281 return rb_io_getline_fast(fptr, enc, chomp);
4282 }
4283 else {
4284 int c, newline = -1;
4285 const char *rsptr = 0;
4286 long rslen = 0;
4287 int rspara = 0;
4288 int extra_limit = 16;
4289 int chomp_cr = chomp;
4290
4291 SET_BINARY_MODE(fptr);
4292 enc = io_read_encoding(fptr);
4293
4294 if (!NIL_P(rs)) {
4295 rslen = RSTRING_LEN(rs);
4296 if (rslen == 0) {
4297 rsptr = "\n\n";
4298 rslen = 2;
4299 rspara = 1;
4300 swallow(fptr, '\n');
4301 rs = 0;
4302 if (!rb_enc_asciicompat(enc)) {
4303 rs = rb_usascii_str_new(rsptr, rslen);
4304 rs = rb_str_conv_enc(rs, 0, enc);
4305 OBJ_FREEZE(rs);
4306 rsptr = RSTRING_PTR(rs);
4307 rslen = RSTRING_LEN(rs);
4308 }
4309 newline = '\n';
4310 }
4311 else if (rb_enc_mbminlen(enc) == 1) {
4312 rsptr = RSTRING_PTR(rs);
4313 newline = (unsigned char)rsptr[rslen - 1];
4314 }
4315 else {
4316 rs = rb_str_conv_enc(rs, 0, enc);
4317 rsptr = RSTRING_PTR(rs);
4318 const char *e = rsptr + rslen;
4319 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4320 int n;
4321 newline = rb_enc_codepoint_len(last, e, &n, enc);
4322 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4323 }
4324 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4325 }
4326
4327 /* MS - Optimization */
4328 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4329 const char *s, *p, *pp, *e;
4330
4331 if (c == newline) {
4332 if (RSTRING_LEN(str) < rslen) continue;
4333 s = RSTRING_PTR(str);
4334 e = RSTRING_END(str);
4335 p = e - rslen;
4336 if (!at_char_boundary(s, p, e, enc)) continue;
4337 if (!rspara) rscheck(rsptr, rslen, rs);
4338 if (memcmp(p, rsptr, rslen) == 0) {
4339 if (chomp) {
4340 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4341 rb_str_set_len(str, p - s);
4342 }
4343 break;
4344 }
4345 }
4346 if (limit == 0) {
4347 s = RSTRING_PTR(str);
4348 p = RSTRING_END(str);
4349 pp = rb_enc_prev_char(s, p, p, enc);
4350 if (extra_limit && pp &&
4351 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4352 /* relax the limit while incomplete character.
4353 * extra_limit limits the relax length */
4354 limit = 1;
4355 extra_limit--;
4356 }
4357 else {
4358 nolimit = 1;
4359 break;
4360 }
4361 }
4362 }
4363
4364 if (rspara && c != EOF)
4365 swallow(fptr, '\n');
4366 if (!NIL_P(str))
4367 str = io_enc_str(str, fptr);
4368 }
4369
4370 if (!NIL_P(str) && !nolimit) {
4371 fptr->lineno++;
4372 }
4373
4374 return str;
4375}
4376
4377static VALUE
4378rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4379{
4380 rb_io_t *fptr;
4381 int old_lineno, new_lineno;
4382 VALUE str;
4383
4384 GetOpenFile(io, fptr);
4385 old_lineno = fptr->lineno;
4386 str = rb_io_getline_0(rs, limit, chomp, fptr);
4387 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4388 if (io == ARGF.current_file) {
4389 ARGF.lineno += new_lineno - old_lineno;
4390 ARGF.last_lineno = ARGF.lineno;
4391 }
4392 else {
4393 ARGF.last_lineno = new_lineno;
4394 }
4395 }
4396
4397 return str;
4398}
4399
4400static VALUE
4401rb_io_getline(int argc, VALUE *argv, VALUE io)
4402{
4403 struct getline_arg args;
4404
4405 prepare_getline_args(argc, argv, &args, io);
4406 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4407}
4408
4409VALUE
4411{
4412 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4413}
4414
4415VALUE
4416rb_io_gets_limit_internal(VALUE io, long limit)
4417{
4418 rb_io_t *fptr;
4419 GetOpenFile(io, fptr);
4420 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4421}
4422
4423VALUE
4424rb_io_gets_internal(VALUE io)
4425{
4426 return rb_io_gets_limit_internal(io, -1);
4427}
4428
4429/*
4430 * call-seq:
4431 * gets(sep = $/, chomp: false) -> string or nil
4432 * gets(limit, chomp: false) -> string or nil
4433 * gets(sep, limit, chomp: false) -> string or nil
4434 *
4435 * Reads and returns a line from the stream;
4436 * assigns the return value to <tt>$_</tt>.
4437 * See {Line IO}[rdoc-ref:IO@Line+IO].
4438 *
4439 * With no arguments given, returns the next line
4440 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4441 *
4442 * f = File.open('t.txt')
4443 * f.gets # => "First line\n"
4444 * $_ # => "First line\n"
4445 * f.gets # => "\n"
4446 * f.gets # => "Fourth line\n"
4447 * f.gets # => "Fifth line\n"
4448 * f.gets # => nil
4449 * f.close
4450 *
4451 * With only string argument +sep+ given,
4452 * returns the next line as determined by line separator +sep+,
4453 * or +nil+ if none;
4454 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4455 *
4456 * f = File.new('t.txt')
4457 * f.gets('l') # => "First l"
4458 * f.gets('li') # => "ine\nSecond li"
4459 * f.gets('lin') # => "ne\n\nFourth lin"
4460 * f.gets # => "e\n"
4461 * f.close
4462 *
4463 * The two special values for +sep+ are honored:
4464 *
4465 * f = File.new('t.txt')
4466 * # Get all.
4467 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4468 * f.rewind
4469 * # Get paragraph (up to two line separators).
4470 * f.gets('') # => "First line\nSecond line\n\n"
4471 * f.close
4472 *
4473 * With only integer argument +limit+ given,
4474 * limits the number of bytes in the line;
4475 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4476 *
4477 * # No more than one line.
4478 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4479 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4480 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4481 *
4482 * With arguments +sep+ and +limit+ given,
4483 * combines the two behaviors
4484 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4485 *
4486 * Optional keyword argument +chomp+ specifies whether line separators
4487 * are to be omitted:
4488 *
4489 * f = File.open('t.txt')
4490 * # Chomp the lines.
4491 * f.gets(chomp: true) # => "First line"
4492 * f.gets(chomp: true) # => "Second line"
4493 * f.gets(chomp: true) # => ""
4494 * f.gets(chomp: true) # => "Fourth line"
4495 * f.gets(chomp: true) # => "Fifth line"
4496 * f.gets(chomp: true) # => nil
4497 * f.close
4498 *
4499 */
4500
4501static VALUE
4502rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4503{
4504 VALUE str;
4505
4506 str = rb_io_getline(argc, argv, io);
4507 rb_lastline_set(str);
4508
4509 return str;
4510}
4511
4512/*
4513 * call-seq:
4514 * lineno -> integer
4515 *
4516 * Returns the current line number for the stream;
4517 * see {Line Number}[rdoc-ref:IO@Line+Number].
4518 *
4519 */
4520
4521static VALUE
4522rb_io_lineno(VALUE io)
4523{
4524 rb_io_t *fptr;
4525
4526 GetOpenFile(io, fptr);
4528 return INT2NUM(fptr->lineno);
4529}
4530
4531/*
4532 * call-seq:
4533 * lineno = integer -> integer
4534 *
4535 * Sets and returns the line number for the stream;
4536 * see {Line Number}[rdoc-ref:IO@Line+Number].
4537 *
4538 */
4539
4540static VALUE
4541rb_io_set_lineno(VALUE io, VALUE lineno)
4542{
4543 rb_io_t *fptr;
4544
4545 GetOpenFile(io, fptr);
4547 fptr->lineno = NUM2INT(lineno);
4548 return lineno;
4549}
4550
4551/* :nodoc: */
4552static VALUE
4553io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4554{
4555 long limit = -1;
4556 if (NIL_P(lim)) {
4557 VALUE tmp = Qnil;
4558 // If sep is specified, but it's not a string and not nil, then assume
4559 // it's the limit (it should be an integer)
4560 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4561 // If the user has specified a non-nil / non-string value
4562 // for the separator, we assume it's the limit and set the
4563 // separator to default: rb_rs.
4564 lim = sep;
4565 limit = NUM2LONG(lim);
4566 sep = rb_rs;
4567 }
4568 else {
4569 sep = tmp;
4570 }
4571 }
4572 else {
4573 if (!NIL_P(sep)) StringValue(sep);
4574 limit = NUM2LONG(lim);
4575 }
4576
4577 check_getline_args(&sep, &limit, io);
4578
4579 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4580 rb_lastline_set_up(line, 1);
4581
4582 if (NIL_P(line)) {
4583 rb_eof_error();
4584 }
4585 return line;
4586}
4587
4588static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4589
4590/*
4591 * call-seq:
4592 * readlines(sep = $/, chomp: false) -> array
4593 * readlines(limit, chomp: false) -> array
4594 * readlines(sep, limit, chomp: false) -> array
4595 *
4596 * Reads and returns all remaining line from the stream;
4597 * does not modify <tt>$_</tt>.
4598 * See {Line IO}[rdoc-ref:IO@Line+IO].
4599 *
4600 * With no arguments given, returns lines
4601 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4602 *
4603 * f = File.new('t.txt')
4604 * f.readlines
4605 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4606 * f.readlines # => []
4607 * f.close
4608 *
4609 * With only string argument +sep+ given,
4610 * returns lines as determined by line separator +sep+,
4611 * or +nil+ if none;
4612 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4613 *
4614 * f = File.new('t.txt')
4615 * f.readlines('li')
4616 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4617 * f.close
4618 *
4619 * The two special values for +sep+ are honored:
4620 *
4621 * f = File.new('t.txt')
4622 * # Get all into one string.
4623 * f.readlines(nil)
4624 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4625 * # Get paragraphs (up to two line separators).
4626 * f.rewind
4627 * f.readlines('')
4628 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4629 * f.close
4630 *
4631 * With only integer argument +limit+ given,
4632 * limits the number of bytes in each line;
4633 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4634 *
4635 * f = File.new('t.txt')
4636 * f.readlines(8)
4637 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4638 * f.close
4639 *
4640 * With arguments +sep+ and +limit+ given,
4641 * combines the two behaviors
4642 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4643 *
4644 * Optional keyword argument +chomp+ specifies whether line separators
4645 * are to be omitted:
4646 *
4647 * f = File.new('t.txt')
4648 * f.readlines(chomp: true)
4649 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4650 * f.close
4651 *
4652 */
4653
4654static VALUE
4655rb_io_readlines(int argc, VALUE *argv, VALUE io)
4656{
4657 struct getline_arg args;
4658
4659 prepare_getline_args(argc, argv, &args, io);
4660 return io_readlines(&args, io);
4661}
4662
4663static VALUE
4664io_readlines(const struct getline_arg *arg, VALUE io)
4665{
4666 VALUE line, ary;
4667
4668 if (arg->limit == 0)
4669 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4670 ary = rb_ary_new();
4671 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4672 rb_ary_push(ary, line);
4673 }
4674 return ary;
4675}
4676
4677/*
4678 * call-seq:
4679 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4680 * each_line(limit, chomp: false) {|line| ... } -> self
4681 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4682 * each_line -> enumerator
4683 *
4684 * Calls the block with each remaining line read from the stream;
4685 * returns +self+.
4686 * Does nothing if already at end-of-stream;
4687 * See {Line IO}[rdoc-ref:IO@Line+IO].
4688 *
4689 * With no arguments given, reads lines
4690 * as determined by line separator <tt>$/</tt>:
4691 *
4692 * f = File.new('t.txt')
4693 * f.each_line {|line| p line }
4694 * f.each_line {|line| fail 'Cannot happen' }
4695 * f.close
4696 *
4697 * Output:
4698 *
4699 * "First line\n"
4700 * "Second line\n"
4701 * "\n"
4702 * "Fourth line\n"
4703 * "Fifth line\n"
4704 *
4705 * With only string argument +sep+ given,
4706 * reads lines as determined by line separator +sep+;
4707 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4708 *
4709 * f = File.new('t.txt')
4710 * f.each_line('li') {|line| p line }
4711 * f.close
4712 *
4713 * Output:
4714 *
4715 * "First li"
4716 * "ne\nSecond li"
4717 * "ne\n\nFourth li"
4718 * "ne\nFifth li"
4719 * "ne\n"
4720 *
4721 * The two special values for +sep+ are honored:
4722 *
4723 * f = File.new('t.txt')
4724 * # Get all into one string.
4725 * f.each_line(nil) {|line| p line }
4726 * f.close
4727 *
4728 * Output:
4729 *
4730 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4731 *
4732 * f.rewind
4733 * # Get paragraphs (up to two line separators).
4734 * f.each_line('') {|line| p line }
4735 *
4736 * Output:
4737 *
4738 * "First line\nSecond line\n\n"
4739 * "Fourth line\nFifth line\n"
4740 *
4741 * With only integer argument +limit+ given,
4742 * limits the number of bytes in each line;
4743 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4744 *
4745 * f = File.new('t.txt')
4746 * f.each_line(8) {|line| p line }
4747 * f.close
4748 *
4749 * Output:
4750 *
4751 * "First li"
4752 * "ne\n"
4753 * "Second l"
4754 * "ine\n"
4755 * "\n"
4756 * "Fourth l"
4757 * "ine\n"
4758 * "Fifth li"
4759 * "ne\n"
4760 *
4761 * With arguments +sep+ and +limit+ given,
4762 * combines the two behaviors
4763 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4764 *
4765 * Optional keyword argument +chomp+ specifies whether line separators
4766 * are to be omitted:
4767 *
4768 * f = File.new('t.txt')
4769 * f.each_line(chomp: true) {|line| p line }
4770 * f.close
4771 *
4772 * Output:
4773 *
4774 * "First line"
4775 * "Second line"
4776 * ""
4777 * "Fourth line"
4778 * "Fifth line"
4779 *
4780 * Returns an Enumerator if no block is given.
4781 */
4782
4783static VALUE
4784rb_io_each_line(int argc, VALUE *argv, VALUE io)
4785{
4786 VALUE str;
4787 struct getline_arg args;
4788
4789 RETURN_ENUMERATOR(io, argc, argv);
4790 prepare_getline_args(argc, argv, &args, io);
4791 if (args.limit == 0)
4792 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4793 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4794 rb_yield(str);
4795 }
4796 return io;
4797}
4798
4799/*
4800 * call-seq:
4801 * each_byte {|byte| ... } -> self
4802 * each_byte -> enumerator
4803 *
4804 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4805 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4806 *
4807 * File.read('t.ja') # => "こんにちは"
4808 * f = File.new('t.ja')
4809 * a = []
4810 * f.each_byte {|b| a << b }
4811 * a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
4812 * f.close
4813 *
4814 * Returns an Enumerator if no block is given.
4815 *
4816 * Related: IO#each_char, IO#each_codepoint.
4817 *
4818 */
4819
4820static VALUE
4821rb_io_each_byte(VALUE io)
4822{
4823 rb_io_t *fptr;
4824
4825 RETURN_ENUMERATOR(io, 0, 0);
4826 GetOpenFile(io, fptr);
4827
4828 do {
4829 while (fptr->rbuf.len > 0) {
4830 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4831 fptr->rbuf.len--;
4832 rb_yield(INT2FIX(*p & 0xff));
4834 errno = 0;
4835 }
4836 READ_CHECK(fptr);
4837 } while (io_fillbuf(fptr) >= 0);
4838 return io;
4839}
4840
4841static VALUE
4842io_getc(rb_io_t *fptr, rb_encoding *enc)
4843{
4844 int r, n, cr = 0;
4845 VALUE str;
4846
4847 if (NEED_READCONV(fptr)) {
4848 rb_encoding *read_enc = io_read_encoding(fptr);
4849
4850 str = Qnil;
4851 SET_BINARY_MODE(fptr);
4852 make_readconv(fptr, 0);
4853
4854 while (1) {
4855 if (fptr->cbuf.len) {
4856 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4857 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4858 read_enc);
4859 if (!MBCLEN_NEEDMORE_P(r))
4860 break;
4861 if (fptr->cbuf.len == fptr->cbuf.capa) {
4862 rb_raise(rb_eIOError, "too long character");
4863 }
4864 }
4865
4866 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4867 if (fptr->cbuf.len == 0) {
4868 clear_readconv(fptr);
4869 return Qnil;
4870 }
4871 /* return an unit of an incomplete character just before EOF */
4872 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4873 fptr->cbuf.off += 1;
4874 fptr->cbuf.len -= 1;
4875 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4877 return str;
4878 }
4879 }
4880 if (MBCLEN_INVALID_P(r)) {
4881 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4882 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4883 read_enc);
4884 io_shift_cbuf(fptr, r, &str);
4886 }
4887 else {
4888 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4890 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4891 ISASCII(RSTRING_PTR(str)[0])) {
4892 cr = ENC_CODERANGE_7BIT;
4893 }
4894 }
4895 str = io_enc_str(str, fptr);
4896 ENC_CODERANGE_SET(str, cr);
4897 return str;
4898 }
4899
4900 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4901 if (io_fillbuf(fptr) < 0) {
4902 return Qnil;
4903 }
4904 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4905 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4906 fptr->rbuf.off += 1;
4907 fptr->rbuf.len -= 1;
4908 cr = ENC_CODERANGE_7BIT;
4909 }
4910 else {
4911 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4912 if (MBCLEN_CHARFOUND_P(r) &&
4913 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4914 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4915 fptr->rbuf.off += n;
4916 fptr->rbuf.len -= n;
4918 }
4919 else if (MBCLEN_NEEDMORE_P(r)) {
4920 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4921 fptr->rbuf.len = 0;
4922 getc_needmore:
4923 if (io_fillbuf(fptr) != -1) {
4924 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4925 fptr->rbuf.off++;
4926 fptr->rbuf.len--;
4927 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4928 if (MBCLEN_NEEDMORE_P(r)) {
4929 goto getc_needmore;
4930 }
4931 else if (MBCLEN_CHARFOUND_P(r)) {
4933 }
4934 }
4935 }
4936 else {
4937 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4938 fptr->rbuf.off++;
4939 fptr->rbuf.len--;
4940 }
4941 }
4942 if (!cr) cr = ENC_CODERANGE_BROKEN;
4943 str = io_enc_str(str, fptr);
4944 ENC_CODERANGE_SET(str, cr);
4945 return str;
4946}
4947
4948/*
4949 * call-seq:
4950 * each_char {|c| ... } -> self
4951 * each_char -> enumerator
4952 *
4953 * Calls the given block with each character in the stream; returns +self+.
4954 * See {Character IO}[rdoc-ref:IO@Character+IO].
4955 *
4956 * File.read('t.ja') # => "こんにちは"
4957 * f = File.new('t.ja')
4958 * a = []
4959 * f.each_char {|c| a << c.ord }
4960 * a # => [12371, 12435, 12395, 12385, 12399]
4961 * f.close
4962 *
4963 * Returns an Enumerator if no block is given.
4964 *
4965 * Related: IO#each_byte, IO#each_codepoint.
4966 *
4967 */
4968
4969static VALUE
4970rb_io_each_char(VALUE io)
4971{
4972 rb_io_t *fptr;
4973 rb_encoding *enc;
4974 VALUE c;
4975
4976 RETURN_ENUMERATOR(io, 0, 0);
4977 GetOpenFile(io, fptr);
4979
4980 enc = io_input_encoding(fptr);
4981 READ_CHECK(fptr);
4982 while (!NIL_P(c = io_getc(fptr, enc))) {
4983 rb_yield(c);
4984 }
4985 return io;
4986}
4987
4988/*
4989 * call-seq:
4990 * each_codepoint {|c| ... } -> self
4991 * each_codepoint -> enumerator
4992 *
4993 * Calls the given block with each codepoint in the stream; returns +self+:
4994 *
4995 * File.read('t.ja') # => "こんにちは"
4996 * f = File.new('t.ja')
4997 * a = []
4998 * f.each_codepoint {|c| a << c }
4999 * a # => [12371, 12435, 12395, 12385, 12399]
5000 * f.close
5001 *
5002 * Returns an Enumerator if no block is given.
5003 *
5004 * Related: IO#each_byte, IO#each_char.
5005 *
5006 */
5007
5008static VALUE
5009rb_io_each_codepoint(VALUE io)
5010{
5011 rb_io_t *fptr;
5012 rb_encoding *enc;
5013 unsigned int c;
5014 int r, n;
5015
5016 RETURN_ENUMERATOR(io, 0, 0);
5017 GetOpenFile(io, fptr);
5019
5020 READ_CHECK(fptr);
5021 enc = io_read_encoding(fptr);
5022 if (NEED_READCONV(fptr)) {
5023 SET_BINARY_MODE(fptr);
5024 r = 1; /* no invalid char yet */
5025 for (;;) {
5026 make_readconv(fptr, 0);
5027 for (;;) {
5028 if (fptr->cbuf.len) {
5029 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
5030 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5031 enc);
5032 if (!MBCLEN_NEEDMORE_P(r))
5033 break;
5034 if (fptr->cbuf.len == fptr->cbuf.capa) {
5035 rb_raise(rb_eIOError, "too long character");
5036 }
5037 }
5038 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5039 clear_readconv(fptr);
5040 if (!MBCLEN_CHARFOUND_P(r)) {
5041 goto invalid;
5042 }
5043 return io;
5044 }
5045 }
5046 if (MBCLEN_INVALID_P(r)) {
5047 goto invalid;
5048 }
5049 n = MBCLEN_CHARFOUND_LEN(r);
5050 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
5051 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5052 enc);
5053 fptr->cbuf.off += n;
5054 fptr->cbuf.len -= n;
5055 rb_yield(UINT2NUM(c));
5057 }
5058 }
5059 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5060 while (io_fillbuf(fptr) >= 0) {
5061 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
5062 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5063 if (MBCLEN_CHARFOUND_P(r) &&
5064 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
5065 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
5066 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5067 fptr->rbuf.off += n;
5068 fptr->rbuf.len -= n;
5069 rb_yield(UINT2NUM(c));
5070 }
5071 else if (MBCLEN_INVALID_P(r)) {
5072 goto invalid;
5073 }
5074 else if (MBCLEN_NEEDMORE_P(r)) {
5075 char cbuf[8], *p = cbuf;
5076 int more = MBCLEN_NEEDMORE_LEN(r);
5077 if (more > numberof(cbuf)) goto invalid;
5078 more += n = fptr->rbuf.len;
5079 if (more > numberof(cbuf)) goto invalid;
5080 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
5081 (p += n, (more -= n) > 0)) {
5082 if (io_fillbuf(fptr) < 0) goto invalid;
5083 if ((n = fptr->rbuf.len) > more) n = more;
5084 }
5085 r = rb_enc_precise_mbclen(cbuf, p, enc);
5086 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
5087 c = rb_enc_codepoint(cbuf, p, enc);
5088 rb_yield(UINT2NUM(c));
5089 }
5090 else {
5091 continue;
5092 }
5094 }
5095 return io;
5096
5097 invalid:
5098 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
5100}
5101
5102/*
5103 * call-seq:
5104 * getc -> character or nil
5105 *
5106 * Reads and returns the next 1-character string from the stream;
5107 * returns +nil+ if already at end-of-stream.
5108 * See {Character IO}[rdoc-ref:IO@Character+IO].
5109 *
5110 * f = File.open('t.txt')
5111 * f.getc # => "F"
5112 * f.close
5113 * File.read('t.ja') # => "こんにちは"
5114 * f = File.open('t.ja')
5115 * f.getc.ord # => 12371
5116 * f.close
5117 *
5118 * Related: IO#readchar (may raise EOFError).
5119 *
5120 */
5121
5122static VALUE
5123rb_io_getc(VALUE io)
5124{
5125 rb_io_t *fptr;
5126 rb_encoding *enc;
5127
5128 GetOpenFile(io, fptr);
5130
5131 enc = io_input_encoding(fptr);
5132 READ_CHECK(fptr);
5133 return io_getc(fptr, enc);
5134}
5135
5136/*
5137 * call-seq:
5138 * readchar -> string
5139 *
5140 * Reads and returns the next 1-character string from the stream;
5141 * raises EOFError if already at end-of-stream.
5142 * See {Character IO}[rdoc-ref:IO@Character+IO].
5143 *
5144 * f = File.open('t.txt')
5145 * f.readchar # => "F"
5146 * f.close
5147 * File.read('t.ja') # => "こんにちは"
5148 * f = File.open('t.ja')
5149 * f.readchar.ord # => 12371
5150 * f.close
5151 *
5152 * Related: IO#getc (will not raise EOFError).
5153 *
5154 */
5155
5156static VALUE
5157rb_io_readchar(VALUE io)
5158{
5159 VALUE c = rb_io_getc(io);
5160
5161 if (NIL_P(c)) {
5162 rb_eof_error();
5163 }
5164 return c;
5165}
5166
5167/*
5168 * call-seq:
5169 * getbyte -> integer or nil
5170 *
5171 * Reads and returns the next byte (in range 0..255) from the stream;
5172 * returns +nil+ if already at end-of-stream.
5173 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5174 *
5175 * f = File.open('t.txt')
5176 * f.getbyte # => 70
5177 * f.close
5178 * File.read('t.ja') # => "こんにちは"
5179 * f = File.open('t.ja')
5180 * f.getbyte # => 227
5181 * f.close
5182 *
5183 * Related: IO#readbyte (may raise EOFError).
5184 */
5185
5186VALUE
5188{
5189 rb_io_t *fptr;
5190 int c;
5191
5192 GetOpenFile(io, fptr);
5194 READ_CHECK(fptr);
5195 VALUE r_stdout = rb_ractor_stdout();
5196 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5197 rb_io_t *ofp;
5198 GetOpenFile(r_stdout, ofp);
5199 if (ofp->mode & FMODE_TTY) {
5200 rb_io_flush(r_stdout);
5201 }
5202 }
5203 if (io_fillbuf(fptr) < 0) {
5204 return Qnil;
5205 }
5206 fptr->rbuf.off++;
5207 fptr->rbuf.len--;
5208 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5209 return INT2FIX(c & 0xff);
5210}
5211
5212/*
5213 * call-seq:
5214 * readbyte -> integer
5215 *
5216 * Reads and returns the next byte (in range 0..255) from the stream;
5217 * raises EOFError if already at end-of-stream.
5218 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5219 *
5220 * f = File.open('t.txt')
5221 * f.readbyte # => 70
5222 * f.close
5223 * File.read('t.ja') # => "こんにちは"
5224 * f = File.open('t.ja')
5225 * f.readbyte # => 227
5226 * f.close
5227 *
5228 * Related: IO#getbyte (will not raise EOFError).
5229 *
5230 */
5231
5232static VALUE
5233rb_io_readbyte(VALUE io)
5234{
5235 VALUE c = rb_io_getbyte(io);
5236
5237 if (NIL_P(c)) {
5238 rb_eof_error();
5239 }
5240 return c;
5241}
5242
5243/*
5244 * call-seq:
5245 * ungetbyte(integer) -> nil
5246 * ungetbyte(string) -> nil
5247 *
5248 * Pushes back ("unshifts") the given data onto the stream's buffer,
5249 * placing the data so that it is next to be read; returns +nil+.
5250 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5251 *
5252 * Note that:
5253 *
5254 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5255 * - Calling #rewind on the stream discards the pushed-back data.
5256 *
5257 * When argument +integer+ is given, uses only its low-order byte:
5258 *
5259 * File.write('t.tmp', '012')
5260 * f = File.open('t.tmp')
5261 * f.ungetbyte(0x41) # => nil
5262 * f.read # => "A012"
5263 * f.rewind
5264 * f.ungetbyte(0x4243) # => nil
5265 * f.read # => "C012"
5266 * f.close
5267 *
5268 * When argument +string+ is given, uses all bytes:
5269 *
5270 * File.write('t.tmp', '012')
5271 * f = File.open('t.tmp')
5272 * f.ungetbyte('A') # => nil
5273 * f.read # => "A012"
5274 * f.rewind
5275 * f.ungetbyte('BCDE') # => nil
5276 * f.read # => "BCDE012"
5277 * f.close
5278 *
5279 */
5280
5281VALUE
5283{
5284 rb_io_t *fptr;
5285
5286 GetOpenFile(io, fptr);
5288 switch (TYPE(b)) {
5289 case T_NIL:
5290 return Qnil;
5291 case T_FIXNUM:
5292 case T_BIGNUM: ;
5293 VALUE v = rb_int_modulo(b, INT2FIX(256));
5294 unsigned char c = NUM2INT(v) & 0xFF;
5295 b = rb_str_new((const char *)&c, 1);
5296 break;
5297 default:
5298 StringValue(b);
5299 }
5300 io_ungetbyte(b, fptr);
5301 return Qnil;
5302}
5303
5304/*
5305 * call-seq:
5306 * ungetc(integer) -> nil
5307 * ungetc(string) -> nil
5308 *
5309 * Pushes back ("unshifts") the given data onto the stream's buffer,
5310 * placing the data so that it is next to be read; returns +nil+.
5311 * See {Character IO}[rdoc-ref:IO@Character+IO].
5312 *
5313 * Note that:
5314 *
5315 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5316 * - Calling #rewind on the stream discards the pushed-back data.
5317 *
5318 * When argument +integer+ is given, interprets the integer as a character:
5319 *
5320 * File.write('t.tmp', '012')
5321 * f = File.open('t.tmp')
5322 * f.ungetc(0x41) # => nil
5323 * f.read # => "A012"
5324 * f.rewind
5325 * f.ungetc(0x0442) # => nil
5326 * f.getc.ord # => 1090
5327 * f.close
5328 *
5329 * When argument +string+ is given, uses all characters:
5330 *
5331 * File.write('t.tmp', '012')
5332 * f = File.open('t.tmp')
5333 * f.ungetc('A') # => nil
5334 * f.read # => "A012"
5335 * f.rewind
5336 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5337 * f.getc.ord # => 1090
5338 * f.getc.ord # => 1077
5339 * f.getc.ord # => 1089
5340 * f.getc.ord # => 1090
5341 * f.close
5342 *
5343 */
5344
5345VALUE
5347{
5348 rb_io_t *fptr;
5349 long len;
5350
5351 GetOpenFile(io, fptr);
5353 if (FIXNUM_P(c)) {
5354 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5355 }
5356 else if (RB_BIGNUM_TYPE_P(c)) {
5357 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5358 }
5359 else {
5360 StringValue(c);
5361 }
5362 if (NEED_READCONV(fptr)) {
5363 SET_BINARY_MODE(fptr);
5364 len = RSTRING_LEN(c);
5365#if SIZEOF_LONG > SIZEOF_INT
5366 if (len > INT_MAX)
5367 rb_raise(rb_eIOError, "ungetc failed");
5368#endif
5369 make_readconv(fptr, (int)len);
5370 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5371 rb_raise(rb_eIOError, "ungetc failed");
5372 if (fptr->cbuf.off < len) {
5373 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5374 fptr->cbuf.ptr+fptr->cbuf.off,
5375 char, fptr->cbuf.len);
5376 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5377 }
5378 fptr->cbuf.off -= (int)len;
5379 fptr->cbuf.len += (int)len;
5380 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5381 }
5382 else {
5383 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5384 io_ungetbyte(c, fptr);
5385 }
5386 return Qnil;
5387}
5388
5389/*
5390 * call-seq:
5391 * isatty -> true or false
5392 *
5393 * Returns +true+ if the stream is associated with a terminal device (tty),
5394 * +false+ otherwise:
5395 *
5396 * f = File.new('t.txt').isatty #=> false
5397 * f.close
5398 * f = File.new('/dev/tty').isatty #=> true
5399 * f.close
5400 *
5401 */
5402
5403static VALUE
5404rb_io_isatty(VALUE io)
5405{
5406 rb_io_t *fptr;
5407
5408 GetOpenFile(io, fptr);
5409 return RBOOL(isatty(fptr->fd) != 0);
5410}
5411
5412#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5413/*
5414 * call-seq:
5415 * close_on_exec? -> true or false
5416 *
5417 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5418 *
5419 * f = File.open('t.txt')
5420 * f.close_on_exec? # => true
5421 * f.close_on_exec = false
5422 * f.close_on_exec? # => false
5423 * f.close
5424 *
5425 */
5426
5427static VALUE
5428rb_io_close_on_exec_p(VALUE io)
5429{
5430 rb_io_t *fptr;
5431 VALUE write_io;
5432 int fd, ret;
5433
5434 write_io = GetWriteIO(io);
5435 if (io != write_io) {
5436 GetOpenFile(write_io, fptr);
5437 if (fptr && 0 <= (fd = fptr->fd)) {
5438 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5439 if (!(ret & FD_CLOEXEC)) return Qfalse;
5440 }
5441 }
5442
5443 GetOpenFile(io, fptr);
5444 if (fptr && 0 <= (fd = fptr->fd)) {
5445 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5446 if (!(ret & FD_CLOEXEC)) return Qfalse;
5447 }
5448 return Qtrue;
5449}
5450#else
5451#define rb_io_close_on_exec_p rb_f_notimplement
5452#endif
5453
5454#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5455/*
5456 * call-seq:
5457 * self.close_on_exec = bool -> true or false
5458 *
5459 * Sets a close-on-exec flag.
5460 *
5461 * f = File.open(File::NULL)
5462 * f.close_on_exec = true
5463 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5464 * f.closed? #=> false
5465 *
5466 * Ruby sets close-on-exec flags of all file descriptors by default
5467 * since Ruby 2.0.0.
5468 * So you don't need to set by yourself.
5469 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5470 * if another thread use fork() and exec() (via system() method for example).
5471 * If you really needs file descriptor inheritance to child process,
5472 * use spawn()'s argument such as fd=>fd.
5473 */
5474
5475static VALUE
5476rb_io_set_close_on_exec(VALUE io, VALUE arg)
5477{
5478 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5479 rb_io_t *fptr;
5480 VALUE write_io;
5481 int fd, ret;
5482
5483 write_io = GetWriteIO(io);
5484 if (io != write_io) {
5485 GetOpenFile(write_io, fptr);
5486 if (fptr && 0 <= (fd = fptr->fd)) {
5487 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5488 if ((ret & FD_CLOEXEC) != flag) {
5489 ret = (ret & ~FD_CLOEXEC) | flag;
5490 ret = fcntl(fd, F_SETFD, ret);
5491 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5492 }
5493 }
5494
5495 }
5496
5497 GetOpenFile(io, fptr);
5498 if (fptr && 0 <= (fd = fptr->fd)) {
5499 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5500 if ((ret & FD_CLOEXEC) != flag) {
5501 ret = (ret & ~FD_CLOEXEC) | flag;
5502 ret = fcntl(fd, F_SETFD, ret);
5503 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5504 }
5505 }
5506 return Qnil;
5507}
5508#else
5509#define rb_io_set_close_on_exec rb_f_notimplement
5510#endif
5511
5512#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5513#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5514
5515static VALUE
5516finish_writeconv(rb_io_t *fptr, int noalloc)
5517{
5518 unsigned char *ds, *dp, *de;
5520
5521 if (!fptr->wbuf.ptr) {
5522 unsigned char buf[1024];
5523
5525 while (res == econv_destination_buffer_full) {
5526 ds = dp = buf;
5527 de = buf + sizeof(buf);
5528 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5529 while (dp-ds) {
5530 size_t remaining = dp-ds;
5531 long result = rb_io_write_memory(fptr, ds, remaining);
5532
5533 if (result > 0) {
5534 ds += result;
5535 if ((size_t)result == remaining) break;
5536 }
5537 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5538 if (fptr->fd < 0)
5539 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5540 }
5541 else {
5542 return noalloc ? Qtrue : INT2NUM(errno);
5543 }
5544 }
5545 if (res == econv_invalid_byte_sequence ||
5546 res == econv_incomplete_input ||
5548 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5549 }
5550 }
5551
5552 return Qnil;
5553 }
5554
5556 while (res == econv_destination_buffer_full) {
5557 if (fptr->wbuf.len == fptr->wbuf.capa) {
5558 if (io_fflush(fptr) < 0) {
5559 return noalloc ? Qtrue : INT2NUM(errno);
5560 }
5561 }
5562
5563 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5564 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5565 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5566 fptr->wbuf.len += (int)(dp - ds);
5567 if (res == econv_invalid_byte_sequence ||
5568 res == econv_incomplete_input ||
5570 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5571 }
5572 }
5573 return Qnil;
5574}
5575
5577 rb_io_t *fptr;
5578 int noalloc;
5579};
5580
5581static VALUE
5582finish_writeconv_sync(VALUE arg)
5583{
5584 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5585 return finish_writeconv(p->fptr, p->noalloc);
5586}
5587
5588static void*
5589nogvl_close(void *ptr)
5590{
5591 int *fd = ptr;
5592
5593 return (void*)(intptr_t)close(*fd);
5594}
5595
5596static int
5597maygvl_close(int fd, int keepgvl)
5598{
5599 if (keepgvl)
5600 return close(fd);
5601
5602 /*
5603 * close() may block for certain file types (NFS, SO_LINGER sockets,
5604 * inotify), so let other threads run.
5605 */
5606 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5607}
5608
5609static void*
5610nogvl_fclose(void *ptr)
5611{
5612 FILE *file = ptr;
5613
5614 return (void*)(intptr_t)fclose(file);
5615}
5616
5617static int
5618maygvl_fclose(FILE *file, int keepgvl)
5619{
5620 if (keepgvl)
5621 return fclose(file);
5622
5623 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5624}
5625
5626static void free_io_buffer(rb_io_buffer_t *buf);
5627
5628static void
5629fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5630{
5631 VALUE error = Qnil;
5632 int fd = fptr->fd;
5633 FILE *stdio_file = fptr->stdio_file;
5634 int mode = fptr->mode;
5635
5636 if (fptr->writeconv) {
5637 if (!NIL_P(fptr->write_lock) && !noraise) {
5638 struct finish_writeconv_arg arg;
5639 arg.fptr = fptr;
5640 arg.noalloc = noraise;
5641 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5642 }
5643 else {
5644 error = finish_writeconv(fptr, noraise);
5645 }
5646 }
5647 /* Do not flush the write buffer on close when the stream is in sync
5648 * mode. In sync mode Ruby's write buffer is not authoritative (writes go
5649 * straight to the OS), so any bytes left in the buffer are the result of
5650 * writes made while sync was disabled. Setting sync = true is therefore a
5651 * way to abandon that pending output rather than replaying it on close,
5652 * which matters after an interrupted write where the amount actually
5653 * written is indeterminate. Call flush before enabling sync if the
5654 * buffered data should still be sent. */
5655 if (fptr->wbuf.len && !(fptr->mode & FMODE_SYNC)) {
5656 if (noraise) {
5657 io_flush_buffer_sync(fptr);
5658 }
5659 else {
5660 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5661 error = INT2NUM(errno);
5662 }
5663 }
5664 }
5665
5666 int done = 0;
5667
5668 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5669 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5670 done = 1;
5671 }
5672
5673 fptr->fd = -1;
5674 fptr->stdio_file = 0;
5676
5677 // Wait for blocking operations to ensure they do not hit EBADF:
5678 rb_thread_io_close_wait(fptr);
5679
5680 if (!done && stdio_file) {
5681 // stdio_file is deallocated anyway even if fclose failed.
5682 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5683 if (!noraise) {
5684 error = INT2NUM(errno);
5685 }
5686 }
5687
5688 done = 1;
5689 }
5690
5691 VALUE scheduler = rb_fiber_scheduler_current();
5692 if (!done && fd >= 0 && scheduler != Qnil) {
5693 VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
5694
5695 if (!UNDEF_P(result)) {
5696 done = RTEST(result);
5697 }
5698 }
5699
5700 if (!done && fd >= 0) {
5701 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5702 // We assumes it is closed.
5703
5704 keepgvl |= !(mode & FMODE_WRITABLE);
5705 keepgvl |= noraise;
5706 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5707 if (!noraise) {
5708 error = INT2NUM(errno);
5709 }
5710 }
5711
5712 done = 1;
5713 }
5714
5715 if (!NIL_P(error) && !noraise) {
5716 if (RB_INTEGER_TYPE_P(error))
5717 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5718 else
5719 rb_exc_raise(error);
5720 }
5721}
5722
5723static void
5724fptr_finalize(rb_io_t *fptr, int noraise)
5725{
5726 fptr_finalize_flush(fptr, noraise, FALSE);
5727 free_io_buffer(&fptr->rbuf);
5728 free_io_buffer(&fptr->wbuf);
5729 clear_codeconv(fptr);
5730}
5731
5732static void
5733rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5734{
5735 if (fptr->finalize) {
5736 (*fptr->finalize)(fptr, noraise);
5737 }
5738 else {
5739 fptr_finalize(fptr, noraise);
5740 }
5741}
5742
5743static void
5744free_io_buffer(rb_io_buffer_t *buf)
5745{
5746 if (buf->ptr) {
5747 ruby_xfree_sized(buf->ptr, (size_t)buf->capa);
5748 buf->ptr = NULL;
5749 }
5750 buf->off = buf->len = buf->capa = 0;
5751}
5752
5753static void
5754clear_readconv(rb_io_t *fptr)
5755{
5756 if (fptr->readconv) {
5757 rb_econv_close(fptr->readconv);
5758 fptr->readconv = NULL;
5759 }
5760 free_io_buffer(&fptr->cbuf);
5761}
5762
5763static void
5764clear_writeconv(rb_io_t *fptr)
5765{
5766 if (fptr->writeconv) {
5768 fptr->writeconv = NULL;
5769 }
5770 fptr->writeconv_initialized = 0;
5771}
5772
5773static void
5774clear_codeconv(rb_io_t *fptr)
5775{
5776 clear_readconv(fptr);
5777 clear_writeconv(fptr);
5778}
5779
5780static void
5781rb_io_fptr_cleanup_all(rb_io_t *fptr)
5782{
5783 fptr->pathv = Qnil;
5784 if (0 <= fptr->fd)
5785 rb_io_fptr_cleanup(fptr, TRUE);
5786 fptr->write_lock = Qnil;
5787 free_io_buffer(&fptr->rbuf);
5788 free_io_buffer(&fptr->wbuf);
5789 clear_codeconv(fptr);
5790}
5791
5792int
5794{
5795 if (!io) return 0;
5796 rb_io_fptr_cleanup_all(io);
5797 free(io);
5798
5799 return 1;
5800}
5801
5802bool
5803rb_io_fptr_finalize_closed(struct rb_io *io)
5804{
5805 if (!io) return true;
5806 if (io->fd >= 0) return false;
5808 return true;
5809}
5810
5811size_t
5812rb_io_memsize(const rb_io_t *io)
5813{
5814 size_t size = sizeof(rb_io_t);
5815 size += io->rbuf.capa;
5816 size += io->wbuf.capa;
5817 size += io->cbuf.capa;
5818 if (io->readconv) size += rb_econv_memsize(io->readconv);
5819 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5820
5821 struct rb_io_blocking_operation *blocking_operation = 0;
5822
5823 // 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.
5824 rb_serial_t fork_generation = GET_VM()->fork_gen;
5825 if (io->fork_generation == fork_generation) {
5826 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5827 size += sizeof(struct rb_io_blocking_operation);
5828 }
5829 }
5830
5831 return size;
5832}
5833
5834#ifdef _WIN32
5835/* keep GVL while closing to prevent crash on Windows */
5836# define KEEPGVL TRUE
5837#else
5838# define KEEPGVL FALSE
5839#endif
5840
5841static rb_io_t *
5842io_close_fptr(VALUE io)
5843{
5844 rb_io_t *fptr;
5845 VALUE write_io;
5846 rb_io_t *write_fptr;
5847
5848 write_io = GetWriteIO(io);
5849 if (io != write_io) {
5850 write_fptr = RFILE(write_io)->fptr;
5851 if (write_fptr && 0 <= write_fptr->fd) {
5852 rb_io_fptr_cleanup(write_fptr, TRUE);
5853 }
5854 }
5855
5856 fptr = RFILE(io)->fptr;
5857 if (!fptr) return 0;
5858 if (fptr->fd < 0) return 0;
5859
5860 // This guards against multiple threads closing the same IO object:
5861 if (rb_thread_io_close_interrupt(fptr)) {
5862 /* calls close(fptr->fd): */
5863 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5864 }
5865
5866 rb_io_fptr_cleanup(fptr, FALSE);
5867 return fptr;
5868}
5869
5870static void
5871fptr_waitpid(rb_io_t *fptr, int nohang)
5872{
5873 int status;
5874 if (fptr->pid) {
5875 rb_last_status_clear();
5876 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5877 fptr->pid = 0;
5878 }
5879}
5880
5881VALUE
5883{
5884 rb_io_t *fptr = io_close_fptr(io);
5885 if (fptr) fptr_waitpid(fptr, 0);
5886 return Qnil;
5887}
5888
5889/*
5890 * call-seq:
5891 * close -> nil
5892 *
5893 * Closes the stream for both reading and writing
5894 * if open for either or both; returns +nil+.
5895 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5896 *
5897 * If the stream is open for writing, flushes any buffered writes
5898 * to the operating system before closing.
5899 *
5900 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5901 * (child exit status).
5902 *
5903 * It is not an error to close an IO object that has already been closed.
5904 * It just returns nil.
5905 *
5906 * Example:
5907 *
5908 * IO.popen('ruby', 'r+') do |pipe|
5909 * puts pipe.closed?
5910 * pipe.close
5911 * puts $?
5912 * puts pipe.closed?
5913 * end
5914 *
5915 * Output:
5916 *
5917 * false
5918 * pid 13760 exit 0
5919 * true
5920 *
5921 * Related: IO#close_read, IO#close_write, IO#closed?.
5922 */
5923
5924static VALUE
5925rb_io_close_m(VALUE io)
5926{
5927 rb_io_t *fptr = rb_io_get_fptr(io);
5928 if (fptr->fd < 0) {
5929 return Qnil;
5930 }
5931 rb_io_close(io);
5932 return Qnil;
5933}
5934
5935static VALUE
5936io_call_close(VALUE io)
5937{
5938 rb_check_funcall(io, rb_intern("close"), 0, 0);
5939 return io;
5940}
5941
5942static VALUE
5943ignore_closed_stream(VALUE io, VALUE exc)
5944{
5945 enum {mesg_len = sizeof(closed_stream)-1};
5946 VALUE mesg = rb_attr_get(exc, idMesg);
5947 if (!RB_TYPE_P(mesg, T_STRING) ||
5948 RSTRING_LEN(mesg) != mesg_len ||
5949 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5950 rb_exc_raise(exc);
5951 }
5952 return io;
5953}
5954
5955static VALUE
5956io_close(VALUE io)
5957{
5958 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5959 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5960 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5961 rb_eIOError, (VALUE)0);
5962 return io;
5963}
5964
5965/*
5966 * call-seq:
5967 * closed? -> true or false
5968 *
5969 * Returns +true+ if the stream is closed for both reading and writing,
5970 * +false+ otherwise.
5971 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5972 *
5973 * IO.popen('ruby', 'r+') do |pipe|
5974 * puts pipe.closed?
5975 * pipe.close_read
5976 * puts pipe.closed?
5977 * pipe.close_write
5978 * puts pipe.closed?
5979 * end
5980 *
5981 * Output:
5982 *
5983 * false
5984 * false
5985 * true
5986 *
5987 * Related: IO#close_read, IO#close_write, IO#close.
5988 */
5989VALUE
5991{
5992 rb_io_t *fptr;
5993 VALUE write_io;
5994 rb_io_t *write_fptr;
5995
5996 write_io = GetWriteIO(io);
5997 if (io != write_io) {
5998 write_fptr = RFILE(write_io)->fptr;
5999 if (write_fptr && 0 <= write_fptr->fd) {
6000 return Qfalse;
6001 }
6002 }
6003
6004 fptr = rb_io_get_fptr(io);
6005 return RBOOL(0 > fptr->fd);
6006}
6007
6008/*
6009 * call-seq:
6010 * close_read -> nil
6011 *
6012 * Closes the stream for reading if open for reading;
6013 * returns +nil+.
6014 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6015 *
6016 * If the stream was opened by IO.popen and is also closed for writing,
6017 * sets global variable <tt>$?</tt> (child exit status).
6018 *
6019 * Example:
6020 *
6021 * IO.popen('ruby', 'r+') do |pipe|
6022 * puts pipe.closed?
6023 * pipe.close_write
6024 * puts pipe.closed?
6025 * pipe.close_read
6026 * puts $?
6027 * puts pipe.closed?
6028 * end
6029 *
6030 * Output:
6031 *
6032 * false
6033 * false
6034 * pid 14748 exit 0
6035 * true
6036 *
6037 * Related: IO#close, IO#close_write, IO#closed?.
6038 */
6039
6040static VALUE
6041rb_io_close_read(VALUE io)
6042{
6043 rb_io_t *fptr;
6044 VALUE write_io;
6045
6046 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6047 if (fptr->fd < 0) return Qnil;
6048 if (is_socket(fptr->fd, fptr->pathv)) {
6049#ifndef SHUT_RD
6050# define SHUT_RD 0
6051#endif
6052 if (shutdown(fptr->fd, SHUT_RD) < 0)
6053 rb_sys_fail_path(fptr->pathv);
6054 fptr->mode &= ~FMODE_READABLE;
6055 if (!(fptr->mode & FMODE_WRITABLE))
6056 return rb_io_close(io);
6057 return Qnil;
6058 }
6059
6060 write_io = GetWriteIO(io);
6061 if (io != write_io) {
6062 rb_io_t *wfptr;
6063 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6064 wfptr->pid = fptr->pid;
6065 fptr->pid = 0;
6066 RFILE(io)->fptr = wfptr;
6067 /* bind to write_io temporarily to get rid of memory/fd leak */
6068 fptr->tied_io_for_writing = 0;
6069 RFILE(write_io)->fptr = fptr;
6070 rb_io_fptr_cleanup(fptr, FALSE);
6071 /* should not finalize fptr because another thread may be reading it */
6072 return Qnil;
6073 }
6074
6075 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
6076 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
6077 }
6078 return rb_io_close(io);
6079}
6080
6081/*
6082 * call-seq:
6083 * close_write -> nil
6084 *
6085 * Closes the stream for writing if open for writing;
6086 * returns +nil+.
6087 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6088 *
6089 * Flushes any buffered writes to the operating system before closing.
6090 *
6091 * If the stream was opened by IO.popen and is also closed for reading,
6092 * sets global variable <tt>$?</tt> (child exit status).
6093 *
6094 * IO.popen('ruby', 'r+') do |pipe|
6095 * puts pipe.closed?
6096 * pipe.close_read
6097 * puts pipe.closed?
6098 * pipe.close_write
6099 * puts $?
6100 * puts pipe.closed?
6101 * end
6102 *
6103 * Output:
6104 *
6105 * false
6106 * false
6107 * pid 15044 exit 0
6108 * true
6109 *
6110 * Related: IO#close, IO#close_read, IO#closed?.
6111 */
6112
6113static VALUE
6114rb_io_close_write(VALUE io)
6115{
6116 rb_io_t *fptr;
6117 VALUE write_io;
6118
6119 write_io = GetWriteIO(io);
6120 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6121 if (fptr->fd < 0) return Qnil;
6122 if (is_socket(fptr->fd, fptr->pathv)) {
6123#ifndef SHUT_WR
6124# define SHUT_WR 1
6125#endif
6126 /* Flush any buffered data before shutting down the write side.
6127 * Otherwise the buffered bytes are silently dropped here, and a
6128 * subsequent #close would try to flush them into the now
6129 * shutdown(SHUT_WR) socket and fail with EPIPE. This matches the
6130 * behaviour of the non-socket path below, which flushes via
6131 * rb_io_close(). */
6132 if (fptr->mode & FMODE_WRITABLE) {
6133 if (io_fflush(fptr) < 0)
6134 rb_sys_fail_on_write(fptr);
6135 }
6136 if (shutdown(fptr->fd, SHUT_WR) < 0)
6137 rb_sys_fail_path(fptr->pathv);
6138 fptr->mode &= ~FMODE_WRITABLE;
6139 if (!(fptr->mode & FMODE_READABLE))
6140 return rb_io_close(write_io);
6141 return Qnil;
6142 }
6143
6144 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6145 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6146 }
6147
6148 if (io != write_io) {
6149 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6150 fptr->tied_io_for_writing = 0;
6151 }
6152 rb_io_close(write_io);
6153 return Qnil;
6154}
6155
6156/*
6157 * call-seq:
6158 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6159 *
6160 * Behaves like IO#seek, except that it:
6161 *
6162 * - Uses low-level system functions.
6163 * - Returns the new position.
6164 *
6165 */
6166
6167static VALUE
6168rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6169{
6170 VALUE offset, ptrname;
6171 int whence = SEEK_SET;
6172 rb_io_t *fptr;
6173 rb_off_t pos;
6174
6175 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6176 whence = interpret_seek_whence(ptrname);
6177 }
6178 pos = NUM2OFFT(offset);
6179 GetOpenFile(io, fptr);
6180 if ((fptr->mode & FMODE_READABLE) &&
6181 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6182 rb_raise(rb_eIOError, "sysseek for buffered IO");
6183 }
6184 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6185 rb_warn("sysseek for buffered IO");
6186 }
6187 errno = 0;
6188 pos = lseek(fptr->fd, pos, whence);
6189 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6190
6191 return OFFT2NUM(pos);
6192}
6193
6194/*
6195 * call-seq:
6196 * syswrite(object) -> integer
6197 *
6198 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6199 * returns the number bytes written.
6200 * If +object+ is not a string is converted via method to_s:
6201 *
6202 * f = File.new('t.tmp', 'w')
6203 * f.syswrite('foo') # => 3
6204 * f.syswrite(30) # => 2
6205 * f.syswrite(:foo) # => 3
6206 * f.close
6207 *
6208 * This methods should not be used with other stream-writer methods.
6209 *
6210 */
6211
6212static VALUE
6213rb_io_syswrite(VALUE io, VALUE str)
6214{
6215 VALUE tmp;
6216 rb_io_t *fptr;
6217 long n, len;
6218 const char *ptr;
6219
6220 if (!RB_TYPE_P(str, T_STRING))
6221 str = rb_obj_as_string(str);
6222
6223 io = GetWriteIO(io);
6224 GetOpenFile(io, fptr);
6226
6227 if (fptr->wbuf.len) {
6228 rb_warn("syswrite for buffered IO");
6229 }
6230
6231 tmp = rb_str_tmp_frozen_acquire(str);
6232 RSTRING_GETMEM(tmp, ptr, len);
6233 n = rb_io_write_memory(fptr, ptr, len);
6234 if (n < 0) rb_sys_fail_path(fptr->pathv);
6235 rb_str_tmp_frozen_release(str, tmp);
6236
6237 return LONG2FIX(n);
6238}
6239
6240/*
6241 * call-seq:
6242 * sysread(maxlen) -> string
6243 * sysread(maxlen, out_string) -> string
6244 *
6245 * Behaves like IO#readpartial, except that it uses low-level system functions.
6246 *
6247 * This method should not be used with other stream-reader methods.
6248 *
6249 */
6250
6251static VALUE
6252rb_io_sysread(int argc, VALUE *argv, VALUE io)
6253{
6254 VALUE len, str;
6255 rb_io_t *fptr;
6256 long n, ilen;
6257 struct io_internal_read_struct iis;
6258 int shrinkable;
6259
6260 rb_scan_args(argc, argv, "11", &len, &str);
6261 ilen = NUM2LONG(len);
6262
6263 shrinkable = io_setstrbuf(&str, ilen);
6264 if (ilen == 0) return str;
6265
6266 GetOpenFile(io, fptr);
6268
6269 if (READ_DATA_BUFFERED(fptr)) {
6270 rb_raise(rb_eIOError, "sysread for buffered IO");
6271 }
6272
6273 rb_io_check_closed(fptr);
6274
6275 io_setstrbuf(&str, ilen);
6276 iis.th = rb_thread_current();
6277 iis.fptr = fptr;
6278 iis.nonblock = 0;
6279 iis.fd = fptr->fd;
6280 iis.buf = RSTRING_PTR(str);
6281 iis.capa = ilen;
6282 iis.timeout = NULL;
6283 n = io_read_memory_locktmp(str, &iis);
6284
6285 if (n < 0) {
6286 rb_sys_fail_path(fptr->pathv);
6287 }
6288
6289 io_set_read_length(str, n, shrinkable);
6290
6291 if (n == 0 && ilen > 0) {
6292 rb_eof_error();
6293 }
6294
6295 return str;
6296}
6297
6299 struct rb_io *io;
6300 int fd;
6301 void *buf;
6302 size_t count;
6303 rb_off_t offset;
6304};
6305
6306static VALUE
6307internal_pread_func(void *_arg)
6308{
6309 struct prdwr_internal_arg *arg = _arg;
6310
6311 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6312}
6313
6314static VALUE
6315pread_internal_call(VALUE _arg)
6316{
6317 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6318
6319 VALUE scheduler = rb_fiber_scheduler_current();
6320 if (scheduler != Qnil) {
6321 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6322
6323 if (!UNDEF_P(result)) {
6325 }
6326 }
6327
6328 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6329}
6330
6331/*
6332 * call-seq:
6333 * pread(maxlen, offset) -> string
6334 * pread(maxlen, offset, out_string) -> string
6335 *
6336 * Behaves like IO#readpartial, except that it:
6337 *
6338 * - Reads at the given +offset+ (in bytes).
6339 * - Disregards, and does not modify, the stream's position
6340 * (see {Position}[rdoc-ref:IO@Position]).
6341 * - Bypasses any user space buffering in the stream.
6342 *
6343 * Because this method does not disturb the stream's state
6344 * (its position, in particular), +pread+ allows multiple threads and processes
6345 * to use the same \IO object for reading at various offsets.
6346 *
6347 * f = File.open('t.txt')
6348 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6349 * f.pos # => 52
6350 * # Read 12 bytes at offset 0.
6351 * f.pread(12, 0) # => "First line\n"
6352 * # Read 9 bytes at offset 8.
6353 * f.pread(9, 8) # => "ne\nSecon"
6354 * f.close
6355 *
6356 * Not available on some platforms.
6357 *
6358 */
6359static VALUE
6360rb_io_pread(int argc, VALUE *argv, VALUE io)
6361{
6362 VALUE len, offset, str;
6363 rb_io_t *fptr;
6364 ssize_t n;
6365 struct prdwr_internal_arg arg;
6366 int shrinkable;
6367
6368 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6369 arg.count = NUM2SIZET(len);
6370 arg.offset = NUM2OFFT(offset);
6371
6372 shrinkable = io_setstrbuf(&str, (long)arg.count);
6373 if (arg.count == 0) return str;
6374 arg.buf = RSTRING_PTR(str);
6375
6376 GetOpenFile(io, fptr);
6378
6379 arg.io = fptr;
6380 arg.fd = fptr->fd;
6381 rb_io_check_closed(fptr);
6382
6383 rb_str_locktmp(str);
6384 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6385
6386 if (n < 0) {
6387 rb_sys_fail_path(fptr->pathv);
6388 }
6389 io_set_read_length(str, n, shrinkable);
6390 if (n == 0 && arg.count > 0) {
6391 rb_eof_error();
6392 }
6393
6394 return str;
6395}
6396
6397static VALUE
6398internal_pwrite_func(void *_arg)
6399{
6400 struct prdwr_internal_arg *arg = _arg;
6401
6402 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6403}
6404
6405static VALUE
6406pwrite_internal_call(VALUE _arg)
6407{
6408 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6409
6410 VALUE scheduler = rb_fiber_scheduler_current();
6411 if (scheduler != Qnil) {
6412 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6413
6414 if (!UNDEF_P(result)) {
6416 }
6417 }
6418
6419 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
6420}
6421
6422/*
6423 * call-seq:
6424 * pwrite(object, offset) -> integer
6425 *
6426 * Behaves like IO#write, except that it:
6427 *
6428 * - Writes at the given +offset+ (in bytes).
6429 * - Disregards, and does not modify, the stream's position
6430 * (see {Position}[rdoc-ref:IO@Position]).
6431 * - Bypasses any user space buffering in the stream.
6432 *
6433 * Because this method does not disturb the stream's state
6434 * (its position, in particular), +pwrite+ allows multiple threads and processes
6435 * to use the same \IO object for writing at various offsets.
6436 *
6437 * f = File.open('t.tmp', 'w+')
6438 * # Write 6 bytes at offset 3.
6439 * f.pwrite('ABCDEF', 3) # => 6
6440 * f.rewind
6441 * f.read # => "\u0000\u0000\u0000ABCDEF"
6442 * f.close
6443 *
6444 * Not available on some platforms.
6445 *
6446 */
6447static VALUE
6448rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6449{
6450 rb_io_t *fptr;
6451 ssize_t n;
6452 struct prdwr_internal_arg arg;
6453 VALUE tmp;
6454
6455 if (!RB_TYPE_P(str, T_STRING))
6456 str = rb_obj_as_string(str);
6457
6458 arg.offset = NUM2OFFT(offset);
6459
6460 io = GetWriteIO(io);
6461 GetOpenFile(io, fptr);
6463
6464 arg.io = fptr;
6465 arg.fd = fptr->fd;
6466
6467 tmp = rb_str_tmp_frozen_acquire(str);
6468 arg.buf = RSTRING_PTR(tmp);
6469 arg.count = (size_t)RSTRING_LEN(tmp);
6470
6471 n = (ssize_t)pwrite_internal_call((VALUE)&arg);
6472 if (n < 0) rb_sys_fail_path(fptr->pathv);
6473 rb_str_tmp_frozen_release(str, tmp);
6474
6475 return SSIZET2NUM(n);
6476}
6477
6478VALUE
6480{
6481 rb_io_t *fptr;
6482
6483 GetOpenFile(io, fptr);
6484 if (fptr->readconv)
6486 if (fptr->writeconv)
6488 fptr->mode |= FMODE_BINMODE;
6489 fptr->mode &= ~FMODE_TEXTMODE;
6490 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6491#ifdef O_BINARY
6492 if (!fptr->readconv) {
6493 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6494 }
6495 else {
6496 setmode(fptr->fd, O_BINARY);
6497 }
6498#endif
6499 return io;
6500}
6501
6502static void
6503io_ascii8bit_binmode(rb_io_t *fptr)
6504{
6505 if (fptr->readconv) {
6506 rb_econv_close(fptr->readconv);
6507 fptr->readconv = NULL;
6508 }
6509 if (fptr->writeconv) {
6511 fptr->writeconv = NULL;
6512 }
6513 fptr->mode |= FMODE_BINMODE;
6514 fptr->mode &= ~FMODE_TEXTMODE;
6515 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6516
6517 fptr->encs.enc = rb_ascii8bit_encoding();
6518 fptr->encs.enc2 = NULL;
6519 fptr->encs.ecflags = 0;
6520 fptr->encs.ecopts = Qnil;
6521 clear_codeconv(fptr);
6522}
6523
6524VALUE
6526{
6527 rb_io_t *fptr;
6528
6529 GetOpenFile(io, fptr);
6530 io_ascii8bit_binmode(fptr);
6531
6532 return io;
6533}
6534
6535/*
6536 * call-seq:
6537 * binmode -> self
6538 *
6539 * Sets the stream's data mode as binary
6540 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6541 *
6542 * A stream's data mode may not be changed from binary to text.
6543 *
6544 */
6545
6546static VALUE
6547rb_io_binmode_m(VALUE io)
6548{
6549 VALUE write_io;
6550
6552
6553 write_io = GetWriteIO(io);
6554 if (write_io != io)
6555 rb_io_ascii8bit_binmode(write_io);
6556 return io;
6557}
6558
6559/*
6560 * call-seq:
6561 * binmode? -> true or false
6562 *
6563 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6564 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6565 *
6566 */
6567static VALUE
6568rb_io_binmode_p(VALUE io)
6569{
6570 rb_io_t *fptr;
6571 GetOpenFile(io, fptr);
6572 return RBOOL(fptr->mode & FMODE_BINMODE);
6573}
6574
6575static const char*
6576rb_io_fmode_modestr(enum rb_io_mode fmode)
6577{
6578 if (fmode & FMODE_APPEND) {
6579 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6580 return MODE_BTMODE("a+", "ab+", "at+");
6581 }
6582 return MODE_BTMODE("a", "ab", "at");
6583 }
6584 switch (fmode & FMODE_READWRITE) {
6585 default:
6586 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6587 case FMODE_READABLE:
6588 return MODE_BTMODE("r", "rb", "rt");
6589 case FMODE_WRITABLE:
6590 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6591 case FMODE_READWRITE:
6592 if (fmode & FMODE_CREATE) {
6593 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6594 }
6595 return MODE_BTMODE("r+", "rb+", "rt+");
6596 }
6597}
6598
6599static const char bom_prefix[] = "bom|";
6600static const char utf_prefix[] = "utf-";
6601enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6602enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6603
6604static int
6605io_encname_bom_p(const char *name, long len)
6606{
6607 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6608}
6609
6610enum rb_io_mode
6611rb_io_modestr_fmode(const char *modestr)
6612{
6613 enum rb_io_mode fmode = 0;
6614 const char *m = modestr, *p = NULL;
6615
6616 switch (*m++) {
6617 case 'r':
6618 fmode |= FMODE_READABLE;
6619 break;
6620 case 'w':
6622 break;
6623 case 'a':
6625 break;
6626 default:
6627 goto error;
6628 }
6629
6630 while (*m) {
6631 switch (*m++) {
6632 case 'b':
6633 fmode |= FMODE_BINMODE;
6634 break;
6635 case 't':
6636 fmode |= FMODE_TEXTMODE;
6637 break;
6638 case '+':
6639 fmode |= FMODE_READWRITE;
6640 break;
6641 case 'x':
6642 if (modestr[0] != 'w')
6643 goto error;
6644 fmode |= FMODE_EXCL;
6645 break;
6646 default:
6647 goto error;
6648 case ':':
6649 p = strchr(m, ':');
6650 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6651 fmode |= FMODE_SETENC_BY_BOM;
6652 goto finished;
6653 }
6654 }
6655
6656 finished:
6657 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6658 goto error;
6659
6660 return fmode;
6661
6662 error:
6663 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6665}
6666
6667int
6668rb_io_oflags_fmode(int oflags)
6669{
6670 enum rb_io_mode fmode = 0;
6671
6672 switch (oflags & O_ACCMODE) {
6673 case O_RDONLY:
6674 fmode = FMODE_READABLE;
6675 break;
6676 case O_WRONLY:
6677 fmode = FMODE_WRITABLE;
6678 break;
6679 case O_RDWR:
6680 fmode = FMODE_READWRITE;
6681 break;
6682 }
6683
6684 if (oflags & O_APPEND) {
6685 fmode |= FMODE_APPEND;
6686 }
6687 if (oflags & O_TRUNC) {
6688 fmode |= FMODE_TRUNC;
6689 }
6690 if (oflags & O_CREAT) {
6691 fmode |= FMODE_CREATE;
6692 }
6693 if (oflags & O_EXCL) {
6694 fmode |= FMODE_EXCL;
6695 }
6696#ifdef O_BINARY
6697 if (oflags & O_BINARY) {
6698 fmode |= FMODE_BINMODE;
6699 }
6700#endif
6701
6702 return fmode;
6703}
6704
6705static int
6706rb_io_fmode_oflags(enum rb_io_mode fmode)
6707{
6708 int oflags = 0;
6709
6710 switch (fmode & FMODE_READWRITE) {
6711 case FMODE_READABLE:
6712 oflags |= O_RDONLY;
6713 break;
6714 case FMODE_WRITABLE:
6715 oflags |= O_WRONLY;
6716 break;
6717 case FMODE_READWRITE:
6718 oflags |= O_RDWR;
6719 break;
6720 }
6721
6722 if (fmode & FMODE_APPEND) {
6723 oflags |= O_APPEND;
6724 }
6725 if (fmode & FMODE_TRUNC) {
6726 oflags |= O_TRUNC;
6727 }
6728 if (fmode & FMODE_CREATE) {
6729 oflags |= O_CREAT;
6730 }
6731 if (fmode & FMODE_EXCL) {
6732 oflags |= O_EXCL;
6733 }
6734#ifdef O_BINARY
6735 if (fmode & FMODE_BINMODE) {
6736 oflags |= O_BINARY;
6737 }
6738#endif
6739
6740 return oflags;
6741}
6742
6743int
6744rb_io_modestr_oflags(const char *modestr)
6745{
6746 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6747}
6748
6749static const char*
6750rb_io_oflags_modestr(int oflags)
6751{
6752#ifdef O_BINARY
6753# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6754#else
6755# define MODE_BINARY(a,b) (a)
6756#endif
6757 int accmode;
6758 if (oflags & O_EXCL) {
6759 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6760 }
6761 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6762 if (oflags & O_APPEND) {
6763 if (accmode == O_WRONLY) {
6764 return MODE_BINARY("a", "ab");
6765 }
6766 if (accmode == O_RDWR) {
6767 return MODE_BINARY("a+", "ab+");
6768 }
6769 }
6770 switch (accmode) {
6771 default:
6772 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6773 case O_RDONLY:
6774 return MODE_BINARY("r", "rb");
6775 case O_WRONLY:
6776 return MODE_BINARY("w", "wb");
6777 case O_RDWR:
6778 if (oflags & O_TRUNC) {
6779 return MODE_BINARY("w+", "wb+");
6780 }
6781 return MODE_BINARY("r+", "rb+");
6782 }
6783}
6784
6785/*
6786 * Convert external/internal encodings to enc/enc2
6787 * NULL => use default encoding
6788 * Qnil => no encoding specified (internal only)
6789 */
6790static void
6791rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6792{
6793 int default_ext = 0;
6794
6795 if (ext == NULL) {
6796 ext = rb_default_external_encoding();
6797 default_ext = 1;
6798 }
6799 if (rb_is_ascii8bit_enc(ext)) {
6800 /* If external is ASCII-8BIT, no transcoding */
6801 intern = NULL;
6802 }
6803 else if (intern == NULL) {
6804 intern = rb_default_internal_encoding();
6805 }
6806 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6807 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6808 /* No internal encoding => use external + no transcoding */
6809 *enc = (default_ext && intern != ext) ? NULL : ext;
6810 *enc2 = NULL;
6811 }
6812 else {
6813 *enc = intern;
6814 *enc2 = ext;
6815 }
6816}
6817
6818static void
6819unsupported_encoding(const char *name, rb_encoding *enc)
6820{
6821 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6822}
6823
6824static void
6825parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6826 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6827{
6828 const char *p;
6829 char encname[ENCODING_MAXNAMELEN+1];
6830 int idx, idx2;
6831 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6832 rb_encoding *ext_enc, *int_enc;
6833 long len;
6834
6835 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6836
6837 p = strrchr(estr, ':');
6838 len = p ? (p++ - estr) : (long)strlen(estr);
6839 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6840 estr += bom_prefix_len;
6841 len -= bom_prefix_len;
6842 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6843 fmode |= FMODE_SETENC_BY_BOM;
6844 }
6845 else {
6846 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6847 fmode &= ~FMODE_SETENC_BY_BOM;
6848 }
6849 }
6850 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6851 idx = -1;
6852 }
6853 else {
6854 if (p) {
6855 memcpy(encname, estr, len);
6856 encname[len] = '\0';
6857 estr = encname;
6858 }
6859 idx = rb_enc_find_index(estr);
6860 }
6861 if (fmode_p) *fmode_p = fmode;
6862
6863 if (idx >= 0)
6864 ext_enc = rb_enc_from_index(idx);
6865 else {
6866 if (idx != -2)
6867 unsupported_encoding(estr, estr_enc);
6868 ext_enc = NULL;
6869 }
6870
6871 int_enc = NULL;
6872 if (p) {
6873 if (*p == '-' && *(p+1) == '\0') {
6874 /* Special case - "-" => no transcoding */
6875 int_enc = (rb_encoding *)Qnil;
6876 }
6877 else {
6878 idx2 = rb_enc_find_index(p);
6879 if (idx2 < 0)
6880 unsupported_encoding(p, estr_enc);
6881 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6882 int_enc = (rb_encoding *)Qnil;
6883 }
6884 else
6885 int_enc = rb_enc_from_index(idx2);
6886 }
6887 }
6888
6889 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6890}
6891
6892int
6893rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6894{
6895 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6896 int extracted = 0;
6897 rb_encoding *extencoding = NULL;
6898 rb_encoding *intencoding = NULL;
6899
6900 if (!NIL_P(opt)) {
6901 VALUE v;
6902 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6903 if (v != Qnil) encoding = v;
6904 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6905 if (v != Qnil) extenc = v;
6906 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6907 if (!UNDEF_P(v)) intenc = v;
6908 }
6909 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6910 if (!NIL_P(ruby_verbose)) {
6911 int idx = rb_to_encoding_index(encoding);
6912 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6913 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6914 encoding, UNDEF_P(extenc) ? "internal" : "external");
6915 }
6916 encoding = Qnil;
6917 }
6918 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6919 extencoding = rb_to_encoding(extenc);
6920 }
6921 if (!UNDEF_P(intenc)) {
6922 if (NIL_P(intenc)) {
6923 /* internal_encoding: nil => no transcoding */
6924 intencoding = (rb_encoding *)Qnil;
6925 }
6926 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6927 char *p = StringValueCStr(tmp);
6928
6929 if (*p == '-' && *(p+1) == '\0') {
6930 /* Special case - "-" => no transcoding */
6931 intencoding = (rb_encoding *)Qnil;
6932 }
6933 else {
6934 intencoding = rb_to_encoding(intenc);
6935 }
6936 }
6937 else {
6938 intencoding = rb_to_encoding(intenc);
6939 }
6940 if (extencoding == intencoding) {
6941 intencoding = (rb_encoding *)Qnil;
6942 }
6943 }
6944 if (!NIL_P(encoding)) {
6945 extracted = 1;
6946 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6947 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6948 enc_p, enc2_p, fmode_p);
6949 }
6950 else {
6951 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6952 }
6953 }
6954 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6955 extracted = 1;
6956 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6957 }
6958 return extracted;
6959}
6960
6961static void
6962validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6963{
6964 enum rb_io_mode fmode = *fmode_p;
6965
6966 if ((fmode & FMODE_READABLE) &&
6967 !enc2 &&
6968 !(fmode & FMODE_BINMODE) &&
6969 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6970 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6971
6972 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6973 rb_raise(rb_eArgError, "newline decorator with binary mode");
6974 }
6975 if (!(fmode & FMODE_BINMODE) &&
6976 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6977 fmode |= FMODE_TEXTMODE;
6978 *fmode_p = fmode;
6979 }
6980#if !DEFAULT_TEXTMODE
6981 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6982 fmode &= ~FMODE_TEXTMODE;
6983 *fmode_p = fmode;
6984 }
6985#endif
6986}
6987
6988static void
6989extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
6990{
6991 if (!NIL_P(opthash)) {
6992 VALUE v;
6993 v = rb_hash_aref(opthash, sym_textmode);
6994 if (!NIL_P(v)) {
6995 if (*fmode & FMODE_TEXTMODE)
6996 rb_raise(rb_eArgError, "textmode specified twice");
6997 if (*fmode & FMODE_BINMODE)
6998 rb_raise(rb_eArgError, "both textmode and binmode specified");
6999 if (RTEST(v))
7000 *fmode |= FMODE_TEXTMODE;
7001 }
7002 v = rb_hash_aref(opthash, sym_binmode);
7003 if (!NIL_P(v)) {
7004 if (*fmode & FMODE_BINMODE)
7005 rb_raise(rb_eArgError, "binmode specified twice");
7006 if (*fmode & FMODE_TEXTMODE)
7007 rb_raise(rb_eArgError, "both textmode and binmode specified");
7008 if (RTEST(v))
7009 *fmode |= FMODE_BINMODE;
7010 }
7011
7012 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
7013 rb_raise(rb_eArgError, "both textmode and binmode specified");
7014 }
7015}
7016
7017void
7018rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
7019 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
7020{
7021 VALUE vmode;
7022 int oflags;
7023 enum rb_io_mode fmode;
7024 rb_encoding *enc, *enc2;
7025 int ecflags;
7026 VALUE ecopts;
7027 int has_enc = 0, has_vmode = 0;
7028 VALUE intmode;
7029
7030 vmode = *vmode_p;
7031
7032 /* Set to defaults */
7033 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
7034
7035 vmode_handle:
7036 if (NIL_P(vmode)) {
7037 fmode = FMODE_READABLE;
7038 oflags = O_RDONLY;
7039 }
7040 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
7041 vmode = intmode;
7042 oflags = NUM2INT(intmode);
7043 fmode = rb_io_oflags_fmode(oflags);
7044 }
7045 else {
7046 const char *p;
7047
7048 StringValue(vmode);
7049 p = StringValueCStr(vmode);
7050 fmode = rb_io_modestr_fmode(p);
7051 oflags = rb_io_fmode_oflags(fmode);
7052 p = strchr(p, ':');
7053 if (p) {
7054 has_enc = 1;
7055 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
7056 }
7057 else {
7058 rb_encoding *e;
7059
7060 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7061 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
7062 }
7063 }
7064
7065 if (NIL_P(opthash)) {
7066 ecflags = (fmode & FMODE_READABLE) ?
7069#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7070 ecflags |= (fmode & FMODE_WRITABLE) ?
7071 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7072 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7073#endif
7074 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7075 ecopts = Qnil;
7076 if (fmode & FMODE_BINMODE) {
7077#ifdef O_BINARY
7078 oflags |= O_BINARY;
7079#endif
7080 if (!has_enc)
7081 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7082 }
7083#if DEFAULT_TEXTMODE
7084 else if (NIL_P(vmode)) {
7085 fmode |= DEFAULT_TEXTMODE;
7086 }
7087#endif
7088 }
7089 else {
7090 VALUE v;
7091 if (!has_vmode) {
7092 v = rb_hash_aref(opthash, sym_mode);
7093 if (!NIL_P(v)) {
7094 if (!NIL_P(vmode)) {
7095 rb_raise(rb_eArgError, "mode specified twice");
7096 }
7097 has_vmode = 1;
7098 vmode = v;
7099 goto vmode_handle;
7100 }
7101 }
7102 v = rb_hash_aref(opthash, sym_flags);
7103 if (!NIL_P(v)) {
7104 v = rb_to_int(v);
7105 oflags |= NUM2INT(v);
7106 vmode = INT2NUM(oflags);
7107 fmode = rb_io_oflags_fmode(oflags);
7108 }
7109 extract_binmode(opthash, &fmode);
7110 if (fmode & FMODE_BINMODE) {
7111#ifdef O_BINARY
7112 oflags |= O_BINARY;
7113#endif
7114 if (!has_enc)
7115 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7116 }
7117#if DEFAULT_TEXTMODE
7118 else if (NIL_P(vmode)) {
7119 fmode |= DEFAULT_TEXTMODE;
7120 }
7121#endif
7122 v = rb_hash_aref(opthash, sym_perm);
7123 if (!NIL_P(v)) {
7124 if (vperm_p) {
7125 if (!NIL_P(*vperm_p)) {
7126 rb_raise(rb_eArgError, "perm specified twice");
7127 }
7128 *vperm_p = v;
7129 }
7130 else {
7131 /* perm no use, just ignore */
7132 }
7133 }
7134 ecflags = (fmode & FMODE_READABLE) ?
7137#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7138 ecflags |= (fmode & FMODE_WRITABLE) ?
7139 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7140 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7141#endif
7142
7143 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7144 if (has_enc) {
7145 rb_raise(rb_eArgError, "encoding specified twice");
7146 }
7147 }
7148 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7149 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7150 }
7151
7152 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7153
7154 *vmode_p = vmode;
7155
7156 *oflags_p = oflags;
7157 *fmode_p = fmode;
7158 convconfig_p->enc = enc;
7159 convconfig_p->enc2 = enc2;
7160 convconfig_p->ecflags = ecflags;
7161 convconfig_p->ecopts = ecopts;
7162}
7163
7165 VALUE fname;
7166 int oflags;
7167 mode_t perm;
7168};
7169
7170static void *
7171sysopen_func(void *ptr)
7172{
7173 const struct sysopen_struct *data = ptr;
7174 const char *fname = RSTRING_PTR(data->fname);
7175 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7176}
7177
7178static inline int
7179rb_sysopen_internal(struct sysopen_struct *data)
7180{
7181 int fd;
7182 do {
7183 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7184 } while (fd < 0 && errno == EINTR);
7185 if (0 <= fd)
7186 rb_update_max_fd(fd);
7187 return fd;
7188}
7189
7190static int
7191rb_sysopen(VALUE fname, int oflags, mode_t perm)
7192{
7193 int fd = -1;
7194 struct sysopen_struct data;
7195
7196 data.fname = rb_str_encode_ospath(fname);
7197 StringValueCStr(data.fname);
7198 data.oflags = oflags;
7199 data.perm = perm;
7200
7201 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7202 rb_syserr_fail_path(first_errno, fname);
7203 }
7204 return fd;
7205}
7206
7207static inline FILE *
7208fdopen_internal(int fd, const char *modestr)
7209{
7210 FILE *file;
7211
7212#if defined(__sun)
7213 errno = 0;
7214#endif
7215 file = fdopen(fd, modestr);
7216 if (!file) {
7217#ifdef _WIN32
7218 if (errno == 0) errno = EINVAL;
7219#elif defined(__sun)
7220 if (errno == 0) errno = EMFILE;
7221#endif
7222 }
7223 return file;
7224}
7225
7226FILE *
7227rb_fdopen(int fd, const char *modestr)
7228{
7229 FILE *file = 0;
7230
7231 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7232 rb_syserr_fail(first_errno, 0);
7233 }
7234
7235 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7236#ifdef USE_SETVBUF
7237 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7238 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7239#endif
7240 return file;
7241}
7242
7243static int
7244io_check_tty(rb_io_t *fptr)
7245{
7246 int t = isatty(fptr->fd);
7247 if (t)
7248 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7249 return t;
7250}
7251
7252static VALUE rb_io_internal_encoding(VALUE);
7253static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7254
7255static int
7256io_strip_bom(VALUE io)
7257{
7258 VALUE b1, b2, b3, b4;
7259 rb_io_t *fptr;
7260
7261 GetOpenFile(io, fptr);
7262 if (!(fptr->mode & FMODE_READABLE)) return 0;
7263 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7264 switch (b1) {
7265 case INT2FIX(0xEF):
7266 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7267 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7268 if (b3 == INT2FIX(0xBF)) {
7269 return rb_utf8_encindex();
7270 }
7271 rb_io_ungetbyte(io, b3);
7272 }
7273 rb_io_ungetbyte(io, b2);
7274 break;
7275
7276 case INT2FIX(0xFE):
7277 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7278 if (b2 == INT2FIX(0xFF)) {
7279 return ENCINDEX_UTF_16BE;
7280 }
7281 rb_io_ungetbyte(io, b2);
7282 break;
7283
7284 case INT2FIX(0xFF):
7285 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7286 if (b2 == INT2FIX(0xFE)) {
7287 b3 = rb_io_getbyte(io);
7288 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7289 if (b4 == INT2FIX(0)) {
7290 return ENCINDEX_UTF_32LE;
7291 }
7292 rb_io_ungetbyte(io, b4);
7293 }
7294 rb_io_ungetbyte(io, b3);
7295 return ENCINDEX_UTF_16LE;
7296 }
7297 rb_io_ungetbyte(io, b2);
7298 break;
7299
7300 case INT2FIX(0):
7301 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7302 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7303 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7304 if (b4 == INT2FIX(0xFF)) {
7305 return ENCINDEX_UTF_32BE;
7306 }
7307 rb_io_ungetbyte(io, b4);
7308 }
7309 rb_io_ungetbyte(io, b3);
7310 }
7311 rb_io_ungetbyte(io, b2);
7312 break;
7313 }
7314 rb_io_ungetbyte(io, b1);
7315 return 0;
7316}
7317
7318static rb_encoding *
7319io_set_encoding_by_bom(VALUE io)
7320{
7321 int idx = io_strip_bom(io);
7322 rb_io_t *fptr;
7323 rb_encoding *extenc = NULL;
7324
7325 GetOpenFile(io, fptr);
7326 if (idx) {
7327 extenc = rb_enc_from_index(idx);
7328 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7329 rb_io_internal_encoding(io), Qnil);
7330 }
7331 else {
7332 fptr->encs.enc2 = NULL;
7333 }
7334 return extenc;
7335}
7336
7337static VALUE
7338rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7339 const struct rb_io_encoding *convconfig, mode_t perm)
7340{
7341 VALUE pathv;
7342 rb_io_t *fptr;
7343 struct rb_io_encoding cc;
7344 if (!convconfig) {
7345 /* Set to default encodings */
7346 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7347 cc.ecflags = 0;
7348 cc.ecopts = Qnil;
7349 convconfig = &cc;
7350 }
7351 validate_enc_binmode(&fmode, convconfig->ecflags,
7352 convconfig->enc, convconfig->enc2);
7353
7354 MakeOpenFile(io, fptr);
7355 fptr->mode = fmode;
7356 fptr->encs = *convconfig;
7357 pathv = rb_str_new_frozen(filename);
7358#ifdef O_TMPFILE
7359 if (!(oflags & O_TMPFILE)) {
7360 fptr->pathv = pathv;
7361 }
7362#else
7363 fptr->pathv = pathv;
7364#endif
7365 fptr->fd = rb_sysopen(pathv, oflags, perm);
7366 io_check_tty(fptr);
7367 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7368
7369 return io;
7370}
7371
7372static VALUE
7373rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7374{
7375 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7376 const char *p = strchr(modestr, ':');
7377 struct rb_io_encoding convconfig;
7378
7379 if (p) {
7380 parse_mode_enc(p+1, rb_usascii_encoding(),
7381 &convconfig.enc, &convconfig.enc2, &fmode);
7382 }
7383 else {
7384 rb_encoding *e;
7385 /* Set to default encodings */
7386
7387 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7388 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7389 }
7390
7391 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7394#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7395 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7396 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7397 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7398#endif
7399 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7400 convconfig.ecopts = Qnil;
7401
7402 return rb_file_open_generic(io, filename,
7403 rb_io_fmode_oflags(fmode),
7404 fmode,
7405 &convconfig,
7406 0666);
7407}
7408
7409VALUE
7410rb_file_open_str(VALUE fname, const char *modestr)
7411{
7412 FilePathValue(fname);
7413 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7414}
7415
7416VALUE
7417rb_file_open(const char *fname, const char *modestr)
7418{
7419 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7420}
7421
7422#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7423static struct pipe_list {
7424 rb_io_t *fptr;
7425 struct pipe_list *next;
7426} *pipe_list;
7427
7428static void
7429pipe_add_fptr(rb_io_t *fptr)
7430{
7431 struct pipe_list *list;
7432
7433 list = ALLOC(struct pipe_list);
7434 list->fptr = fptr;
7435 list->next = pipe_list;
7436 pipe_list = list;
7437}
7438
7439static void
7440pipe_del_fptr(rb_io_t *fptr)
7441{
7442 struct pipe_list **prev = &pipe_list;
7443 struct pipe_list *tmp;
7444
7445 while ((tmp = *prev) != 0) {
7446 if (tmp->fptr == fptr) {
7447 *prev = tmp->next;
7448 free(tmp);
7449 return;
7450 }
7451 prev = &tmp->next;
7452 }
7453}
7454
7455#if defined (_WIN32) || defined(__CYGWIN__)
7456static void
7457pipe_atexit(void)
7458{
7459 struct pipe_list *list = pipe_list;
7460 struct pipe_list *tmp;
7461
7462 while (list) {
7463 tmp = list->next;
7464 rb_io_fptr_finalize(list->fptr);
7465 list = tmp;
7466 }
7467}
7468#endif
7469
7470static void
7471pipe_finalize(rb_io_t *fptr, int noraise)
7472{
7473#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7474 int status = 0;
7475 if (fptr->stdio_file) {
7476 status = pclose(fptr->stdio_file);
7477 }
7478 fptr->fd = -1;
7479 fptr->stdio_file = 0;
7480 rb_last_status_set(status, fptr->pid);
7481#else
7482 fptr_finalize(fptr, noraise);
7483#endif
7484 pipe_del_fptr(fptr);
7485}
7486#endif
7487
7488static void
7489fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7490{
7491#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7492 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7493
7494 if (old_finalize == orig->finalize) return;
7495#endif
7496
7497 fptr->finalize = orig->finalize;
7498
7499#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7500 if (old_finalize != pipe_finalize) {
7501 struct pipe_list *list;
7502 for (list = pipe_list; list; list = list->next) {
7503 if (list->fptr == fptr) break;
7504 }
7505 if (!list) pipe_add_fptr(fptr);
7506 }
7507 else {
7508 pipe_del_fptr(fptr);
7509 }
7510#endif
7511}
7512
7513void
7515{
7517 fptr->mode |= FMODE_SYNC;
7518}
7519
7520
7521int
7522rb_pipe(int *pipes)
7523{
7524 int ret;
7525 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7526 if (ret == 0) {
7527 rb_update_max_fd(pipes[0]);
7528 rb_update_max_fd(pipes[1]);
7529 }
7530 return ret;
7531}
7532
7533#ifdef _WIN32
7534#define HAVE_SPAWNV 1
7535#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7536#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7537#endif
7538
7539#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7540struct popen_arg {
7541 VALUE execarg_obj;
7542 struct rb_execarg *eargp;
7543 int modef;
7544 int pair[2];
7545 int write_pair[2];
7546};
7547#endif
7548
7549#ifdef HAVE_WORKING_FORK
7550# ifndef __EMSCRIPTEN__
7551static void
7552popen_redirect(struct popen_arg *p)
7553{
7554 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7555 close(p->write_pair[1]);
7556 if (p->write_pair[0] != 0) {
7557 dup2(p->write_pair[0], 0);
7558 close(p->write_pair[0]);
7559 }
7560 close(p->pair[0]);
7561 if (p->pair[1] != 1) {
7562 dup2(p->pair[1], 1);
7563 close(p->pair[1]);
7564 }
7565 }
7566 else if (p->modef & FMODE_READABLE) {
7567 close(p->pair[0]);
7568 if (p->pair[1] != 1) {
7569 dup2(p->pair[1], 1);
7570 close(p->pair[1]);
7571 }
7572 }
7573 else {
7574 close(p->pair[1]);
7575 if (p->pair[0] != 0) {
7576 dup2(p->pair[0], 0);
7577 close(p->pair[0]);
7578 }
7579 }
7580}
7581# endif
7582
7583#if defined(__linux__)
7584/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7585 * Since /proc may not be available, linux_get_maxfd is just a hint.
7586 * This function, linux_get_maxfd, must be async-signal-safe.
7587 * I.e. opendir() is not usable.
7588 *
7589 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7590 * However they are easy to re-implement in async-signal-safe manner.
7591 * (Also note that there is missing/memcmp.c.)
7592 */
7593static int
7594linux_get_maxfd(void)
7595{
7596 int fd;
7597 char buf[4096], *p, *np, *e;
7598 ssize_t ss;
7599 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7600 if (fd < 0) return fd;
7601 ss = read(fd, buf, sizeof(buf));
7602 if (ss < 0) goto err;
7603 p = buf;
7604 e = buf + ss;
7605 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7606 (np = memchr(p, '\n', e-p)) != NULL) {
7607 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7608 int fdsize;
7609 p += sizeof("FDSize:")-1;
7610 *np = '\0';
7611 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7612 close(fd);
7613 return fdsize;
7614 }
7615 p = np+1;
7616 }
7617 /* fall through */
7618
7619 err:
7620 close(fd);
7621 return (int)ss;
7622}
7623#endif
7624
7625/* This function should be async-signal-safe. */
7626void
7627rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7628{
7629#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7630 int fd, ret;
7631 int max = (int)max_file_descriptor;
7632# ifdef F_MAXFD
7633 /* F_MAXFD is available since NetBSD 2.0. */
7634 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7635 if (ret != -1)
7636 maxhint = max = ret;
7637# elif defined(__linux__)
7638 ret = linux_get_maxfd();
7639 if (maxhint < ret)
7640 maxhint = ret;
7641 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7642# endif
7643 if (max < maxhint)
7644 max = maxhint;
7645 for (fd = lowfd; fd <= max; fd++) {
7646 if (!NIL_P(noclose_fds) &&
7647 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7648 continue;
7649 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7650 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7651 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7652 }
7653# define CONTIGUOUS_CLOSED_FDS 20
7654 if (ret != -1) {
7655 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7656 max = fd + CONTIGUOUS_CLOSED_FDS;
7657 }
7658 }
7659#endif
7660}
7661
7662# ifndef __EMSCRIPTEN__
7663static int
7664popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7665{
7666 struct popen_arg *p = (struct popen_arg*)pp;
7667
7668 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7669}
7670# endif
7671#endif
7672
7673#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7674static VALUE
7675rb_execarg_fixup_v(VALUE execarg_obj)
7676{
7677 rb_execarg_parent_start(execarg_obj);
7678 return Qnil;
7679}
7680#else
7681char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7682#endif
7683
7684#ifndef __EMSCRIPTEN__
7685static VALUE
7686pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7687 const struct rb_io_encoding *convconfig)
7688{
7689 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7690 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7691 rb_pid_t pid = 0;
7692 rb_io_t *fptr;
7693 VALUE port;
7694 rb_io_t *write_fptr;
7695 VALUE write_port;
7696#if defined(HAVE_WORKING_FORK)
7697 int status;
7698 char errmsg[80] = { '\0' };
7699#endif
7700#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7701 int state;
7702 struct popen_arg arg;
7703#endif
7704 int e = 0;
7705#if defined(HAVE_SPAWNV)
7706# if defined(HAVE_SPAWNVE)
7707# define DO_SPAWN(cmd, args, envp) ((args) ? \
7708 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7709 spawne(P_NOWAIT, (cmd), (envp)))
7710# else
7711# define DO_SPAWN(cmd, args, envp) ((args) ? \
7712 spawnv(P_NOWAIT, (cmd), (args)) : \
7713 spawn(P_NOWAIT, (cmd)))
7714# endif
7715# if !defined(HAVE_WORKING_FORK)
7716 char **args = NULL;
7717# if defined(HAVE_SPAWNVE)
7718 char **envp = NULL;
7719# endif
7720# endif
7721#endif
7722#if !defined(HAVE_WORKING_FORK)
7723 struct rb_execarg sarg, *sargp = &sarg;
7724#endif
7725 FILE *fp = 0;
7726 int fd = -1;
7727 int write_fd = -1;
7728#if !defined(HAVE_WORKING_FORK)
7729 const char *cmd = 0;
7730
7731 if (prog)
7732 cmd = StringValueCStr(prog);
7733#endif
7734
7735#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7736 arg.execarg_obj = execarg_obj;
7737 arg.eargp = eargp;
7738 arg.modef = fmode;
7739 arg.pair[0] = arg.pair[1] = -1;
7740 arg.write_pair[0] = arg.write_pair[1] = -1;
7741# if !defined(HAVE_WORKING_FORK)
7742 if (eargp && !eargp->use_shell) {
7743 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7744 }
7745# endif
7746 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7748 if (rb_pipe(arg.write_pair) < 0)
7749 rb_sys_fail_str(prog);
7750 if (rb_pipe(arg.pair) < 0) {
7751 e = errno;
7752 close(arg.write_pair[0]);
7753 close(arg.write_pair[1]);
7754 rb_syserr_fail_str(e, prog);
7755 }
7756 if (eargp) {
7757 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7758 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7759 }
7760 break;
7761 case FMODE_READABLE:
7762 if (rb_pipe(arg.pair) < 0)
7763 rb_sys_fail_str(prog);
7764 if (eargp)
7765 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7766 break;
7767 case FMODE_WRITABLE:
7768 if (rb_pipe(arg.pair) < 0)
7769 rb_sys_fail_str(prog);
7770 if (eargp)
7771 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7772 break;
7773 default:
7774 rb_sys_fail_str(prog);
7775 }
7776 if (!NIL_P(execarg_obj)) {
7777 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7778 if (state) {
7779 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7780 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7781 if (0 <= arg.pair[0]) close(arg.pair[0]);
7782 if (0 <= arg.pair[1]) close(arg.pair[1]);
7783 rb_execarg_parent_end(execarg_obj);
7784 rb_jump_tag(state);
7785 }
7786
7787# if defined(HAVE_WORKING_FORK)
7788 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7789# else
7790 rb_execarg_run_options(eargp, sargp, NULL, 0);
7791# if defined(HAVE_SPAWNVE)
7792 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7793# endif
7794 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7795 /* exec failed */
7796 switch (e = errno) {
7797 case EAGAIN:
7798# if EWOULDBLOCK != EAGAIN
7799 case EWOULDBLOCK:
7800# endif
7801 rb_thread_sleep(1);
7802 continue;
7803 }
7804 break;
7805 }
7806 if (eargp)
7807 rb_execarg_run_options(sargp, NULL, NULL, 0);
7808# endif
7809 rb_execarg_parent_end(execarg_obj);
7810 }
7811 else {
7812# if defined(HAVE_WORKING_FORK)
7813 pid = rb_call_proc__fork();
7814 if (pid == 0) { /* child */
7815 popen_redirect(&arg);
7816 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7817 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7818 return Qnil;
7819 }
7820# else
7821 rb_notimplement();
7822# endif
7823 }
7824
7825 /* parent */
7826 if (pid < 0) {
7827# if defined(HAVE_WORKING_FORK)
7828 e = errno;
7829# endif
7830 close(arg.pair[0]);
7831 close(arg.pair[1]);
7833 close(arg.write_pair[0]);
7834 close(arg.write_pair[1]);
7835 }
7836# if defined(HAVE_WORKING_FORK)
7837 if (errmsg[0])
7838 rb_syserr_fail(e, errmsg);
7839# endif
7840 rb_syserr_fail_str(e, prog);
7841 }
7842 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7843 close(arg.pair[1]);
7844 fd = arg.pair[0];
7845 close(arg.write_pair[0]);
7846 write_fd = arg.write_pair[1];
7847 }
7848 else if (fmode & FMODE_READABLE) {
7849 close(arg.pair[1]);
7850 fd = arg.pair[0];
7851 }
7852 else {
7853 close(arg.pair[0]);
7854 fd = arg.pair[1];
7855 }
7856#else
7857 cmd = rb_execarg_commandline(eargp, &prog);
7858 if (!NIL_P(execarg_obj)) {
7859 rb_execarg_parent_start(execarg_obj);
7860 rb_execarg_run_options(eargp, sargp, NULL, 0);
7861 }
7862 fp = popen(cmd, modestr);
7863 e = errno;
7864 if (eargp) {
7865 rb_execarg_parent_end(execarg_obj);
7866 rb_execarg_run_options(sargp, NULL, NULL, 0);
7867 }
7868 if (!fp) rb_syserr_fail_path(e, prog);
7869 fd = fileno(fp);
7870#endif
7871
7872 port = io_alloc(rb_cIO);
7873 MakeOpenFile(port, fptr);
7874 fptr->fd = fd;
7875 fptr->stdio_file = fp;
7876 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7877 if (convconfig) {
7878 fptr->encs = *convconfig;
7879#if RUBY_CRLF_ENVIRONMENT
7882 }
7883#endif
7884 }
7885 else {
7886 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7888 }
7889#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7890 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7891 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7892 }
7893#endif
7894 }
7895 fptr->pid = pid;
7896
7897 if (0 <= write_fd) {
7898 write_port = io_alloc(rb_cIO);
7899 MakeOpenFile(write_port, write_fptr);
7900 write_fptr->fd = write_fd;
7901 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7902 fptr->mode &= ~FMODE_WRITABLE;
7903 fptr->tied_io_for_writing = write_port;
7904 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7905 }
7906
7907#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7908 fptr->finalize = pipe_finalize;
7909 pipe_add_fptr(fptr);
7910#endif
7911 return port;
7912}
7913#else
7914static VALUE
7915pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7916 const struct rb_io_encoding *convconfig)
7917{
7918 rb_raise(rb_eNotImpError, "popen() is not available");
7919}
7920#endif
7921
7922static int
7923is_popen_fork(VALUE prog)
7924{
7925 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7926#if !defined(HAVE_WORKING_FORK)
7927 rb_raise(rb_eNotImpError,
7928 "fork() function is unimplemented on this machine");
7929#else
7930 return TRUE;
7931#endif
7932 }
7933 return FALSE;
7934}
7935
7936static VALUE
7937pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
7938 const struct rb_io_encoding *convconfig)
7939{
7940 int argc = 1;
7941 VALUE *argv = &prog;
7942 VALUE execarg_obj = Qnil;
7943
7944 if (!is_popen_fork(prog))
7945 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7946 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7947}
7948
7949static VALUE
7950pipe_close(VALUE io)
7951{
7952 rb_io_t *fptr = io_close_fptr(io);
7953 if (fptr) {
7954 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7955 }
7956 return Qnil;
7957}
7958
7959static VALUE popen_finish(VALUE port, VALUE klass);
7960
7961/*
7962 * call-seq:
7963 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7964 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7965 *
7966 * Executes the given command +cmd+ as a subprocess
7967 * whose $stdin and $stdout are connected to a new stream +io+.
7968 *
7969 * This method has potential security vulnerabilities if called with untrusted input;
7970 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
7971 *
7972 * If no block is given, returns the new stream,
7973 * which depending on given +mode+ may be open for reading, writing, or both.
7974 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7975 *
7976 * If a block is given, the stream is passed to the block
7977 * (again, open for reading, writing, or both);
7978 * when the block exits, the stream is closed,
7979 * the block's value is returned,
7980 * and the global variable <tt>$?</tt> is set to the child's exit status.
7981 *
7982 * Optional argument +mode+ may be any valid \IO mode.
7983 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7984 *
7985 * Required argument +cmd+ determines which of the following occurs:
7986 *
7987 * - The process forks.
7988 * - A specified program runs in a shell.
7989 * - A specified program runs with specified arguments.
7990 * - A specified program runs with specified arguments and a specified +argv0+.
7991 *
7992 * Each of these is detailed below.
7993 *
7994 * The optional hash argument +env+ specifies name/value pairs that are to be added
7995 * to the environment variables for the subprocess:
7996 *
7997 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7998 * pipe.puts 'puts ENV["FOO"]'
7999 * pipe.close_write
8000 * pipe.gets
8001 * end => "bar\n"
8002 *
8003 * Optional keyword arguments +opts+ specify:
8004 *
8005 * - {Open options}[rdoc-ref:IO@Open+Options].
8006 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8007 * - Options for Kernel#spawn.
8008 *
8009 * <b>Forked Process</b>
8010 *
8011 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
8012 * IO.popen('-') do |pipe|
8013 * if pipe
8014 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
8015 * else
8016 * $stderr.puts "In child, pid is #{$$}\n"
8017 * end
8018 * end
8019 *
8020 * Output:
8021 *
8022 * In parent, child pid is 26253
8023 * In child, pid is 26253
8024 *
8025 * Note that this is not supported on all platforms.
8026 *
8027 * <b>Shell Subprocess</b>
8028 *
8029 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
8030 * the program named +cmd+ is run as a shell command:
8031 *
8032 * IO.popen('uname') do |pipe|
8033 * pipe.readlines
8034 * end
8035 *
8036 * Output:
8037 *
8038 * ["Linux\n"]
8039 *
8040 * Another example:
8041 *
8042 * IO.popen('/bin/sh', 'r+') do |pipe|
8043 * pipe.puts('ls')
8044 * pipe.close_write
8045 * $stderr.puts pipe.readlines.size
8046 * end
8047 *
8048 * Output:
8049 *
8050 * 213
8051 *
8052 * <b>Program Subprocess</b>
8053 *
8054 * When argument +cmd+ is an array of strings,
8055 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
8056 *
8057 * IO.popen(['du', '..', '.']) do |pipe|
8058 * $stderr.puts pipe.readlines.size
8059 * end
8060 *
8061 * Output:
8062 *
8063 * 1111
8064 *
8065 * <b>Program Subprocess with <tt>argv0</tt></b>
8066 *
8067 * When argument +cmd+ is an array whose first element is a 2-element string array
8068 * and whose remaining elements (if any) are strings:
8069 *
8070 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
8071 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
8072 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
8073 *
8074 * Example (sets <tt>$0</tt> to 'foo'):
8075 *
8076 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
8077 *
8078 * <b>Some Special Examples</b>
8079 *
8080 * # Set IO encoding.
8081 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
8082 * euc_jp_string = nkf_io.read
8083 * }
8084 *
8085 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
8086 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
8087 * ls_result_with_error = io.read
8088 * end
8089 *
8090 * # Use mixture of spawn options and IO options.
8091 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
8092 * ls_result_with_error = io.read
8093 * end
8094 *
8095 * f = IO.popen("uname")
8096 * p f.readlines
8097 * f.close
8098 * puts "Parent is #{Process.pid}"
8099 * IO.popen("date") {|f| puts f.gets }
8100 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
8101 * p $?
8102 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
8103 * f.puts "bar"; f.close_write; puts f.gets
8104 * }
8105 *
8106 * Output (from last section):
8107 *
8108 * ["Linux\n"]
8109 * Parent is 21346
8110 * Thu Jan 15 22:41:19 JST 2009
8111 * 21346 is here, f is #<IO:fd 3>
8112 * 21352 is here, f is nil
8113 * #<Process::Status: pid 21352 exit 0>
8114 * <foo>bar;zot;
8115 *
8116 * Raises exceptions that IO.pipe and Kernel.spawn raise.
8117 *
8118 */
8119
8120static VALUE
8121rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
8122{
8123 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
8124
8125 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8126 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8127 switch (argc) {
8128 case 2:
8129 pmode = argv[1];
8130 case 1:
8131 pname = argv[0];
8132 break;
8133 default:
8134 {
8135 int ex = !NIL_P(opt);
8136 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8137 }
8138 }
8139 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8140}
8141
8142VALUE
8143rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8144{
8145 const char *modestr;
8146 VALUE tmp, execarg_obj = Qnil;
8147 int oflags;
8148 enum rb_io_mode fmode;
8149 struct rb_io_encoding convconfig;
8150
8151 tmp = rb_check_array_type(pname);
8152 if (!NIL_P(tmp)) {
8153 long len = RARRAY_LEN(tmp);
8154#if SIZEOF_LONG > SIZEOF_INT
8155 if (len > INT_MAX) {
8156 rb_raise(rb_eArgError, "too many arguments");
8157 }
8158#endif
8159 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8160 RB_GC_GUARD(tmp);
8161 }
8162 else {
8163 StringValue(pname);
8164 execarg_obj = Qnil;
8165 if (!is_popen_fork(pname))
8166 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8167 }
8168 if (!NIL_P(execarg_obj)) {
8169 if (!NIL_P(opt))
8170 opt = rb_execarg_extract_options(execarg_obj, opt);
8171 if (!NIL_P(env))
8172 rb_execarg_setenv(execarg_obj, env);
8173 }
8174 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8175 modestr = rb_io_oflags_modestr(oflags);
8176
8177 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8178}
8179
8180static VALUE
8181popen_finish(VALUE port, VALUE klass)
8182{
8183 if (NIL_P(port)) {
8184 /* child */
8185 if (rb_block_given_p()) {
8186 rb_protect(rb_yield, Qnil, NULL);
8187 rb_io_flush(rb_ractor_stdout());
8188 rb_io_flush(rb_ractor_stderr());
8189 _exit(EXIT_SUCCESS);
8190 }
8191 return Qnil;
8192 }
8193 RBASIC_SET_CLASS(port, klass);
8194 if (rb_block_given_p()) {
8195 return rb_ensure(rb_yield, port, pipe_close, port);
8196 }
8197 return port;
8198}
8199
8200#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8201struct popen_writer_arg {
8202 char *const *argv;
8203 struct popen_arg popen;
8204};
8205
8206static int
8207exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8208{
8209 struct popen_writer_arg *pw = arg;
8210 pw->popen.modef = FMODE_WRITABLE;
8211 popen_redirect(&pw->popen);
8212 execv(pw->argv[0], pw->argv);
8213 strlcpy(errmsg, strerror(errno), buflen);
8214 return -1;
8215}
8216#endif
8217
8218FILE *
8219ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8220{
8221#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8222# ifdef HAVE_WORKING_FORK
8223 struct popen_writer_arg pw;
8224 int *const write_pair = pw.popen.pair;
8225# else
8226 int write_pair[2];
8227# endif
8228
8229 *pid = -1;
8230 if (cloexec_pipe(write_pair, 0, false) == 0) {
8231# ifdef HAVE_WORKING_FORK
8232 pw.argv = argv;
8233 int status;
8234 char errmsg[80] = {'\0'};
8235 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8236# else
8237 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8238 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8239# endif
8240 close(write_pair[0]);
8241 if (*pid < 0) {
8242 close(write_pair[1]);
8243 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8244 }
8245 else {
8246 return fdopen(write_pair[1], "w");
8247 }
8248 }
8249#endif
8250 return NULL;
8251}
8252
8253static VALUE
8254rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8255{
8256 int oflags;
8257 enum rb_io_mode fmode;
8258 struct rb_io_encoding convconfig;
8259 mode_t perm;
8260
8261 FilePathValue(fname);
8262
8263 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8264 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8265
8266 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8267
8268 return io;
8269}
8270
8271/*
8272 * Document-method: File::open
8273 *
8274 * :markup: markdown
8275 *
8276 * call-seq:
8277 * File.open(path, mode = 'r', permissions = 0666, **options) -> file
8278 * File.open(path, mode = 'r', permissions = 0666, **options) {|file| ... } -> object
8279 *
8280 * Creates a new \File object via File.new with the given arguments.
8281 *
8282 * With no block given, returns the \File object.
8283 *
8284 * With a block given, calls the block with the \File object,
8285 * closes the \File object, and returns the block's value:
8286 *
8287 * ```ruby
8288 * File.open('doc/maintainers.md') {|file| file.size } # => 14900
8289 * ```
8290 *
8291 * Note that the \File object is automatically closed
8292 * even if the block raises an exception.
8293 */
8294
8295/*
8296 * Document-method: IO::open
8297 *
8298 * :markup: markdown
8299 *
8300 * call-seq:
8301 * IO.open(fd, mode = 'r', **options) -> io
8302 * IO.open(fd, mode = 'r', **options) {|io| ... } -> object
8303 *
8304 * Creates a new \IO object via IO.new with the given arguments.
8305 *
8306 * With no block given, returns the \IO object.
8307 *
8308 * With a block given, calls the block with the \IO object,
8309 * closes the \IO object, and returns the block’s value:
8310 *
8311 * ```ruby
8312 * fd = File.sysopen('doc/maintainers.md') # => 6
8313 * IO.open(fd) {|io| io.read.size } # => 14897
8314 * ```
8315 */
8316
8317static VALUE
8318rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8319{
8321
8322 if (rb_block_given_p()) {
8323 return rb_ensure(rb_yield, io, io_close, io);
8324 }
8325
8326 return io;
8327}
8328
8329/*
8330 * call-seq:
8331 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8332 *
8333 * Opens the file at the given path with the given mode and permissions;
8334 * returns the integer file descriptor.
8335 *
8336 * If the file is to be readable, it must exist;
8337 * if the file is to be writable and does not exist,
8338 * it is created with the given permissions:
8339 *
8340 * File.write('t.tmp', '') # => 0
8341 * IO.sysopen('t.tmp') # => 8
8342 * IO.sysopen('t.tmp', 'w') # => 9
8343 *
8344 *
8345 */
8346
8347static VALUE
8348rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8349{
8350 VALUE fname, vmode, vperm;
8351 VALUE intmode;
8352 int oflags, fd;
8353 mode_t perm;
8354
8355 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8356 FilePathValue(fname);
8357
8358 if (NIL_P(vmode))
8359 oflags = O_RDONLY;
8360 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8361 oflags = NUM2INT(intmode);
8362 else {
8363 StringValue(vmode);
8364 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8365 }
8366 if (NIL_P(vperm)) perm = 0666;
8367 else perm = NUM2MODET(vperm);
8368
8369 RB_GC_GUARD(fname) = rb_str_new4(fname);
8370 fd = rb_sysopen(fname, oflags, perm);
8371 return INT2NUM(fd);
8372}
8373
8374/*
8375 * call-seq:
8376 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8377 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8378 *
8379 * Creates an IO object connected to the given file.
8380 *
8381 * With no block given, file stream is returned:
8382 *
8383 * open('t.txt') # => #<File:t.txt>
8384 *
8385 * With a block given, calls the block with the open file stream,
8386 * then closes the stream:
8387 *
8388 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8389 *
8390 * Output:
8391 *
8392 * #<File:t.txt>
8393 *
8394 * See File.open for details.
8395 *
8396 */
8397
8398static VALUE
8399rb_f_open(int argc, VALUE *argv, VALUE _)
8400{
8401 ID to_open = 0;
8402 int redirect = FALSE;
8403
8404 if (argc >= 1) {
8405 CONST_ID(to_open, "to_open");
8406 if (rb_respond_to(argv[0], to_open)) {
8407 redirect = TRUE;
8408 }
8409 else {
8410 VALUE tmp = argv[0];
8411 FilePathValue(tmp);
8412 if (NIL_P(tmp)) {
8413 redirect = TRUE;
8414 }
8415 else {
8416 argv[0] = tmp;
8417 }
8418 }
8419 }
8420 if (redirect) {
8421 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8422
8423 if (rb_block_given_p()) {
8424 return rb_ensure(rb_yield, io, io_close, io);
8425 }
8426 return io;
8427 }
8428 return rb_io_s_open(argc, argv, rb_cFile);
8429}
8430
8431static VALUE
8432rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8433 const struct rb_io_encoding *convconfig, mode_t perm)
8434{
8435 return rb_file_open_generic(io_alloc(klass), filename,
8436 oflags, fmode, convconfig, perm);
8437}
8438
8439static VALUE
8440rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8441{
8442 int oflags;
8443 enum rb_io_mode fmode;
8444 struct rb_io_encoding convconfig;
8445 mode_t perm;
8446
8447 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8448 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8449 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8450}
8451
8452static VALUE
8453io_reopen(VALUE io, VALUE nfile)
8454{
8455 rb_io_t *fptr, *orig;
8456 int fd, fd2;
8457 rb_off_t pos = 0;
8458
8459 nfile = rb_io_get_io(nfile);
8460 GetOpenFile(io, fptr);
8461 GetOpenFile(nfile, orig);
8462
8463 if (fptr == orig) return io;
8464 if (RUBY_IO_EXTERNAL_P(fptr)) {
8465 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8466 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8467 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8468 rb_raise(rb_eArgError,
8469 "%s can't change access mode from \"%s\" to \"%s\"",
8470 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8471 rb_io_fmode_modestr(orig->mode));
8472 }
8473 }
8474 flush_before_seek(fptr, true);
8475 /* in flush_before_seek, clear_codeconv called only if rbuf is filled */
8476 clear_codeconv(fptr);
8477 if (orig->mode & FMODE_READABLE) {
8478 pos = io_tell(orig);
8479 }
8480 if (orig->mode & FMODE_WRITABLE) {
8481 if (io_fflush(orig) < 0)
8482 rb_sys_fail_on_write(fptr);
8483 }
8484
8485 /* copy rb_io_t structure */
8486 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8487 fptr->encs = orig->encs;
8488 fptr->pid = orig->pid;
8489 fptr->lineno = orig->lineno;
8490 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8491 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8492 fptr_copy_finalizer(fptr, orig);
8493
8494 fd = fptr->fd;
8495 fd2 = orig->fd;
8496 if (fd != fd2) {
8497 // Interrupt all usage of the old file descriptor:
8498 rb_thread_io_close_interrupt(fptr);
8499 rb_thread_io_close_wait(fptr);
8500
8501 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8502 /* need to keep FILE objects of stdin, stdout and stderr */
8503 if (rb_cloexec_dup2(fd2, fd) < 0)
8504 rb_sys_fail_path(orig->pathv);
8505 rb_update_max_fd(fd);
8506 }
8507 else {
8508 fclose(fptr->stdio_file);
8509 fptr->stdio_file = 0;
8510 fptr->fd = -1;
8511 if (rb_cloexec_dup2(fd2, fd) < 0)
8512 rb_sys_fail_path(orig->pathv);
8513 rb_update_max_fd(fd);
8514 fptr->fd = fd;
8515 }
8516
8517 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8518 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8519 rb_sys_fail_path(fptr->pathv);
8520 }
8521 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8522 rb_sys_fail_path(orig->pathv);
8523 }
8524 }
8525 }
8526
8527 if (fptr->mode & FMODE_BINMODE) {
8528 rb_io_binmode(io);
8529 }
8530
8531 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8532 return io;
8533}
8534
8535#ifdef _WIN32
8536int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8537#else
8538static int
8539rb_freopen(VALUE fname, const char *mode, FILE *fp)
8540{
8541 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8542 RB_GC_GUARD(fname);
8543 return errno;
8544 }
8545 return 0;
8546}
8547#endif
8548
8549/*
8550 * call-seq:
8551 * reopen(other_io) -> self
8552 * reopen(path, mode = 'r', **opts) -> self
8553 *
8554 * Reassociates the stream with another stream,
8555 * which may be of a different class.
8556 * This method may be used to redirect an existing stream
8557 * to a new destination.
8558 *
8559 * With argument +other_io+ given, reassociates with that stream:
8560 *
8561 * # Redirect $stdin from a file.
8562 * f = File.open('t.txt')
8563 * $stdin.reopen(f)
8564 * f.close
8565 *
8566 * # Redirect $stdout to a file.
8567 * f = File.open('t.tmp', 'w')
8568 * $stdout.reopen(f)
8569 * f.close
8570 *
8571 * With argument +path+ given, reassociates with a new stream to that file path:
8572 *
8573 * $stdin.reopen('t.txt')
8574 * $stdout.reopen('t.tmp', 'w')
8575 *
8576 * Optional keyword arguments +opts+ specify:
8577 *
8578 * - {Open Options}[rdoc-ref:IO@Open+Options].
8579 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8580 *
8581 */
8582
8583static VALUE
8584rb_io_reopen(int argc, VALUE *argv, VALUE file)
8585{
8586 VALUE fname, nmode, opt;
8587 int oflags;
8588 rb_io_t *fptr;
8589
8590 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8591 VALUE tmp = rb_io_check_io(fname);
8592 if (!NIL_P(tmp)) {
8593 return io_reopen(file, tmp);
8594 }
8595 }
8596
8597 FilePathValue(fname);
8598 rb_io_taint_check(file);
8599 fptr = RFILE(file)->fptr;
8600 if (!fptr) {
8601 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8602 }
8603
8604 if (!NIL_P(nmode) || !NIL_P(opt)) {
8605 enum rb_io_mode fmode;
8606 struct rb_io_encoding convconfig;
8607
8608 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8609 if (RUBY_IO_EXTERNAL_P(fptr) &&
8610 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8611 (fptr->mode & FMODE_READWRITE)) {
8612 rb_raise(rb_eArgError,
8613 "%s can't change access mode from \"%s\" to \"%s\"",
8614 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8615 rb_io_fmode_modestr(fmode));
8616 }
8617 fptr->mode = fmode;
8618 fptr->encs = convconfig;
8619 }
8620 else {
8621 oflags = rb_io_fmode_oflags(fptr->mode);
8622 }
8623
8624 fptr->pathv = fname;
8625 if (fptr->fd < 0) {
8626 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8627 fptr->stdio_file = 0;
8628 return file;
8629 }
8630
8631 if (fptr->mode & FMODE_WRITABLE) {
8632 if (io_fflush(fptr) < 0)
8633 rb_sys_fail_on_write(fptr);
8634 }
8635 fptr->rbuf.off = fptr->rbuf.len = 0;
8636 clear_codeconv(fptr);
8637
8638 if (fptr->stdio_file) {
8639 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8640 rb_io_oflags_modestr(oflags),
8641 fptr->stdio_file);
8642 if (e) rb_syserr_fail_path(e, fptr->pathv);
8643 fptr->fd = fileno(fptr->stdio_file);
8644 rb_fd_fix_cloexec(fptr->fd);
8645#ifdef USE_SETVBUF
8646 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8647 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8648#endif
8649 if (fptr->stdio_file == stderr) {
8650 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8651 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8652 }
8653 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8654 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8655 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8656 }
8657 }
8658 else {
8659 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8660 int err = 0;
8661 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8662 err = errno;
8663 (void)close(tmpfd);
8664 if (err) {
8665 rb_syserr_fail_path(err, fptr->pathv);
8666 }
8667 }
8668
8669 return file;
8670}
8671
8672/* :nodoc: */
8673static VALUE
8674rb_io_init_copy(VALUE dest, VALUE io)
8675{
8676 rb_io_t *fptr, *orig;
8677 int fd;
8678 VALUE write_io;
8679 rb_off_t pos;
8680
8681 io = rb_io_get_io(io);
8682 if (!OBJ_INIT_COPY(dest, io)) return dest;
8683 GetOpenFile(io, orig);
8684 MakeOpenFile(dest, fptr);
8685
8686 rb_io_flush(io);
8687
8688 /* copy rb_io_t structure */
8689 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8690 fptr->encs = orig->encs;
8691 fptr->pid = orig->pid;
8692 fptr->lineno = orig->lineno;
8693 fptr->timeout = orig->timeout;
8694
8695 ccan_list_head_init(&fptr->blocking_operations);
8696 fptr->closing_ec = NULL;
8697 fptr->wakeup_mutex = Qnil;
8698 fptr->fork_generation = GET_VM()->fork_gen;
8699
8700 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8701 fptr_copy_finalizer(fptr, orig);
8702
8703 fd = ruby_dup(orig->fd);
8704 fptr->fd = fd;
8705 pos = io_tell(orig);
8706 if (0 <= pos)
8707 io_seek(fptr, pos, SEEK_SET);
8708 if (fptr->mode & FMODE_BINMODE) {
8709 rb_io_binmode(dest);
8710 }
8711
8712 write_io = GetWriteIO(io);
8713 if (io != write_io) {
8714 write_io = rb_obj_dup(write_io);
8715 fptr->tied_io_for_writing = write_io;
8716 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8717 }
8718
8719 return dest;
8720}
8721
8722/*
8723 * call-seq:
8724 * printf(format_string, *objects) -> nil
8725 *
8726 * Formats and writes +objects+ to the stream.
8727 *
8728 * For details on +format_string+, see
8729 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8730 *
8731 */
8732
8733VALUE
8734rb_io_printf(int argc, const VALUE *argv, VALUE out)
8735{
8736 rb_io_write(out, rb_f_sprintf(argc, argv));
8737 return Qnil;
8738}
8739
8740/*
8741 * call-seq:
8742 * printf(format_string, *objects) -> nil
8743 * printf(io, format_string, *objects) -> nil
8744 *
8745 * Equivalent to:
8746 *
8747 * io.write(sprintf(format_string, *objects))
8748 *
8749 * For details on +format_string+, see
8750 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8751 *
8752 * With the single argument +format_string+, formats +objects+ into the string,
8753 * then writes the formatted string to $stdout:
8754 *
8755 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8756 *
8757 * Output (on $stdout):
8758 *
8759 * 0024 24 24.00#
8760 *
8761 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8762 * then writes the formatted string to +io+:
8763 *
8764 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8765 *
8766 * Output (on $stderr):
8767 *
8768 * 0024 24 24.00# => nil
8769 *
8770 * With no arguments, does nothing.
8771 *
8772 */
8773
8774static VALUE
8775rb_f_printf(int argc, VALUE *argv, VALUE _)
8776{
8777 VALUE out;
8778
8779 if (argc == 0) return Qnil;
8780 if (RB_TYPE_P(argv[0], T_STRING)) {
8781 out = rb_ractor_stdout();
8782 }
8783 else {
8784 out = argv[0];
8785 argv++;
8786 argc--;
8787 }
8788 rb_io_write(out, rb_f_sprintf(argc, argv));
8789
8790 return Qnil;
8791}
8792
8793extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
8794
8795static void
8796deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8797{
8798 rb_deprecated_str_setter(val, id, &val);
8799 if (!NIL_P(val)) {
8800 if (rb_str_equal(val, rb_default_rs)) {
8801 val = rb_default_rs;
8802 }
8803 else {
8804 val = rb_str_frozen_bare_string(val);
8805 }
8806 }
8807 *var = val;
8808}
8809
8810/*
8811 * call-seq:
8812 * print(*objects) -> nil
8813 *
8814 * Writes the given objects to the stream; returns +nil+.
8815 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8816 * (<tt>$\</tt>), if it is not +nil+.
8817 * See {Line IO}[rdoc-ref:IO@Line+IO].
8818 *
8819 * With argument +objects+ given, for each object:
8820 *
8821 * - Converts via its method +to_s+ if not a string.
8822 * - Writes to the stream.
8823 * - If not the last object, writes the output field separator
8824 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8825 *
8826 * With default separators:
8827 *
8828 * f = File.open('t.tmp', 'w+')
8829 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8830 * p $OUTPUT_RECORD_SEPARATOR
8831 * p $OUTPUT_FIELD_SEPARATOR
8832 * f.print(*objects)
8833 * f.rewind
8834 * p f.read
8835 * f.close
8836 *
8837 * Output:
8838 *
8839 * nil
8840 * nil
8841 * "00.00/10+0izerozero"
8842 *
8843 * With specified separators:
8844 *
8845 * $\ = "\n"
8846 * $, = ','
8847 * f.rewind
8848 * f.print(*objects)
8849 * f.rewind
8850 * p f.read
8851 *
8852 * Output:
8853 *
8854 * "0,0.0,0/1,0+0i,zero,zero\n"
8855 *
8856 * With no argument given, writes the content of <tt>$_</tt>
8857 * (which is usually the most recent user input):
8858 *
8859 * f = File.open('t.tmp', 'w+')
8860 * gets # Sets $_ to the most recent user input.
8861 * f.print
8862 * f.close
8863 *
8864 */
8865
8866VALUE
8867rb_io_print(int argc, const VALUE *argv, VALUE out)
8868{
8869 int i;
8870 VALUE line;
8871
8872 /* if no argument given, print `$_' */
8873 if (argc == 0) {
8874 argc = 1;
8875 line = rb_lastline_get();
8876 argv = &line;
8877 }
8878 if (argc > 1 && !NIL_P(rb_output_fs)) {
8879 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8880 }
8881 for (i=0; i<argc; i++) {
8882 if (!NIL_P(rb_output_fs) && i>0) {
8883 rb_io_write(out, rb_output_fs);
8884 }
8885 rb_io_write(out, argv[i]);
8886 }
8887 if (argc > 0 && !NIL_P(rb_output_rs)) {
8888 rb_io_write(out, rb_output_rs);
8889 }
8890
8891 return Qnil;
8892}
8893
8894/*
8895 * call-seq:
8896 * print(*objects) -> nil
8897 *
8898 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8899 * this method is the straightforward way to write to <tt>$stdout</tt>.
8900 *
8901 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8902 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8903 * (<tt>$\</tt>), if it is not +nil+.
8904 *
8905 * With argument +objects+ given, for each object:
8906 *
8907 * - Converts via its method +to_s+ if not a string.
8908 * - Writes to <tt>stdout</tt>.
8909 * - If not the last object, writes the output field separator
8910 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8911 *
8912 * With default separators:
8913 *
8914 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8915 * $OUTPUT_RECORD_SEPARATOR
8916 * $OUTPUT_FIELD_SEPARATOR
8917 * print(*objects)
8918 *
8919 * Output:
8920 *
8921 * nil
8922 * nil
8923 * 00.00/10+0izerozero
8924 *
8925 * With specified separators:
8926 *
8927 * $OUTPUT_RECORD_SEPARATOR = "\n"
8928 * $OUTPUT_FIELD_SEPARATOR = ','
8929 * print(*objects)
8930 *
8931 * Output:
8932 *
8933 * 0,0.0,0/1,0+0i,zero,zero
8934 *
8935 * With no argument given, writes the content of <tt>$_</tt>
8936 * (which is usually the most recent user input):
8937 *
8938 * gets # Sets $_ to the most recent user input.
8939 * print # Prints $_.
8940 *
8941 */
8942
8943static VALUE
8944rb_f_print(int argc, const VALUE *argv, VALUE _)
8945{
8946 rb_io_print(argc, argv, rb_ractor_stdout());
8947 return Qnil;
8948}
8949
8950/*
8951 * call-seq:
8952 * putc(object) -> object
8953 *
8954 * Writes a character to the stream.
8955 * See {Character IO}[rdoc-ref:IO@Character+IO].
8956 *
8957 * If +object+ is numeric, converts to integer if necessary,
8958 * then writes the character whose code is the
8959 * least significant byte;
8960 * if +object+ is a string, writes the first character:
8961 *
8962 * $stdout.putc "A"
8963 * $stdout.putc 65
8964 *
8965 * Output:
8966 *
8967 * AA
8968 *
8969 */
8970
8971static VALUE
8972rb_io_putc(VALUE io, VALUE ch)
8973{
8974 VALUE str;
8975 if (RB_TYPE_P(ch, T_STRING)) {
8976 str = rb_str_substr(ch, 0, 1);
8977 }
8978 else {
8979 char c = NUM2CHR(ch);
8980 str = rb_str_new(&c, 1);
8981 }
8982 rb_io_write(io, str);
8983 return ch;
8984}
8985
8986#define forward(obj, id, argc, argv) \
8987 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8988#define forward_public(obj, id, argc, argv) \
8989 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8990#define forward_current(id, argc, argv) \
8991 forward_public(ARGF.current_file, id, argc, argv)
8992
8993/*
8994 * call-seq:
8995 * putc(int) -> int
8996 *
8997 * Equivalent to:
8998 *
8999 * $stdout.putc(int)
9000 *
9001 * See IO#putc for important information regarding multi-byte characters.
9002 *
9003 */
9004
9005static VALUE
9006rb_f_putc(VALUE recv, VALUE ch)
9007{
9008 VALUE r_stdout = rb_ractor_stdout();
9009 if (recv == r_stdout) {
9010 return rb_io_putc(recv, ch);
9011 }
9012 return forward(r_stdout, rb_intern("putc"), 1, &ch);
9013}
9014
9015
9016int
9017rb_str_end_with_asciichar(VALUE str, int c)
9018{
9019 long len = RSTRING_LEN(str);
9020 const char *ptr = RSTRING_PTR(str);
9021 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
9022 int n;
9023
9024 if (len == 0) return 0;
9025 if ((n = rb_enc_mbminlen(enc)) == 1) {
9026 return ptr[len - 1] == c;
9027 }
9028 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
9029}
9030
9031static VALUE
9032io_puts_ary(VALUE ary, VALUE out, int recur)
9033{
9034 VALUE tmp;
9035 long i;
9036
9037 if (recur) {
9038 tmp = rb_str_new2("[...]");
9039 rb_io_puts(1, &tmp, out);
9040 return Qtrue;
9041 }
9042 ary = rb_check_array_type(ary);
9043 if (NIL_P(ary)) return Qfalse;
9044 for (i=0; i<RARRAY_LEN(ary); i++) {
9045 tmp = RARRAY_AREF(ary, i);
9046 rb_io_puts(1, &tmp, out);
9047 }
9048 return Qtrue;
9049}
9050
9051/*
9052 * call-seq:
9053 * puts(*objects) -> nil
9054 *
9055 * Writes the given +objects+ to the stream, which must be open for writing;
9056 * returns +nil+.\
9057 * Writes a newline after each that does not already end with a newline sequence.
9058 * If called without arguments, writes a newline.
9059 * See {Line IO}[rdoc-ref:IO@Line+IO].
9060 *
9061 * Note that each added newline is the character <tt>"\n"</tt>,
9062 * not the output record separator (<tt>$\</tt>).
9063 *
9064 * Treatment for each object:
9065 *
9066 * - String: writes the string.
9067 * - Neither string nor array: writes <tt>object.to_s</tt>.
9068 * - Array: writes each element of the array; arrays may be nested.
9069 *
9070 * To keep these examples brief, we define this helper method:
9071 *
9072 * def show(*objects)
9073 * # Puts objects to file.
9074 * f = File.new('t.tmp', 'w+')
9075 * f.puts(objects)
9076 * # Return file content.
9077 * f.rewind
9078 * p f.read
9079 * f.close
9080 * end
9081 *
9082 * # Strings without newlines.
9083 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
9084 * # Strings, some with newlines.
9085 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
9086 *
9087 * # Neither strings nor arrays:
9088 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
9089 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
9090 *
9091 * # Array of strings.
9092 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
9093 * # Nested arrays.
9094 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
9095 *
9096 */
9097
9098VALUE
9099rb_io_puts(int argc, const VALUE *argv, VALUE out)
9100{
9101 VALUE line, args[2];
9102
9103 /* if no argument given, print newline. */
9104 if (argc == 0) {
9105 rb_io_write(out, rb_default_rs);
9106 return Qnil;
9107 }
9108 for (int i = 0; i < argc; i++) {
9109 // Convert the argument to a string:
9110 if (RB_TYPE_P(argv[i], T_STRING)) {
9111 line = argv[i];
9112 }
9113 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9114 continue;
9115 }
9116 else {
9117 line = rb_obj_as_string(argv[i]);
9118 }
9119
9120 // Write the line:
9121 int n = 0;
9122 if (RSTRING_LEN(line) == 0) {
9123 args[n++] = rb_default_rs;
9124 }
9125 else {
9126 args[n++] = line;
9127 if (!rb_str_end_with_asciichar(line, '\n')) {
9128 args[n++] = rb_default_rs;
9129 }
9130 }
9131
9132 rb_io_writev(out, n, args);
9133 }
9134
9135 return Qnil;
9136}
9137
9138/*
9139 * call-seq:
9140 * puts(*objects) -> nil
9141 *
9142 * Equivalent to
9143 *
9144 * $stdout.puts(objects)
9145 */
9146
9147static VALUE
9148rb_f_puts(int argc, VALUE *argv, VALUE recv)
9149{
9150 VALUE r_stdout = rb_ractor_stdout();
9151 if (recv == r_stdout) {
9152 return rb_io_puts(argc, argv, recv);
9153 }
9154 return forward(r_stdout, rb_intern("puts"), argc, argv);
9155}
9156
9157static VALUE
9158rb_p_write(VALUE str)
9159{
9160 VALUE args[2];
9161 args[0] = str;
9162 args[1] = rb_default_rs;
9163 VALUE r_stdout = rb_ractor_stdout();
9164 if (RB_TYPE_P(r_stdout, T_FILE) &&
9165 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9166 io_writev(2, args, r_stdout);
9167 }
9168 else {
9169 rb_io_writev(r_stdout, 2, args);
9170 }
9171 return Qnil;
9172}
9173
9174void
9175rb_p(VALUE obj) /* for debug print within C code */
9176{
9177 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9178}
9179
9180static VALUE
9181rb_p_result(int argc, const VALUE *argv)
9182{
9183 VALUE ret = Qnil;
9184
9185 if (argc == 1) {
9186 ret = argv[0];
9187 }
9188 else if (argc > 1) {
9189 ret = rb_ary_new4(argc, argv);
9190 }
9191 VALUE r_stdout = rb_ractor_stdout();
9192 if (RB_TYPE_P(r_stdout, T_FILE)) {
9193 rb_uninterruptible(rb_io_flush, r_stdout);
9194 }
9195 return ret;
9196}
9197
9198/*
9199 * call-seq:
9200 * p(object) -> obj
9201 * p(*objects) -> array of objects
9202 * p -> nil
9203 *
9204 * For each object +obj+, executes:
9205 *
9206 * $stdout.write(obj.inspect, "\n")
9207 *
9208 * With one object given, returns the object;
9209 * with multiple objects given, returns an array containing the objects;
9210 * with no object given, returns +nil+.
9211 *
9212 * Examples:
9213 *
9214 * r = Range.new(0, 4)
9215 * p r # => 0..4
9216 * p [r, r, r] # => [0..4, 0..4, 0..4]
9217 * p # => nil
9218 *
9219 * Output:
9220 *
9221 * 0..4
9222 * [0..4, 0..4, 0..4]
9223 *
9224 * Kernel#p is designed for debugging purposes.
9225 * Ruby implementations may define Kernel#p to be uninterruptible
9226 * in whole or in part.
9227 * On CRuby, Kernel#p's writing of data is uninterruptible.
9228 */
9229
9230static VALUE
9231rb_f_p(int argc, VALUE *argv, VALUE self)
9232{
9233 int i;
9234 for (i=0; i<argc; i++) {
9235 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9236 rb_uninterruptible(rb_p_write, inspected);
9237 }
9238 return rb_p_result(argc, argv);
9239}
9240
9241/*
9242 * call-seq:
9243 * display(port = $>) -> nil
9244 *
9245 * Writes +self+ on the given port:
9246 *
9247 * 1.display
9248 * "cat".display
9249 * [ 4, 5, 6 ].display
9250 * puts
9251 *
9252 * Output:
9253 *
9254 * 1cat[4, 5, 6]
9255 *
9256 */
9257
9258static VALUE
9259rb_obj_display(int argc, VALUE *argv, VALUE self)
9260{
9261 VALUE out;
9262
9263 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9264 rb_io_write(out, self);
9265
9266 return Qnil;
9267}
9268
9269static int
9270rb_stderr_to_original_p(VALUE err)
9271{
9272 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9273}
9274
9275void
9276rb_write_error2(const char *mesg, long len)
9277{
9278 VALUE out = rb_ractor_stderr();
9279 if (rb_stderr_to_original_p(out)) {
9280#ifdef _WIN32
9281 if (isatty(fileno(stderr))) {
9282 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9283 }
9284#endif
9285 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9286 /* failed to write to stderr, what can we do? */
9287 return;
9288 }
9289 }
9290 else {
9291 rb_io_write(out, rb_str_new(mesg, len));
9292 }
9293}
9294
9295void
9296rb_write_error(const char *mesg)
9297{
9298 rb_write_error2(mesg, strlen(mesg));
9299}
9300
9301void
9302rb_write_error_str(VALUE mesg)
9303{
9304 VALUE out = rb_ractor_stderr();
9305 /* a stopgap measure for the time being */
9306 if (rb_stderr_to_original_p(out)) {
9307 size_t len = (size_t)RSTRING_LEN(mesg);
9308#ifdef _WIN32
9309 if (isatty(fileno(stderr))) {
9310 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9311 }
9312#endif
9313 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9314 RB_GC_GUARD(mesg);
9315 return;
9316 }
9317 }
9318 else {
9319 /* may unlock GVL, and */
9320 rb_io_write(out, mesg);
9321 }
9322}
9323
9324int
9325rb_stderr_tty_p(void)
9326{
9327 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9328 return isatty(fileno(stderr));
9329 return 0;
9330}
9331
9332static void
9333must_respond_to(ID mid, VALUE val, ID id)
9334{
9335 if (!rb_respond_to(val, mid)) {
9336 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9337 rb_id2str(id), rb_id2str(mid),
9338 rb_obj_class(val));
9339 }
9340}
9341
9342static void
9343stdin_setter(VALUE val, ID id, VALUE *ptr)
9344{
9346}
9347
9348static VALUE
9349stdin_getter(ID id, VALUE *ptr)
9350{
9351 return rb_ractor_stdin();
9352}
9353
9354static void
9355stdout_setter(VALUE val, ID id, VALUE *ptr)
9356{
9357 must_respond_to(id_write, val, id);
9359}
9360
9361static VALUE
9362stdout_getter(ID id, VALUE *ptr)
9363{
9364 return rb_ractor_stdout();
9365}
9366
9367static void
9368stderr_setter(VALUE val, ID id, VALUE *ptr)
9369{
9370 must_respond_to(id_write, val, id);
9372}
9373
9374static VALUE
9375stderr_getter(ID id, VALUE *ptr)
9376{
9377 return rb_ractor_stderr();
9378}
9379
9380static VALUE
9381allocate_and_open_new_file(VALUE klass)
9382{
9383 VALUE self = io_alloc(klass);
9384 rb_io_make_open_file(self);
9385 return self;
9386}
9387
9388VALUE
9389rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9390{
9391 int state;
9392 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9393 if (state) {
9394 /* if we raised an exception allocating an IO object, but the caller
9395 intended to transfer ownership of this FD to us, close the fd before
9396 raising the exception. Otherwise, we would leak a FD - the caller
9397 expects GC to close the file, but we never got around to assigning
9398 it to a rb_io. */
9399 if (!(mode & FMODE_EXTERNAL)) {
9400 maygvl_close(descriptor, 0);
9401 }
9402 rb_jump_tag(state);
9403 }
9404
9405
9406 rb_io_t *io = RFILE(self)->fptr;
9407 io->self = self;
9408 io->fd = descriptor;
9409 io->mode = mode;
9410
9411 /* At this point, Ruby fully owns the descriptor, and will close it when
9412 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9413 in the rest of this method. */
9414
9415 if (NIL_P(path)) {
9416 io->pathv = Qnil;
9417 }
9418 else {
9419 StringValue(path);
9420 io->pathv = rb_str_new_frozen(path);
9421 }
9422
9423 io->timeout = timeout;
9424
9425 ccan_list_head_init(&io->blocking_operations);
9426 io->closing_ec = NULL;
9427 io->wakeup_mutex = Qnil;
9428 io->fork_generation = GET_VM()->fork_gen;
9429
9430 if (encoding) {
9431 io->encs = *encoding;
9432 }
9433
9434 rb_update_max_fd(descriptor);
9435
9436 return self;
9437}
9438
9439static VALUE
9440prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9441{
9442 VALUE path_value = Qnil;
9443 rb_encoding *e;
9444 struct rb_io_encoding convconfig;
9445
9446 if (path) {
9447 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9448 }
9449
9450 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9451 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9452 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9455#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9456 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9457 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9458 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9459#endif
9460 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9461 convconfig.ecopts = Qnil;
9462
9463 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9464 rb_io_t*io = RFILE(self)->fptr;
9465
9466 if (!io_check_tty(io)) {
9467#ifdef __CYGWIN__
9468 io->mode |= FMODE_BINMODE;
9469 setmode(fd, O_BINARY);
9470#endif
9471 }
9472
9473 return self;
9474}
9475
9476VALUE
9477rb_io_fdopen(int fd, int oflags, const char *path)
9478{
9479 VALUE klass = rb_cIO;
9480
9481 if (path && strcmp(path, "-")) klass = rb_cFile;
9482 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9483}
9484
9485static VALUE
9486prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9487{
9488 rb_io_t *fptr;
9489 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9490
9491 GetOpenFile(io, fptr);
9493#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9494 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9495 if (fmode & FMODE_READABLE) {
9497 }
9498#endif
9499 fptr->stdio_file = f;
9500
9501 return io;
9502}
9503
9504VALUE
9505rb_io_prep_stdin(void)
9506{
9507 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9508}
9509
9510VALUE
9511rb_io_prep_stdout(void)
9512{
9513 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9514}
9515
9516VALUE
9517rb_io_prep_stderr(void)
9518{
9519 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9520}
9521
9522FILE *
9524{
9525 if (!fptr->stdio_file) {
9526 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9527 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9528 }
9529 return fptr->stdio_file;
9530}
9531
9532static inline void
9533rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9534{
9535 buf->ptr = NULL;
9536 buf->off = 0;
9537 buf->len = 0;
9538 buf->capa = 0;
9539}
9540
9541static inline rb_io_t *
9542rb_io_fptr_new(void)
9543{
9544 rb_io_t *fp = ALLOC(rb_io_t);
9545 fp->self = Qnil;
9546 fp->fd = -1;
9547 fp->stdio_file = NULL;
9548 fp->mode = 0;
9549 fp->pid = 0;
9550 fp->lineno = 0;
9551 fp->pathv = Qnil;
9552 fp->finalize = 0;
9553 rb_io_buffer_init(&fp->wbuf);
9554 rb_io_buffer_init(&fp->rbuf);
9555 rb_io_buffer_init(&fp->cbuf);
9556 fp->readconv = NULL;
9557 fp->writeconv = NULL;
9559 fp->writeconv_pre_ecflags = 0;
9561 fp->writeconv_initialized = 0;
9562 fp->tied_io_for_writing = 0;
9563 fp->encs.enc = NULL;
9564 fp->encs.enc2 = NULL;
9565 fp->encs.ecflags = 0;
9566 fp->encs.ecopts = Qnil;
9567 fp->write_lock = Qnil;
9568 fp->timeout = Qnil;
9569 ccan_list_head_init(&fp->blocking_operations);
9570 fp->closing_ec = NULL;
9571 fp->wakeup_mutex = Qnil;
9572 fp->fork_generation = GET_VM()->fork_gen;
9573 return fp;
9574}
9575
9576rb_io_t *
9577rb_io_make_open_file(VALUE obj)
9578{
9579 rb_io_t *fp = 0;
9580
9581 Check_Type(obj, T_FILE);
9582 if (RFILE(obj)->fptr) {
9583 rb_io_close(obj);
9584 rb_io_fptr_finalize(RFILE(obj)->fptr);
9585 RFILE(obj)->fptr = 0;
9586 }
9587 fp = rb_io_fptr_new();
9588 fp->self = obj;
9589 RFILE(obj)->fptr = fp;
9590 return fp;
9591}
9592
9593static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9594
9595/*
9596 * call-seq:
9597 * IO.new(fd, mode = 'r', **opts) -> io
9598 *
9599 * Creates and returns a new \IO object (file stream) from a file descriptor.
9600 *
9601 * \IO.new may be useful for interaction with low-level libraries.
9602 * For higher-level interactions, it may be simpler to create
9603 * the file stream using File.open.
9604 *
9605 * Argument +fd+ must be a valid file descriptor (integer):
9606 *
9607 * path = 't.tmp'
9608 * fd = IO.sysopen(path) # => 3
9609 * IO.new(fd) # => #<IO:fd 3>
9610 *
9611 * The new \IO object does not inherit encoding
9612 * (because the integer file descriptor does not have an encoding):
9613 *
9614 * File.read('t.ja') # => "こんにちは"
9615 * fd = IO.sysopen('t.ja', 'rb')
9616 * io = IO.new(fd)
9617 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9618 *
9619 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9620 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9621 *
9622 * IO.new(fd, 'w') # => #<IO:fd 3>
9623 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9624 *
9625 * Optional keyword arguments +opts+ specify:
9626 *
9627 * - {Open Options}[rdoc-ref:IO@Open+Options].
9628 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9629 *
9630 * Examples:
9631 *
9632 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9633 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9634 *
9635 */
9636
9637static VALUE
9638rb_io_initialize(int argc, VALUE *argv, VALUE io)
9639{
9640 VALUE fnum, vmode;
9641 VALUE opt;
9642
9643 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9644 return io_initialize(io, fnum, vmode, opt);
9645}
9646
9647static VALUE
9648io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9649{
9650 rb_io_t *fp;
9651 int fd, oflags = O_RDONLY;
9652 enum rb_io_mode fmode;
9653 struct rb_io_encoding convconfig;
9654#if defined(HAVE_FCNTL) && defined(F_GETFL)
9655 int ofmode;
9656#else
9657 struct stat st;
9658#endif
9659
9660 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9661
9662 fd = NUM2INT(fnum);
9663 if (rb_reserved_fd_p(fd)) {
9664 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9665 }
9666#if defined(HAVE_FCNTL) && defined(F_GETFL)
9667 oflags = fcntl(fd, F_GETFL);
9668 if (oflags == -1) rb_sys_fail(0);
9669#else
9670 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9671#endif
9672 rb_update_max_fd(fd);
9673#if defined(HAVE_FCNTL) && defined(F_GETFL)
9674 ofmode = rb_io_oflags_fmode(oflags);
9675 if (NIL_P(vmode)) {
9676 fmode = ofmode;
9677 }
9678 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9679 VALUE error = INT2FIX(EINVAL);
9681 }
9682#endif
9683 VALUE path = Qnil;
9684
9685 if (!NIL_P(opt)) {
9686 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9687 fmode |= FMODE_EXTERNAL;
9688 }
9689
9690 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9691 if (!NIL_P(path)) {
9692 StringValue(path);
9693 path = rb_str_new_frozen(path);
9694 }
9695 }
9696
9697 MakeOpenFile(io, fp);
9698 fp->self = io;
9699 fp->fd = fd;
9700 fp->mode = fmode;
9701 fp->encs = convconfig;
9702 fp->pathv = path;
9703 fp->timeout = Qnil;
9704 ccan_list_head_init(&fp->blocking_operations);
9705 fp->closing_ec = NULL;
9706 fp->wakeup_mutex = Qnil;
9707 fp->fork_generation = GET_VM()->fork_gen;
9708 clear_codeconv(fp);
9709 io_check_tty(fp);
9710 if (fileno(stdin) == fd)
9711 fp->stdio_file = stdin;
9712 else if (fileno(stdout) == fd)
9713 fp->stdio_file = stdout;
9714 else if (fileno(stderr) == fd)
9715 fp->stdio_file = stderr;
9716
9717 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9718 return io;
9719}
9720
9721/*
9722 * call-seq:
9723 * set_encoding_by_bom -> encoding or nil
9724 *
9725 * If the stream begins with a BOM
9726 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9727 * consumes the BOM and sets the external encoding accordingly;
9728 * returns the result encoding if found, or +nil+ otherwise:
9729 *
9730 * File.write('t.tmp', "\u{FEFF}abc")
9731 * io = File.open('t.tmp', 'rb')
9732 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9733 * io.close
9734 *
9735 * File.write('t.tmp', 'abc')
9736 * io = File.open('t.tmp', 'rb')
9737 * io.set_encoding_by_bom # => nil
9738 * io.close
9739 *
9740 * Raises an exception if the stream is not binmode
9741 * or its encoding has already been set.
9742 *
9743 */
9744
9745static VALUE
9746rb_io_set_encoding_by_bom(VALUE io)
9747{
9748 rb_io_t *fptr;
9749
9750 GetOpenFile(io, fptr);
9751 if (!(fptr->mode & FMODE_BINMODE)) {
9752 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9753 }
9754 if (fptr->encs.enc2) {
9755 rb_raise(rb_eArgError, "encoding conversion is set");
9756 }
9757 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9758 rb_raise(rb_eArgError, "encoding is set to %s already",
9759 rb_enc_name(fptr->encs.enc));
9760 }
9761 if (!io_set_encoding_by_bom(io)) return Qnil;
9762 return rb_enc_from_encoding(fptr->encs.enc);
9763}
9764
9765/*
9766 * :markup: markdown
9767 *
9768 * call-seq:
9769 * File.new(path, mode = 'r', permissions = 0666, **options) -> file
9770 *
9771 * Opens the file as specified by the given arguments.
9772 * Creates and returns a new open \File object for that file;
9773 * the opened file is in non-synchronous mode.
9774 *
9775 * Argument `path` must the string path to an existing filesystem entry:
9776 *
9777 * ```ruby
9778 * file = File.new('doc/maintainers.md') # => #<File:doc/maintainers.md>
9779 * file.close # Clean up.
9780 * tty = File.new('/dev/tty') # => #<File:/dev/tty>
9781 * tty.close # Clean up.
9782 * ```
9783 *
9784 * Note that the caller is responsible for closing the file;
9785 * see File.open for automatic closing.
9786 *
9787 * Optional argument `mode` (defaults to `'r'`) must specify a valid mode;
9788 * see [Access Modes](rdoc-ref:File@Access+Modes):
9789 *
9790 * ```ruby
9791 * file = File.new('t.tmp', 'w') # => #<File:t.tmp>
9792 * file.close # Clean up.
9793 * file = File.new('t.tmp', File::RDONLY) # => #<File:t.tmp>
9794 * file.close # Clean up.
9795 * ```
9796 *
9797 * Optional argument `permissions` (defaults to `0666`) must specify valid permissions;
9798 * see [File Permissions](rdoc-ref:File@File+Permissions):
9799 *
9800 * ```ruby
9801 * file = File.new('t.tmp', 'w', 0644) # => #<File:t.tmp>
9802 * file.close # Clean up.
9803 * file = File.new('t.tmp', 'w', 0444) # => #<File:t.tmp>
9804 * file.close # Clean up.
9805 * ```
9806 *
9807 * Optional keyword arguments `options` specify:
9808 *
9809 * - [Open Options](rdoc-ref:IO@Open+Options).
9810 * - [Encoding options](rdoc-ref:encodings.rdoc@Encoding+Options).
9811 *
9812 */
9813
9814static VALUE
9815rb_file_initialize(int argc, VALUE *argv, VALUE io)
9816{
9817 if (RFILE(io)->fptr) {
9818 rb_raise(rb_eRuntimeError, "reinitializing File");
9819 }
9820 VALUE fname, vmode, vperm, opt;
9821 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9822 if (posargc < 3) { /* perm is File only */
9823 VALUE fd = rb_check_to_int(fname);
9824
9825 if (!NIL_P(fd)) {
9826 return io_initialize(io, fd, vmode, opt);
9827 }
9828 }
9829 return rb_open_file(io, fname, vmode, vperm, opt);
9830}
9831
9832/* :nodoc: */
9833static VALUE
9834rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9835{
9836 if (rb_block_given_p()) {
9837 VALUE cname = rb_obj_as_string(klass);
9838
9839 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9840 cname, cname);
9841 }
9842 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9843}
9844
9845
9846/*
9847 * call-seq:
9848 * IO.for_fd(fd, mode = 'r', **opts) -> io
9849 *
9850 * Synonym for IO.new.
9851 *
9852 */
9853
9854static VALUE
9855rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9856{
9857 VALUE io = rb_obj_alloc(klass);
9858 rb_io_initialize(argc, argv, io);
9859 return io;
9860}
9861
9862/*
9863 * call-seq:
9864 * ios.autoclose? -> true or false
9865 *
9866 * Returns +true+ if the underlying file descriptor of _ios_ will be
9867 * closed at its finalization or at calling #close, otherwise +false+.
9868 */
9869
9870static VALUE
9871rb_io_autoclose_p(VALUE io)
9872{
9873 rb_io_t *fptr = RFILE(io)->fptr;
9874 rb_io_check_closed(fptr);
9875 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9876}
9877
9878/*
9879 * call-seq:
9880 * io.autoclose = bool -> true or false
9881 *
9882 * Sets auto-close flag.
9883 *
9884 * f = File.open(File::NULL)
9885 * IO.for_fd(f.fileno).close
9886 * f.gets # raises Errno::EBADF
9887 *
9888 * f = File.open(File::NULL)
9889 * g = IO.for_fd(f.fileno)
9890 * g.autoclose = false
9891 * g.close
9892 * f.gets # won't cause Errno::EBADF
9893 */
9894
9895static VALUE
9896rb_io_set_autoclose(VALUE io, VALUE autoclose)
9897{
9898 rb_io_t *fptr;
9899 GetOpenFile(io, fptr);
9900 if (!RTEST(autoclose))
9901 fptr->mode |= FMODE_EXTERNAL;
9902 else
9903 fptr->mode &= ~FMODE_EXTERNAL;
9904 return autoclose;
9905}
9906
9907static VALUE
9908io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9909{
9910 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9911
9912 if (!RB_TEST(result)) {
9913 return Qnil;
9914 }
9915
9916 int mask = RB_NUM2INT(result);
9917
9918 if (mask & event) {
9919 if (return_io)
9920 return io;
9921 else
9922 return result;
9923 }
9924 else {
9925 return Qfalse;
9926 }
9927}
9928
9929/*
9930 * call-seq:
9931 * io.wait_readable -> truthy or falsy
9932 * io.wait_readable(timeout) -> truthy or falsy
9933 *
9934 * Waits until IO is readable and returns a truthy value, or a falsy
9935 * value when times out. Returns a truthy value immediately when
9936 * buffered data is available.
9937 */
9938
9939static VALUE
9940io_wait_readable(int argc, VALUE *argv, VALUE io)
9941{
9942 rb_io_t *fptr;
9943
9944 RB_IO_POINTER(io, fptr);
9946
9947 if (rb_io_read_pending(fptr)) return Qtrue;
9948
9949 rb_check_arity(argc, 0, 1);
9950 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9951
9952 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9953}
9954
9955/*
9956 * call-seq:
9957 * io.wait_writable -> truthy or falsy
9958 * io.wait_writable(timeout) -> truthy or falsy
9959 *
9960 * Waits until IO is writable and returns a truthy value or a falsy
9961 * value when times out.
9962 */
9963static VALUE
9964io_wait_writable(int argc, VALUE *argv, VALUE io)
9965{
9966 rb_io_t *fptr;
9967
9968 RB_IO_POINTER(io, fptr);
9970
9971 rb_check_arity(argc, 0, 1);
9972 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9973
9974 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9975}
9976
9977/*
9978 * call-seq:
9979 * io.wait_priority -> truthy or falsy
9980 * io.wait_priority(timeout) -> truthy or falsy
9981 *
9982 * Waits until IO is priority and returns a truthy value or a falsy
9983 * value when times out. Priority data is sent and received using
9984 * the Socket::MSG_OOB flag and is typically limited to streams.
9985 */
9986static VALUE
9987io_wait_priority(int argc, VALUE *argv, VALUE io)
9988{
9989 rb_io_t *fptr = NULL;
9990
9991 RB_IO_POINTER(io, fptr);
9993
9994 if (rb_io_read_pending(fptr)) return Qtrue;
9995
9996 rb_check_arity(argc, 0, 1);
9997 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9998
9999 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
10000}
10001
10002static int
10003wait_mode_sym(VALUE mode)
10004{
10005 if (mode == ID2SYM(rb_intern("r"))) {
10006 return RB_WAITFD_IN;
10007 }
10008 if (mode == ID2SYM(rb_intern("read"))) {
10009 return RB_WAITFD_IN;
10010 }
10011 if (mode == ID2SYM(rb_intern("readable"))) {
10012 return RB_WAITFD_IN;
10013 }
10014 if (mode == ID2SYM(rb_intern("w"))) {
10015 return RB_WAITFD_OUT;
10016 }
10017 if (mode == ID2SYM(rb_intern("write"))) {
10018 return RB_WAITFD_OUT;
10019 }
10020 if (mode == ID2SYM(rb_intern("writable"))) {
10021 return RB_WAITFD_OUT;
10022 }
10023 if (mode == ID2SYM(rb_intern("rw"))) {
10024 return RB_WAITFD_IN|RB_WAITFD_OUT;
10025 }
10026 if (mode == ID2SYM(rb_intern("read_write"))) {
10027 return RB_WAITFD_IN|RB_WAITFD_OUT;
10028 }
10029 if (mode == ID2SYM(rb_intern("readable_writable"))) {
10030 return RB_WAITFD_IN|RB_WAITFD_OUT;
10031 }
10032
10033 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
10034}
10035
10036static inline enum rb_io_event
10037io_event_from_value(VALUE value)
10038{
10039 int events = RB_NUM2INT(value);
10040
10041 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
10042
10043 return events;
10044}
10045
10046/*
10047 * call-seq:
10048 * io.wait(events, timeout) -> event mask, false or nil
10049 * io.wait(*event_symbols[, timeout]) -> self, true, or false
10050 *
10051 * Waits until the IO becomes ready for the specified events and returns the
10052 * subset of events that become ready, or a falsy value when times out.
10053 *
10054 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
10055 * +IO::PRIORITY+.
10056 *
10057 * Returns an event mask (truthy value) immediately when buffered data is
10058 * available.
10059 *
10060 * The second form: if one or more event symbols (+:read+, +:write+, or
10061 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
10062 * corresponding to those symbols. In this form, +timeout+ is optional, the
10063 * order of the arguments is arbitrary, and returns +io+ if any of the
10064 * events is ready.
10065 */
10066
10067static VALUE
10068io_wait(int argc, VALUE *argv, VALUE io)
10069{
10070 VALUE timeout = Qundef;
10071 enum rb_io_event events = 0;
10072 int return_io = 0;
10073
10074 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
10075 // We'd prefer to return the actual mask, but this form would return the io itself:
10076 return_io = 1;
10077
10078 // Slow/messy path:
10079 for (int i = 0; i < argc; i += 1) {
10080 if (RB_SYMBOL_P(argv[i])) {
10081 events |= wait_mode_sym(argv[i]);
10082 }
10083 else if (UNDEF_P(timeout)) {
10084 rb_time_interval(timeout = argv[i]);
10085 }
10086 else {
10087 rb_raise(rb_eArgError, "timeout given more than once");
10088 }
10089 }
10090
10091 if (UNDEF_P(timeout)) timeout = Qnil;
10092
10093 if (events == 0) {
10094 events = RUBY_IO_READABLE;
10095 }
10096 }
10097 else /* argc == 2 and neither are symbols */ {
10098 // This is the fast path:
10099 events = io_event_from_value(argv[0]);
10100 timeout = argv[1];
10101 }
10102
10103 if (events & RUBY_IO_READABLE) {
10104 rb_io_t *fptr = NULL;
10105 RB_IO_POINTER(io, fptr);
10106
10107 if (rb_io_read_pending(fptr)) {
10108 // This was the original behaviour:
10109 if (return_io) return Qtrue;
10110 // New behaviour always returns an event mask:
10111 else return RB_INT2NUM(RUBY_IO_READABLE);
10112 }
10113 }
10114
10115 return io_wait_event(io, events, timeout, return_io);
10116}
10117
10118static void
10119argf_mark_and_move(void *ptr)
10120{
10121 struct argf *p = ptr;
10122 rb_gc_mark_and_move(&p->filename);
10123 rb_gc_mark_and_move(&p->current_file);
10124 rb_gc_mark_and_move(&p->argv);
10125 rb_gc_mark_and_move(&p->inplace);
10126 rb_gc_mark_and_move(&p->encs.ecopts);
10127}
10128
10129static size_t
10130argf_memsize(const void *ptr)
10131{
10132 const struct argf *p = ptr;
10133 size_t size = sizeof(*p);
10134 return size;
10135}
10136
10137static const rb_data_type_t argf_type = {
10138 "ARGF",
10139 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10140 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10141};
10142
10143static inline void
10144argf_init(VALUE argf, struct argf *p, VALUE v)
10145{
10146 p->filename = Qnil;
10147 p->current_file = Qnil;
10148 p->lineno = 0;
10149 RB_OBJ_WRITE(argf, &p->argv, v);
10150}
10151
10152static VALUE
10153argf_alloc(VALUE klass)
10154{
10155 struct argf *p;
10156 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10157
10158 argf_init(argf, p, Qnil);
10159 return argf;
10160}
10161
10162#undef rb_argv
10163
10164/* :nodoc: */
10165static VALUE
10166argf_initialize(VALUE argf, VALUE argv)
10167{
10168 memset(&ARGF, 0, sizeof(ARGF));
10169 argf_init(argf, &ARGF, argv);
10170
10171 return argf;
10172}
10173
10174/* :nodoc: */
10175static VALUE
10176argf_initialize_copy(VALUE argf, VALUE orig)
10177{
10178 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10179 ARGF = argf_of(orig);
10180 rb_gc_writebarrier_remember(argf);
10181 ARGF_SET(argv, rb_obj_dup(ARGF.argv));
10182 return argf;
10183}
10184
10185/*
10186 * call-seq:
10187 * ARGF.lineno = integer -> integer
10188 *
10189 * Sets the line number of ARGF as a whole to the given Integer.
10190 *
10191 * ARGF sets the line number automatically as you read data, so normally
10192 * you will not need to set it explicitly. To access the current line number
10193 * use ARGF.lineno.
10194 *
10195 * For example:
10196 *
10197 * ARGF.lineno #=> 0
10198 * ARGF.readline #=> "This is line 1\n"
10199 * ARGF.lineno #=> 1
10200 * ARGF.lineno = 0 #=> 0
10201 * ARGF.lineno #=> 0
10202 */
10203static VALUE
10204argf_set_lineno(VALUE argf, VALUE val)
10205{
10206 ARGF.lineno = NUM2INT(val);
10207 ARGF.last_lineno = ARGF.lineno;
10208 return val;
10209}
10210
10211/*
10212 * call-seq:
10213 * ARGF.lineno -> integer
10214 *
10215 * Returns the current line number of ARGF as a whole. This value
10216 * can be set manually with ARGF.lineno=.
10217 *
10218 * For example:
10219 *
10220 * ARGF.lineno #=> 0
10221 * ARGF.readline #=> "This is line 1\n"
10222 * ARGF.lineno #=> 1
10223 */
10224static VALUE
10225argf_lineno(VALUE argf)
10226{
10227 return INT2FIX(ARGF.lineno);
10228}
10229
10230static VALUE
10231argf_forward(int argc, VALUE *argv, VALUE argf)
10232{
10233 return forward_current(rb_frame_this_func(), argc, argv);
10234}
10235
10236#define next_argv() argf_next_argv(argf)
10237#define ARGF_GENERIC_INPUT_P() \
10238 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10239#define ARGF_FORWARD(argc, argv) do {\
10240 if (ARGF_GENERIC_INPUT_P())\
10241 return argf_forward((argc), (argv), argf);\
10242} while (0)
10243#define NEXT_ARGF_FORWARD(argc, argv) do {\
10244 if (!next_argv()) return Qnil;\
10245 ARGF_FORWARD((argc), (argv));\
10246} while (0)
10247
10248static void
10249argf_close(VALUE argf)
10250{
10251 VALUE file = ARGF.current_file;
10252 if (file == rb_stdin) return;
10253 if (RB_TYPE_P(file, T_FILE)) {
10254 rb_io_set_write_io(file, Qnil);
10255 }
10256 io_close(file);
10257 ARGF.init_p = -1;
10258}
10259
10260static int
10261argf_next_argv(VALUE argf)
10262{
10263 char *fn;
10264 rb_io_t *fptr;
10265 int stdout_binmode = 0;
10266 enum rb_io_mode fmode;
10267
10268 VALUE r_stdout = rb_ractor_stdout();
10269
10270 if (RB_TYPE_P(r_stdout, T_FILE)) {
10271 GetOpenFile(r_stdout, fptr);
10272 if (fptr->mode & FMODE_BINMODE)
10273 stdout_binmode = 1;
10274 }
10275
10276 if (ARGF.init_p == 0) {
10277 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10278 ARGF.next_p = 1;
10279 }
10280 else {
10281 ARGF.next_p = -1;
10282 }
10283 ARGF.init_p = 1;
10284 }
10285 else {
10286 if (NIL_P(ARGF.argv)) {
10287 ARGF.next_p = -1;
10288 }
10289 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10290 ARGF.next_p = 1;
10291 }
10292 }
10293
10294 if (ARGF.next_p == 1) {
10295 if (ARGF.init_p == 1) argf_close(argf);
10296 retry:
10297 if (RARRAY_LEN(ARGF.argv) > 0) {
10298 VALUE filename = rb_ary_shift(ARGF.argv);
10299 FilePathValue(filename);
10300 ARGF_SET(filename, filename);
10301 filename = rb_str_encode_ospath(filename);
10302 fn = StringValueCStr(filename);
10303 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10304 ARGF_SET(current_file, rb_stdin);
10305 if (ARGF.inplace) {
10306 rb_warn("Can't do inplace edit for stdio; skipping");
10307 goto retry;
10308 }
10309 }
10310 else {
10311 VALUE write_io = Qnil;
10312 int fr = rb_sysopen(filename, O_RDONLY, 0);
10313
10314 if (ARGF.inplace) {
10315 struct stat st;
10316#ifndef NO_SAFE_RENAME
10317 struct stat st2;
10318#endif
10319 VALUE str;
10320 int fw;
10321
10322 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10323 rb_io_close(r_stdout);
10324 }
10325 fstat(fr, &st);
10326 str = filename;
10327 if (!NIL_P(ARGF.inplace)) {
10328 VALUE suffix = ARGF.inplace;
10329 str = rb_str_dup(str);
10330 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10331 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10332 rb_enc_get(suffix), 0, Qnil))) {
10333 rb_str_append(str, suffix);
10334 }
10335#ifdef NO_SAFE_RENAME
10336 (void)close(fr);
10337 (void)unlink(RSTRING_PTR(str));
10338 if (rename(fn, RSTRING_PTR(str)) < 0) {
10339 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10340 filename, str, strerror(errno));
10341 goto retry;
10342 }
10343 fr = rb_sysopen(str, O_RDONLY, 0);
10344#else
10345 if (rename(fn, RSTRING_PTR(str)) < 0) {
10346 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10347 filename, str, strerror(errno));
10348 close(fr);
10349 goto retry;
10350 }
10351#endif
10352 }
10353 else {
10354#ifdef NO_SAFE_RENAME
10355 rb_fatal("Can't do inplace edit without backup");
10356#else
10357 if (unlink(fn) < 0) {
10358 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10359 filename, strerror(errno));
10360 close(fr);
10361 goto retry;
10362 }
10363#endif
10364 }
10365 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10366#ifndef NO_SAFE_RENAME
10367 fstat(fw, &st2);
10368#ifdef HAVE_FCHMOD
10369 fchmod(fw, st.st_mode);
10370#else
10371 chmod(fn, st.st_mode);
10372#endif
10373 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10374 int err;
10375#ifdef HAVE_FCHOWN
10376 err = fchown(fw, st.st_uid, st.st_gid);
10377#else
10378 err = chown(fn, st.st_uid, st.st_gid);
10379#endif
10380 if (err && getuid() == 0 && st2.st_uid == 0) {
10381 const char *wkfn = RSTRING_PTR(filename);
10382 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10383 filename, str, strerror(errno));
10384 (void)close(fr);
10385 (void)close(fw);
10386 (void)unlink(wkfn);
10387 goto retry;
10388 }
10389 }
10390#endif
10391 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10392 rb_ractor_stdout_set(write_io);
10393 if (stdout_binmode) rb_io_binmode(rb_stdout);
10394 }
10395 fmode = FMODE_READABLE;
10396 if (!ARGF.binmode) {
10397 fmode |= DEFAULT_TEXTMODE;
10398 }
10399 ARGF_SET(current_file, prep_io(fr, fmode, rb_cFile, fn));
10400 if (!NIL_P(write_io)) {
10401 rb_io_set_write_io(ARGF.current_file, write_io);
10402 }
10403 RB_GC_GUARD(filename);
10404 }
10405 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10406 GetOpenFile(ARGF.current_file, fptr);
10407 if (ARGF.encs.enc) {
10408 fptr->encs = ARGF.encs;
10409 clear_codeconv(fptr);
10410 }
10411 else {
10412 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10413 if (!ARGF.binmode) {
10415#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10416 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10417#endif
10418 }
10419 }
10420 ARGF.next_p = 0;
10421 }
10422 else {
10423 ARGF.next_p = 1;
10424 return FALSE;
10425 }
10426 }
10427 else if (ARGF.next_p == -1) {
10428 ARGF_SET(current_file, rb_stdin);
10429 ARGF_SET(filename, rb_str_new2("-"));
10430 if (ARGF.inplace) {
10431 rb_warn("Can't do inplace edit for stdio");
10432 rb_ractor_stdout_set(orig_stdout);
10433 }
10434 }
10435 if (ARGF.init_p == -1) ARGF.init_p = 1;
10436 return TRUE;
10437}
10438
10439static VALUE
10440argf_getline(int argc, VALUE *argv, VALUE argf)
10441{
10442 VALUE line;
10443 long lineno = ARGF.lineno;
10444
10445 retry:
10446 if (!next_argv()) return Qnil;
10447 if (ARGF_GENERIC_INPUT_P()) {
10448 line = forward_current(idGets, argc, argv);
10449 }
10450 else {
10451 if (argc == 0 && rb_rs == rb_default_rs) {
10452 line = rb_io_gets(ARGF.current_file);
10453 }
10454 else {
10455 line = rb_io_getline(argc, argv, ARGF.current_file);
10456 }
10457 if (NIL_P(line) && ARGF.next_p != -1) {
10458 argf_close(argf);
10459 ARGF.next_p = 1;
10460 goto retry;
10461 }
10462 }
10463 if (!NIL_P(line)) {
10464 ARGF.lineno = ++lineno;
10465 ARGF.last_lineno = ARGF.lineno;
10466 }
10467 return line;
10468}
10469
10470static VALUE
10471argf_lineno_getter(ID id, VALUE *var)
10472{
10473 VALUE argf = *var;
10474 return INT2FIX(ARGF.last_lineno);
10475}
10476
10477static void
10478argf_lineno_setter(VALUE val, ID id, VALUE *var)
10479{
10480 VALUE argf = *var;
10481 int n = NUM2INT(val);
10482 ARGF.last_lineno = ARGF.lineno = n;
10483}
10484
10485void
10486rb_reset_argf_lineno(long n)
10487{
10488 ARGF.last_lineno = ARGF.lineno = n;
10489}
10490
10491static VALUE argf_gets(int, VALUE *, VALUE);
10492
10493/*
10494 * call-seq:
10495 * gets(sep=$/ [, getline_args]) -> string or nil
10496 * gets(limit [, getline_args]) -> string or nil
10497 * gets(sep, limit [, getline_args]) -> string or nil
10498 *
10499 * Returns (and assigns to <code>$_</code>) the next line from the list
10500 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10501 * no files are present on the command line. Returns +nil+ at end of
10502 * file. The optional argument specifies the record separator. The
10503 * separator is included with the contents of each record. A separator
10504 * of +nil+ reads the entire contents, and a zero-length separator
10505 * reads the input one paragraph at a time, where paragraphs are
10506 * divided by two consecutive newlines. If the first argument is an
10507 * integer, or optional second argument is given, the returning string
10508 * would not be longer than the given value in bytes. If multiple
10509 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10510 * the contents one file at a time.
10511 *
10512 * ARGV << "testfile"
10513 * print while gets
10514 *
10515 * <em>produces:</em>
10516 *
10517 * This is line one
10518 * This is line two
10519 * This is line three
10520 * And so on...
10521 *
10522 * The style of programming using <code>$_</code> as an implicit
10523 * parameter is gradually losing favor in the Ruby community.
10524 */
10525
10526static VALUE
10527rb_f_gets(int argc, VALUE *argv, VALUE recv)
10528{
10529 if (recv == argf) {
10530 return argf_gets(argc, argv, argf);
10531 }
10532 return forward(argf, idGets, argc, argv);
10533}
10534
10535/*
10536 * call-seq:
10537 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10538 * ARGF.gets(limit [, getline_args]) -> string or nil
10539 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10540 *
10541 * Returns the next line from the current file in ARGF.
10542 *
10543 * By default lines are assumed to be separated by <code>$/</code>;
10544 * to use a different character as a separator, supply it as a String
10545 * for the _sep_ argument.
10546 *
10547 * The optional _limit_ argument specifies how many characters of each line
10548 * to return. By default all characters are returned.
10549 *
10550 * See IO.readlines for details about getline_args.
10551 *
10552 */
10553static VALUE
10554argf_gets(int argc, VALUE *argv, VALUE argf)
10555{
10556 VALUE line;
10557
10558 line = argf_getline(argc, argv, argf);
10559 rb_lastline_set(line);
10560
10561 return line;
10562}
10563
10564VALUE
10566{
10567 VALUE line;
10568
10569 if (rb_rs != rb_default_rs) {
10570 return rb_f_gets(0, 0, argf);
10571 }
10572
10573 retry:
10574 if (!next_argv()) return Qnil;
10575 line = rb_io_gets(ARGF.current_file);
10576 if (NIL_P(line) && ARGF.next_p != -1) {
10577 rb_io_close(ARGF.current_file);
10578 ARGF.next_p = 1;
10579 goto retry;
10580 }
10581 rb_lastline_set(line);
10582 if (!NIL_P(line)) {
10583 ARGF.lineno++;
10584 ARGF.last_lineno = ARGF.lineno;
10585 }
10586
10587 return line;
10588}
10589
10590static VALUE argf_readline(int, VALUE *, VALUE);
10591
10592/*
10593 * call-seq:
10594 * readline(sep = $/, chomp: false) -> string
10595 * readline(limit, chomp: false) -> string
10596 * readline(sep, limit, chomp: false) -> string
10597 *
10598 * Equivalent to method Kernel#gets, except that it raises an exception
10599 * if called at end-of-stream:
10600 *
10601 * $ cat t.txt | ruby -e "p readlines; readline"
10602 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10603 * in `readline': end of file reached (EOFError)
10604 *
10605 * Optional keyword argument +chomp+ specifies whether line separators
10606 * are to be omitted.
10607 */
10608
10609static VALUE
10610rb_f_readline(int argc, VALUE *argv, VALUE recv)
10611{
10612 if (recv == argf) {
10613 return argf_readline(argc, argv, argf);
10614 }
10615 return forward(argf, rb_intern("readline"), argc, argv);
10616}
10617
10618
10619/*
10620 * call-seq:
10621 * ARGF.readline(sep=$/) -> string
10622 * ARGF.readline(limit) -> string
10623 * ARGF.readline(sep, limit) -> string
10624 *
10625 * Returns the next line from the current file in ARGF.
10626 *
10627 * By default lines are assumed to be separated by <code>$/</code>;
10628 * to use a different character as a separator, supply it as a String
10629 * for the _sep_ argument.
10630 *
10631 * The optional _limit_ argument specifies how many characters of each line
10632 * to return. By default all characters are returned.
10633 *
10634 * An EOFError is raised at the end of the file.
10635 */
10636static VALUE
10637argf_readline(int argc, VALUE *argv, VALUE argf)
10638{
10639 VALUE line;
10640
10641 if (!next_argv()) rb_eof_error();
10642 ARGF_FORWARD(argc, argv);
10643 line = argf_gets(argc, argv, argf);
10644 if (NIL_P(line)) {
10645 rb_eof_error();
10646 }
10647
10648 return line;
10649}
10650
10651static VALUE argf_readlines(int, VALUE *, VALUE);
10652
10653/*
10654 * call-seq:
10655 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10656 * readlines(limit, chomp: false, **enc_opts) -> array
10657 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10658 *
10659 * Returns an array containing the lines returned by calling
10660 * Kernel#gets until the end-of-stream is reached;
10661 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10662 *
10663 * With only string argument +sep+ given,
10664 * returns the remaining lines as determined by line separator +sep+,
10665 * or +nil+ if none;
10666 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10667 *
10668 * # Default separator.
10669 * $ cat t.txt | ruby -e "p readlines"
10670 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10671 *
10672 * # Specified separator.
10673 * $ cat t.txt | ruby -e "p readlines 'li'"
10674 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10675 *
10676 * # Get-all separator.
10677 * $ cat t.txt | ruby -e "p readlines nil"
10678 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10679 *
10680 * # Get-paragraph separator.
10681 * $ cat t.txt | ruby -e "p readlines ''"
10682 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10683 *
10684 * With only integer argument +limit+ given,
10685 * limits the number of bytes in the line;
10686 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10687 *
10688 * $cat t.txt | ruby -e "p readlines 10"
10689 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10690 *
10691 * $cat t.txt | ruby -e "p readlines 11"
10692 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10693 *
10694 * $cat t.txt | ruby -e "p readlines 12"
10695 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10696 *
10697 * With arguments +sep+ and +limit+ given,
10698 * combines the two behaviors
10699 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10700 *
10701 * Optional keyword argument +chomp+ specifies whether line separators
10702 * are to be omitted:
10703 *
10704 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10705 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10706 *
10707 * Optional keyword arguments +enc_opts+ specify encoding options;
10708 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10709 *
10710 */
10711
10712static VALUE
10713rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10714{
10715 if (recv == argf) {
10716 return argf_readlines(argc, argv, argf);
10717 }
10718 return forward(argf, rb_intern("readlines"), argc, argv);
10719}
10720
10721/*
10722 * call-seq:
10723 * ARGF.readlines(sep = $/, chomp: false) -> array
10724 * ARGF.readlines(limit, chomp: false) -> array
10725 * ARGF.readlines(sep, limit, chomp: false) -> array
10726 *
10727 * ARGF.to_a(sep = $/, chomp: false) -> array
10728 * ARGF.to_a(limit, chomp: false) -> array
10729 * ARGF.to_a(sep, limit, chomp: false) -> array
10730 *
10731 * Reads each file in ARGF in its entirety, returning an Array containing
10732 * lines from the files. Lines are assumed to be separated by _sep_.
10733 *
10734 * lines = ARGF.readlines
10735 * lines[0] #=> "This is line one\n"
10736 *
10737 * See +IO.readlines+ for a full description of all options.
10738 */
10739static VALUE
10740argf_readlines(int argc, VALUE *argv, VALUE argf)
10741{
10742 long lineno = ARGF.lineno;
10743 VALUE lines, ary;
10744
10745 ary = rb_ary_new();
10746 while (next_argv()) {
10747 if (ARGF_GENERIC_INPUT_P()) {
10748 lines = forward_current(rb_intern("readlines"), argc, argv);
10749 }
10750 else {
10751 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10752 argf_close(argf);
10753 }
10754 ARGF.next_p = 1;
10755 rb_ary_concat(ary, lines);
10756 ARGF.lineno = lineno + RARRAY_LEN(ary);
10757 ARGF.last_lineno = ARGF.lineno;
10758 }
10759 ARGF.init_p = 0;
10760 return ary;
10761}
10762
10763/*
10764 * call-seq:
10765 * `command` -> string
10766 *
10767 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10768 * sets global variable <tt>$?</tt> to the process status.
10769 *
10770 * This method has potential security vulnerabilities if called with untrusted input;
10771 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
10772 *
10773 * Examples:
10774 *
10775 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10776 * $ `echo oops && exit 99` # => "oops\n"
10777 * $ $? # => #<Process::Status: pid 17088 exit 99>
10778 * $ $?.exitstatus # => 99
10779 *
10780 * The built-in syntax <tt>%x{...}</tt> uses this method.
10781 *
10782 */
10783
10784static VALUE
10785rb_f_backquote(VALUE obj, VALUE str)
10786{
10787 VALUE port;
10788 VALUE result;
10789 rb_io_t *fptr;
10790
10791 StringValue(str);
10792 rb_last_status_clear();
10793 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10794 if (NIL_P(port)) return rb_str_new(0,0);
10795
10796 GetOpenFile(port, fptr);
10797 result = read_all(fptr, remain_size(fptr), Qnil);
10798 rb_io_close(port);
10799 rb_io_fptr_cleanup_all(fptr);
10800 RB_GC_GUARD(port);
10801
10802 return result;
10803}
10804
10805#ifdef HAVE_SYS_SELECT_H
10806#include <sys/select.h>
10807#endif
10808
10809static VALUE
10810select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10811{
10812 VALUE res, list;
10813 rb_fdset_t *rp, *wp, *ep;
10814 rb_io_t *fptr;
10815 long i;
10816 int max = 0, n;
10817 int pending = 0;
10818 struct timeval timerec;
10819
10820 if (!NIL_P(read)) {
10821 Check_Type(read, T_ARRAY);
10822 for (i=0; i<RARRAY_LEN(read); i++) {
10823 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10824 rb_fd_set(fptr->fd, &fds[0]);
10825 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10826 pending++;
10827 rb_fd_set(fptr->fd, &fds[3]);
10828 }
10829 if (max < fptr->fd) max = fptr->fd;
10830 }
10831 if (pending) { /* no blocking if there's buffered data */
10832 timerec.tv_sec = timerec.tv_usec = 0;
10833 tp = &timerec;
10834 }
10835 rp = &fds[0];
10836 }
10837 else
10838 rp = 0;
10839
10840 if (!NIL_P(write)) {
10841 Check_Type(write, T_ARRAY);
10842 for (i=0; i<RARRAY_LEN(write); i++) {
10843 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10844 GetOpenFile(write_io, fptr);
10845 rb_fd_set(fptr->fd, &fds[1]);
10846 if (max < fptr->fd) max = fptr->fd;
10847 }
10848 wp = &fds[1];
10849 }
10850 else
10851 wp = 0;
10852
10853 if (!NIL_P(except)) {
10854 Check_Type(except, T_ARRAY);
10855 for (i=0; i<RARRAY_LEN(except); i++) {
10856 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10857 VALUE write_io = GetWriteIO(io);
10858 GetOpenFile(io, fptr);
10859 rb_fd_set(fptr->fd, &fds[2]);
10860 if (max < fptr->fd) max = fptr->fd;
10861 if (io != write_io) {
10862 GetOpenFile(write_io, fptr);
10863 rb_fd_set(fptr->fd, &fds[2]);
10864 if (max < fptr->fd) max = fptr->fd;
10865 }
10866 }
10867 ep = &fds[2];
10868 }
10869 else {
10870 ep = 0;
10871 }
10872
10873 max++;
10874
10875 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10876 if (n < 0) {
10877 rb_sys_fail(0);
10878 }
10879 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10880
10881 res = rb_ary_new2(3);
10882 rb_ary_push(res, rp ? rb_ary_new_capa(RARRAY_LEN(read)) : rb_ary_new());
10883 rb_ary_push(res, wp ? rb_ary_new_capa(RARRAY_LEN(write)) : rb_ary_new());
10884 rb_ary_push(res, ep ? rb_ary_new_capa(RARRAY_LEN(except)) : rb_ary_new());
10885
10886 if (rp) {
10887 list = RARRAY_AREF(res, 0);
10888 for (i=0; i< RARRAY_LEN(read); i++) {
10889 VALUE obj = rb_ary_entry(read, i);
10890 VALUE io = rb_io_get_io(obj);
10891 GetOpenFile(io, fptr);
10892 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10893 rb_fd_isset(fptr->fd, &fds[3])) {
10894 rb_ary_push(list, obj);
10895 }
10896 }
10897 }
10898
10899 if (wp) {
10900 list = RARRAY_AREF(res, 1);
10901 for (i=0; i< RARRAY_LEN(write); i++) {
10902 VALUE obj = rb_ary_entry(write, i);
10903 VALUE io = rb_io_get_io(obj);
10904 VALUE write_io = GetWriteIO(io);
10905 GetOpenFile(write_io, fptr);
10906 if (rb_fd_isset(fptr->fd, &fds[1])) {
10907 rb_ary_push(list, obj);
10908 }
10909 }
10910 }
10911
10912 if (ep) {
10913 list = RARRAY_AREF(res, 2);
10914 for (i=0; i< RARRAY_LEN(except); i++) {
10915 VALUE obj = rb_ary_entry(except, i);
10916 VALUE io = rb_io_get_io(obj);
10917 VALUE write_io = GetWriteIO(io);
10918 GetOpenFile(io, fptr);
10919 if (rb_fd_isset(fptr->fd, &fds[2])) {
10920 rb_ary_push(list, obj);
10921 }
10922 else if (io != write_io) {
10923 GetOpenFile(write_io, fptr);
10924 if (rb_fd_isset(fptr->fd, &fds[2])) {
10925 rb_ary_push(list, obj);
10926 }
10927 }
10928 }
10929 }
10930
10931 return res; /* returns an empty array on interrupt */
10932}
10933
10935 VALUE read, write, except;
10936 struct timeval *timeout;
10937 rb_fdset_t fdsets[4];
10938};
10939
10940static VALUE
10941select_call(VALUE arg)
10942{
10943 struct select_args *p = (struct select_args *)arg;
10944
10945 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10946}
10947
10948static VALUE
10949select_end(VALUE arg)
10950{
10951 struct select_args *p = (struct select_args *)arg;
10952 int i;
10953
10954 for (i = 0; i < numberof(p->fdsets); ++i)
10955 rb_fd_term(&p->fdsets[i]);
10956 return Qnil;
10957}
10958
10959static VALUE sym_normal, sym_sequential, sym_random,
10960 sym_willneed, sym_dontneed, sym_noreuse;
10961
10962#ifdef HAVE_POSIX_FADVISE
10963struct io_advise_struct {
10964 int fd;
10965 int advice;
10966 rb_off_t offset;
10967 rb_off_t len;
10968};
10969
10970static VALUE
10971io_advise_internal(void *arg)
10972{
10973 struct io_advise_struct *ptr = arg;
10974 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10975}
10976
10977static VALUE
10978io_advise_sym_to_const(VALUE sym)
10979{
10980#ifdef POSIX_FADV_NORMAL
10981 if (sym == sym_normal)
10982 return INT2NUM(POSIX_FADV_NORMAL);
10983#endif
10984
10985#ifdef POSIX_FADV_RANDOM
10986 if (sym == sym_random)
10987 return INT2NUM(POSIX_FADV_RANDOM);
10988#endif
10989
10990#ifdef POSIX_FADV_SEQUENTIAL
10991 if (sym == sym_sequential)
10992 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10993#endif
10994
10995#ifdef POSIX_FADV_WILLNEED
10996 if (sym == sym_willneed)
10997 return INT2NUM(POSIX_FADV_WILLNEED);
10998#endif
10999
11000#ifdef POSIX_FADV_DONTNEED
11001 if (sym == sym_dontneed)
11002 return INT2NUM(POSIX_FADV_DONTNEED);
11003#endif
11004
11005#ifdef POSIX_FADV_NOREUSE
11006 if (sym == sym_noreuse)
11007 return INT2NUM(POSIX_FADV_NOREUSE);
11008#endif
11009
11010 return Qnil;
11011}
11012
11013static VALUE
11014do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
11015{
11016 int rv;
11017 struct io_advise_struct ias;
11018 VALUE num_adv;
11019
11020 num_adv = io_advise_sym_to_const(advice);
11021
11022 /*
11023 * The platform doesn't support this hint. We don't raise exception, instead
11024 * silently ignore it. Because IO::advise is only hint.
11025 */
11026 if (NIL_P(num_adv))
11027 return Qnil;
11028
11029 ias.fd = fptr->fd;
11030 ias.advice = NUM2INT(num_adv);
11031 ias.offset = offset;
11032 ias.len = len;
11033
11034 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
11035 if (rv && rv != ENOSYS) {
11036 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
11037 it returns the error code. */
11038 VALUE message = rb_sprintf("%"PRIsVALUE" "
11039 "(%"PRI_OFFT_PREFIX"d, "
11040 "%"PRI_OFFT_PREFIX"d, "
11041 "%"PRIsVALUE")",
11042 fptr->pathv, offset, len, advice);
11043 rb_syserr_fail_str(rv, message);
11044 }
11045
11046 return Qnil;
11047}
11048
11049#endif /* HAVE_POSIX_FADVISE */
11050
11051static void
11052advice_arg_check(VALUE advice)
11053{
11054 if (!SYMBOL_P(advice))
11055 rb_raise(rb_eTypeError, "advice must be a Symbol");
11056
11057 if (advice != sym_normal &&
11058 advice != sym_sequential &&
11059 advice != sym_random &&
11060 advice != sym_willneed &&
11061 advice != sym_dontneed &&
11062 advice != sym_noreuse) {
11063 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
11064 }
11065}
11066
11067/*
11068 * call-seq:
11069 * advise(advice, offset = 0, len = 0) -> nil
11070 *
11071 * Invokes Posix system call
11072 * {posix_fadvise(2)}[https://man7.org/linux/man-pages/man2/posix_fadvise.2.html],
11073 * which announces an intention to access data from the current file
11074 * in a particular manner.
11075 *
11076 * The arguments and results are platform-dependent.
11077 *
11078 * The relevant data is specified by:
11079 *
11080 * - +offset+: The offset of the first byte of data.
11081 * - +len+: The number of bytes to be accessed;
11082 * if +len+ is zero, or is larger than the number of bytes remaining,
11083 * all remaining bytes will be accessed.
11084 *
11085 * Argument +advice+ is one of the following symbols:
11086 *
11087 * - +:normal+: The application has no advice to give
11088 * about its access pattern for the specified data.
11089 * If no advice is given for an open file, this is the default assumption.
11090 * - +:sequential+: The application expects to access the specified data sequentially
11091 * (with lower offsets read before higher ones).
11092 * - +:random+: The specified data will be accessed in random order.
11093 * - +:noreuse+: The specified data will be accessed only once.
11094 * - +:willneed+: The specified data will be accessed in the near future.
11095 * - +:dontneed+: The specified data will not be accessed in the near future.
11096 *
11097 * Not implemented on all platforms.
11098 *
11099 */
11100static VALUE
11101rb_io_advise(int argc, VALUE *argv, VALUE io)
11102{
11103 VALUE advice, offset, len;
11104 rb_off_t off, l;
11105 rb_io_t *fptr;
11106
11107 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
11108 advice_arg_check(advice);
11109
11110 io = GetWriteIO(io);
11111 GetOpenFile(io, fptr);
11112
11113 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
11114 l = NIL_P(len) ? 0 : NUM2OFFT(len);
11115
11116#ifdef HAVE_POSIX_FADVISE
11117 return do_io_advise(fptr, advice, off, l);
11118#else
11119 ((void)off, (void)l); /* Ignore all hint */
11120 return Qnil;
11121#endif
11122}
11123
11124static int
11125is_pos_inf(VALUE x)
11126{
11127 double f;
11128 if (!RB_FLOAT_TYPE_P(x))
11129 return 0;
11130 f = RFLOAT_VALUE(x);
11131 return isinf(f) && 0 < f;
11132}
11133
11134/*
11135 * call-seq:
11136 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11137 *
11138 * Invokes system call {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html],
11139 * which monitors multiple file descriptors,
11140 * waiting until one or more of the file descriptors
11141 * becomes ready for some class of I/O operation.
11142 *
11143 * Not implemented on all platforms.
11144 *
11145 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11146 * is an array of IO objects.
11147 *
11148 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11149 * interval in seconds.
11150 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11151 * +nil+ and +Float::INFINITY+ means no timeout.
11152 *
11153 * The method monitors the \IO objects given in all three arrays,
11154 * waiting for some to be ready;
11155 * returns a 3-element array whose elements are:
11156 *
11157 * - An array of the objects in +read_ios+ that are ready for reading.
11158 * - An array of the objects in +write_ios+ that are ready for writing.
11159 * - An array of the objects in +error_ios+ have pending exceptions.
11160 *
11161 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11162 *
11163 * \IO.select peeks the buffer of \IO objects for testing readability.
11164 * If the \IO buffer is not empty, \IO.select immediately notifies
11165 * readability. This "peek" only happens for \IO objects. It does not
11166 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11167 *
11168 * The best way to use \IO.select is invoking it after non-blocking
11169 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11170 * raise an exception which is extended by IO::WaitReadable or
11171 * IO::WaitWritable. The modules notify how the caller should wait
11172 * with \IO.select. If IO::WaitReadable is raised, the caller should
11173 * wait for reading. If IO::WaitWritable is raised, the caller should
11174 * wait for writing.
11175 *
11176 * So, blocking read (#readpartial) can be emulated using
11177 * #read_nonblock and \IO.select as follows:
11178 *
11179 * begin
11180 * result = io_like.read_nonblock(maxlen)
11181 * rescue IO::WaitReadable
11182 * IO.select([io_like])
11183 * retry
11184 * rescue IO::WaitWritable
11185 * IO.select(nil, [io_like])
11186 * retry
11187 * end
11188 *
11189 * Especially, the combination of non-blocking methods and \IO.select is
11190 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11191 * has #to_io method to return underlying IO object. IO.select calls
11192 * #to_io to obtain the file descriptor to wait.
11193 *
11194 * This means that readability notified by \IO.select doesn't mean
11195 * readability from OpenSSL::SSL::SSLSocket object.
11196 *
11197 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11198 * some data. \IO.select doesn't see the buffer. So \IO.select can
11199 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11200 *
11201 * However, several more complicated situations exist.
11202 *
11203 * SSL is a protocol which is sequence of records.
11204 * The record consists of multiple bytes.
11205 * So, the remote side of SSL sends a partial record, IO.select
11206 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11207 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11208 *
11209 * Also, the remote side can request SSL renegotiation which forces
11210 * the local SSL engine to write some data.
11211 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11212 * system call and it can block.
11213 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11214 * IO::WaitWritable instead of blocking.
11215 * So, the caller should wait for ready for writability as above
11216 * example.
11217 *
11218 * The combination of non-blocking methods and \IO.select is also useful
11219 * for streams such as tty, pipe socket socket when multiple processes
11220 * read from a stream.
11221 *
11222 * Finally, Linux kernel developers don't guarantee that
11223 * readability of select(2) means readability of following read(2) even
11224 * for a single process;
11225 * see {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html]
11226 *
11227 * Invoking \IO.select before IO#readpartial works well as usual.
11228 * However it is not the best way to use \IO.select.
11229 *
11230 * The writability notified by select(2) doesn't show
11231 * how many bytes are writable.
11232 * IO#write method blocks until given whole string is written.
11233 * So, <tt>IO#write(two or more bytes)</tt> can block after
11234 * writability is notified by \IO.select. IO#write_nonblock is required
11235 * to avoid the blocking.
11236 *
11237 * Blocking write (#write) can be emulated using #write_nonblock and
11238 * IO.select as follows: IO::WaitReadable should also be rescued for
11239 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11240 *
11241 * while 0 < string.bytesize
11242 * begin
11243 * written = io_like.write_nonblock(string)
11244 * rescue IO::WaitReadable
11245 * IO.select([io_like])
11246 * retry
11247 * rescue IO::WaitWritable
11248 * IO.select(nil, [io_like])
11249 * retry
11250 * end
11251 * string = string.byteslice(written..-1)
11252 * end
11253 *
11254 * Example:
11255 *
11256 * rp, wp = IO.pipe
11257 * mesg = "ping "
11258 * 100.times {
11259 * # IO.select follows IO#read. Not the best way to use IO.select.
11260 * rs, ws, = IO.select([rp], [wp])
11261 * if r = rs[0]
11262 * ret = r.read(5)
11263 * print ret
11264 * case ret
11265 * when /ping/
11266 * mesg = "pong\n"
11267 * when /pong/
11268 * mesg = "ping "
11269 * end
11270 * end
11271 * if w = ws[0]
11272 * w.write(mesg)
11273 * end
11274 * }
11275 *
11276 * Output:
11277 *
11278 * ping pong
11279 * ping pong
11280 * ping pong
11281 * (snipped)
11282 * ping
11283 *
11284 */
11285
11286static VALUE
11287rb_f_select(int argc, VALUE *argv, VALUE obj)
11288{
11289 VALUE scheduler = rb_fiber_scheduler_current();
11290 if (scheduler != Qnil) {
11291 // It's optionally supported.
11292 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11293 if (!UNDEF_P(result)) return result;
11294 }
11295
11296 VALUE timeout;
11297 struct select_args args;
11298 struct timeval timerec;
11299 int i;
11300
11301 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11302 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11303 args.timeout = 0;
11304 }
11305 else {
11306 timerec = rb_time_interval(timeout);
11307 args.timeout = &timerec;
11308 }
11309
11310 for (i = 0; i < numberof(args.fdsets); ++i)
11311 rb_fd_init(&args.fdsets[i]);
11312
11313 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11314}
11315
11316#ifdef IOCTL_REQ_TYPE
11317 typedef IOCTL_REQ_TYPE ioctl_req_t;
11318#else
11319 typedef int ioctl_req_t;
11320# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11321#endif
11322
11323#ifdef HAVE_IOCTL
11324struct ioctl_arg {
11325 int fd;
11326 ioctl_req_t cmd;
11327 long narg;
11328};
11329
11330static VALUE
11331nogvl_ioctl(void *ptr)
11332{
11333 struct ioctl_arg *arg = ptr;
11334
11335 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11336}
11337
11338static int
11339do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11340{
11341 int retval;
11342 struct ioctl_arg arg;
11343
11344 arg.fd = io->fd;
11345 arg.cmd = cmd;
11346 arg.narg = narg;
11347
11348 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11349
11350 return retval;
11351}
11352#endif
11353
11354#define DEFAULT_IOCTL_NARG_LEN (256)
11355
11356#if defined(__linux__) && defined(_IOC_SIZE)
11357static long
11358linux_iocparm_len(ioctl_req_t cmd)
11359{
11360 long len;
11361
11362 if ((cmd & 0xFFFF0000) == 0) {
11363 /* legacy and unstructured ioctl number. */
11364 return DEFAULT_IOCTL_NARG_LEN;
11365 }
11366
11367 len = _IOC_SIZE(cmd);
11368
11369 /* paranoia check for silly drivers which don't keep ioctl convention */
11370 if (len < DEFAULT_IOCTL_NARG_LEN)
11371 len = DEFAULT_IOCTL_NARG_LEN;
11372
11373 return len;
11374}
11375#endif
11376
11377#ifdef HAVE_IOCTL
11378static long
11379ioctl_narg_len(ioctl_req_t cmd)
11380{
11381 long len;
11382
11383#ifdef IOCPARM_MASK
11384#ifndef IOCPARM_LEN
11385#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11386#endif
11387#endif
11388#ifdef IOCPARM_LEN
11389 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11390#elif defined(__linux__) && defined(_IOC_SIZE)
11391 len = linux_iocparm_len(cmd);
11392#else
11393 /* otherwise guess at what's safe */
11394 len = DEFAULT_IOCTL_NARG_LEN;
11395#endif
11396
11397 return len;
11398}
11399#endif
11400
11401#ifdef HAVE_FCNTL
11402#ifdef __linux__
11403typedef long fcntl_arg_t;
11404#else
11405/* posix */
11406typedef int fcntl_arg_t;
11407#endif
11408
11409static long
11410fcntl_narg_len(ioctl_req_t cmd)
11411{
11412 long len;
11413
11414 switch (cmd) {
11415#ifdef F_DUPFD
11416 case F_DUPFD:
11417 len = sizeof(fcntl_arg_t);
11418 break;
11419#endif
11420#ifdef F_DUP2FD /* bsd specific */
11421 case F_DUP2FD:
11422 len = sizeof(int);
11423 break;
11424#endif
11425#ifdef F_DUPFD_CLOEXEC /* linux specific */
11426 case F_DUPFD_CLOEXEC:
11427 len = sizeof(fcntl_arg_t);
11428 break;
11429#endif
11430#ifdef F_GETFD
11431 case F_GETFD:
11432 len = 1;
11433 break;
11434#endif
11435#ifdef F_SETFD
11436 case F_SETFD:
11437 len = sizeof(fcntl_arg_t);
11438 break;
11439#endif
11440#ifdef F_GETFL
11441 case F_GETFL:
11442 len = 1;
11443 break;
11444#endif
11445#ifdef F_SETFL
11446 case F_SETFL:
11447 len = sizeof(fcntl_arg_t);
11448 break;
11449#endif
11450#ifdef F_GETOWN
11451 case F_GETOWN:
11452 len = 1;
11453 break;
11454#endif
11455#ifdef F_SETOWN
11456 case F_SETOWN:
11457 len = sizeof(fcntl_arg_t);
11458 break;
11459#endif
11460#ifdef F_GETOWN_EX /* linux specific */
11461 case F_GETOWN_EX:
11462 len = sizeof(struct f_owner_ex);
11463 break;
11464#endif
11465#ifdef F_SETOWN_EX /* linux specific */
11466 case F_SETOWN_EX:
11467 len = sizeof(struct f_owner_ex);
11468 break;
11469#endif
11470#ifdef F_GETLK
11471 case F_GETLK:
11472 len = sizeof(struct flock);
11473 break;
11474#endif
11475#ifdef F_SETLK
11476 case F_SETLK:
11477 len = sizeof(struct flock);
11478 break;
11479#endif
11480#ifdef F_SETLKW
11481 case F_SETLKW:
11482 len = sizeof(struct flock);
11483 break;
11484#endif
11485#ifdef F_READAHEAD /* bsd specific */
11486 case F_READAHEAD:
11487 len = sizeof(int);
11488 break;
11489#endif
11490#ifdef F_RDAHEAD /* Darwin specific */
11491 case F_RDAHEAD:
11492 len = sizeof(int);
11493 break;
11494#endif
11495#ifdef F_GETSIG /* linux specific */
11496 case F_GETSIG:
11497 len = 1;
11498 break;
11499#endif
11500#ifdef F_SETSIG /* linux specific */
11501 case F_SETSIG:
11502 len = sizeof(fcntl_arg_t);
11503 break;
11504#endif
11505#ifdef F_GETLEASE /* linux specific */
11506 case F_GETLEASE:
11507 len = 1;
11508 break;
11509#endif
11510#ifdef F_SETLEASE /* linux specific */
11511 case F_SETLEASE:
11512 len = sizeof(fcntl_arg_t);
11513 break;
11514#endif
11515#ifdef F_NOTIFY /* linux specific */
11516 case F_NOTIFY:
11517 len = sizeof(fcntl_arg_t);
11518 break;
11519#endif
11520
11521 default:
11522 len = 256;
11523 break;
11524 }
11525
11526 return len;
11527}
11528#else /* HAVE_FCNTL */
11529static long
11530fcntl_narg_len(ioctl_req_t cmd)
11531{
11532 return 0;
11533}
11534#endif /* HAVE_FCNTL */
11535
11536#define NARG_SENTINEL 17
11537
11538static long
11539setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11540{
11541 long narg = 0;
11542 VALUE arg = *argp;
11543
11544 if (!RTEST(arg)) {
11545 narg = 0;
11546 }
11547 else if (FIXNUM_P(arg)) {
11548 narg = FIX2LONG(arg);
11549 }
11550 else if (arg == Qtrue) {
11551 narg = 1;
11552 }
11553 else {
11554 VALUE tmp = rb_check_string_type(arg);
11555
11556 if (NIL_P(tmp)) {
11557 narg = NUM2LONG(arg);
11558 }
11559 else {
11560 char *ptr;
11561 long len, slen;
11562
11563 *argp = arg = tmp;
11564 len = narg_len(cmd);
11565 rb_str_modify(arg);
11566
11567 slen = RSTRING_LEN(arg);
11568 /* expand for data + sentinel. */
11569 if (slen < len+1) {
11570 rb_str_resize(arg, len+1);
11571 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11572 slen = len+1;
11573 }
11574 /* a little sanity check here */
11575 ptr = RSTRING_PTR(arg);
11576 ptr[slen - 1] = NARG_SENTINEL;
11577 narg = (long)(SIGNED_VALUE)ptr;
11578 }
11579 }
11580
11581 return narg;
11582}
11583
11584static VALUE
11585finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11586{
11587 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11588 if (RB_TYPE_P(arg, T_STRING)) {
11589 char *ptr;
11590 long slen;
11591 RSTRING_GETMEM(arg, ptr, slen);
11592 if (ptr[slen-1] != NARG_SENTINEL)
11593 rb_raise(rb_eArgError, "return value overflowed string");
11594 ptr[slen-1] = '\0';
11595 }
11596
11597 return INT2NUM(retval);
11598}
11599
11600#ifdef HAVE_IOCTL
11601static VALUE
11602rb_ioctl(VALUE io, VALUE req, VALUE arg)
11603{
11604 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11605 rb_io_t *fptr;
11606 long narg;
11607 int retval;
11608
11609 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11610 GetOpenFile(io, fptr);
11611 retval = do_ioctl(fptr, cmd, narg);
11612 return finish_narg(retval, arg, fptr);
11613}
11614
11615/*
11616 * call-seq:
11617 * ioctl(integer_cmd, argument) -> integer
11618 *
11619 * Invokes Posix system call {ioctl(2)}[https://man7.org/linux/man-pages/man2/ioctl.2.html],
11620 * which issues a low-level command to an I/O device.
11621 *
11622 * Issues a low-level command to an I/O device.
11623 * The arguments and returned value are platform-dependent.
11624 * The effect of the call is platform-dependent.
11625 *
11626 * If argument +argument+ is an integer, it is passed directly;
11627 * if it is a string, it is interpreted as a binary sequence of bytes.
11628 *
11629 * Not implemented on all platforms.
11630 *
11631 */
11632
11633static VALUE
11634rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11635{
11636 VALUE req, arg;
11637
11638 rb_scan_args(argc, argv, "11", &req, &arg);
11639 return rb_ioctl(io, req, arg);
11640}
11641#else
11642#define rb_io_ioctl rb_f_notimplement
11643#endif
11644
11645#ifdef HAVE_FCNTL
11646struct fcntl_arg {
11647 int fd;
11648 int cmd;
11649 long narg;
11650};
11651
11652static VALUE
11653nogvl_fcntl(void *ptr)
11654{
11655 struct fcntl_arg *arg = ptr;
11656
11657#if defined(F_DUPFD)
11658 if (arg->cmd == F_DUPFD)
11659 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11660#endif
11661 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11662}
11663
11664static int
11665do_fcntl(struct rb_io *io, int cmd, long narg)
11666{
11667 int retval;
11668 struct fcntl_arg arg;
11669
11670 arg.fd = io->fd;
11671 arg.cmd = cmd;
11672 arg.narg = narg;
11673
11674 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11675 if (retval != -1) {
11676 switch (cmd) {
11677#if defined(F_DUPFD)
11678 case F_DUPFD:
11679#endif
11680#if defined(F_DUPFD_CLOEXEC)
11681 case F_DUPFD_CLOEXEC:
11682#endif
11683 rb_update_max_fd(retval);
11684 }
11685 }
11686
11687 return retval;
11688}
11689
11690static VALUE
11691rb_fcntl(VALUE io, VALUE req, VALUE arg)
11692{
11693 int cmd = NUM2INT(req);
11694 rb_io_t *fptr;
11695 long narg;
11696 int retval;
11697
11698 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11699 GetOpenFile(io, fptr);
11700 retval = do_fcntl(fptr, cmd, narg);
11701 return finish_narg(retval, arg, fptr);
11702}
11703
11704/*
11705 * call-seq:
11706 * fcntl(integer_cmd, argument) -> integer
11707 *
11708 * Invokes Posix system call {fcntl(2)}[https://man7.org/linux/man-pages/man2/fcntl.2.html],
11709 * which provides a mechanism for issuing low-level commands to control or query
11710 * a file-oriented I/O stream. Arguments and results are platform
11711 * dependent.
11712 *
11713 * If +argument+ is a number, its value is passed directly;
11714 * if it is a string, it is interpreted as a binary sequence of bytes.
11715 * (Array#pack might be a useful way to build this string.)
11716 *
11717 * Not implemented on all platforms.
11718 *
11719 */
11720
11721static VALUE
11722rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11723{
11724 VALUE req, arg;
11725
11726 rb_scan_args(argc, argv, "11", &req, &arg);
11727 return rb_fcntl(io, req, arg);
11728}
11729#else
11730#define rb_io_fcntl rb_f_notimplement
11731#endif
11732
11733#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11734/*
11735 * call-seq:
11736 * syscall(integer_callno, *arguments) -> integer
11737 *
11738 * Invokes Posix system call {syscall(2)}[https://man7.org/linux/man-pages/man2/syscall.2.html],
11739 * which calls a specified function.
11740 *
11741 * Calls the operating system function identified by +integer_callno+;
11742 * returns the result of the function or raises SystemCallError if it failed.
11743 * The effect of the call is platform-dependent.
11744 * The arguments and returned value are platform-dependent.
11745 *
11746 * For each of +arguments+: if it is an integer, it is passed directly;
11747 * if it is a string, it is interpreted as a binary sequence of bytes.
11748 * There may be as many as nine such arguments.
11749 *
11750 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11751 * are platform-dependent.
11752 *
11753 * Note: Method +syscall+ is essentially unsafe and unportable.
11754 * The DL (Fiddle) library is preferred for safer and a bit
11755 * more portable programming.
11756 *
11757 * Not implemented on all platforms.
11758 *
11759 */
11760
11761static VALUE
11762rb_f_syscall(int argc, VALUE *argv, VALUE _)
11763{
11764 VALUE arg[8];
11765#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11766# define SYSCALL __syscall
11767# define NUM2SYSCALLID(x) NUM2LONG(x)
11768# define RETVAL2NUM(x) LONG2NUM(x)
11769# if SIZEOF_LONG == 8
11770 long num, retval = -1;
11771# elif SIZEOF_LONG_LONG == 8
11772 long long num, retval = -1;
11773# else
11774# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11775# endif
11776#elif defined(__linux__)
11777# define SYSCALL syscall
11778# define NUM2SYSCALLID(x) NUM2LONG(x)
11779# define RETVAL2NUM(x) LONG2NUM(x)
11780 /*
11781 * Linux man page says, syscall(2) function prototype is below.
11782 *
11783 * int syscall(int number, ...);
11784 *
11785 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11786 */
11787 long num, retval = -1;
11788#else
11789# define SYSCALL syscall
11790# define NUM2SYSCALLID(x) NUM2INT(x)
11791# define RETVAL2NUM(x) INT2NUM(x)
11792 int num, retval = -1;
11793#endif
11794 int i;
11795
11796 if (RTEST(ruby_verbose)) {
11798 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11799 }
11800
11801 if (argc == 0)
11802 rb_raise(rb_eArgError, "too few arguments for syscall");
11803 if (argc > numberof(arg))
11804 rb_raise(rb_eArgError, "too many arguments for syscall");
11805 num = NUM2SYSCALLID(argv[0]); ++argv;
11806 for (i = argc - 1; i--; ) {
11807 VALUE v = rb_check_string_type(argv[i]);
11808
11809 if (!NIL_P(v)) {
11810 StringValue(v);
11811 rb_str_modify(v);
11812 arg[i] = (VALUE)StringValueCStr(v);
11813 }
11814 else {
11815 arg[i] = (VALUE)NUM2LONG(argv[i]);
11816 }
11817 }
11818
11819 switch (argc) {
11820 case 1:
11821 retval = SYSCALL(num);
11822 break;
11823 case 2:
11824 retval = SYSCALL(num, arg[0]);
11825 break;
11826 case 3:
11827 retval = SYSCALL(num, arg[0],arg[1]);
11828 break;
11829 case 4:
11830 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11831 break;
11832 case 5:
11833 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11834 break;
11835 case 6:
11836 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11837 break;
11838 case 7:
11839 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11840 break;
11841 case 8:
11842 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11843 break;
11844 }
11845
11846 if (retval == -1)
11847 rb_sys_fail(0);
11848 return RETVAL2NUM(retval);
11849#undef SYSCALL
11850#undef NUM2SYSCALLID
11851#undef RETVAL2NUM
11852}
11853#else
11854#define rb_f_syscall rb_f_notimplement
11855#endif
11856
11857static VALUE
11858io_new_instance(VALUE args)
11859{
11860 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11861}
11862
11863static rb_encoding *
11864find_encoding(VALUE v)
11865{
11866 rb_encoding *enc = rb_find_encoding(v);
11867 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11868 return enc;
11869}
11870
11871static void
11872io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11873{
11874 rb_encoding *enc, *enc2;
11875 int ecflags = fptr->encs.ecflags;
11876 VALUE ecopts, tmp;
11877
11878 if (!NIL_P(v2)) {
11879 enc2 = find_encoding(v1);
11880 tmp = rb_check_string_type(v2);
11881 if (!NIL_P(tmp)) {
11882 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11883 /* Special case - "-" => no transcoding */
11884 enc = enc2;
11885 enc2 = NULL;
11886 }
11887 else
11888 enc = find_encoding(v2);
11889 if (enc == enc2) {
11890 /* Special case - "-" => no transcoding */
11891 enc2 = NULL;
11892 }
11893 }
11894 else {
11895 enc = find_encoding(v2);
11896 if (enc == enc2) {
11897 /* Special case - "-" => no transcoding */
11898 enc2 = NULL;
11899 }
11900 }
11901 if (enc2 == rb_ascii8bit_encoding()) {
11902 /* If external is ASCII-8BIT, no transcoding */
11903 enc = enc2;
11904 enc2 = NULL;
11905 }
11906 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11907 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11908 }
11909 else {
11910 if (NIL_P(v1)) {
11911 /* Set to default encodings */
11912 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11913 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11914 ecopts = Qnil;
11915 }
11916 else {
11917 tmp = rb_check_string_type(v1);
11918 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11919 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11920 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11921 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11922 }
11923 else {
11924 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11925 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11926 ecopts = Qnil;
11927 }
11928 }
11929 }
11930 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11931 fptr->encs.enc = enc;
11932 fptr->encs.enc2 = enc2;
11933 fptr->encs.ecflags = ecflags;
11934 fptr->encs.ecopts = ecopts;
11935 clear_codeconv(fptr);
11936
11937}
11938
11940 rb_io_t *fptr;
11941 VALUE v1;
11942 VALUE v2;
11943 VALUE opt;
11944};
11945
11946static VALUE
11947io_encoding_set_v(VALUE v)
11948{
11949 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11950 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11951 return Qnil;
11952}
11953
11954static VALUE
11955pipe_pair_close(VALUE rw)
11956{
11957 VALUE *rwp = (VALUE *)rw;
11958 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11959}
11960
11961/*
11962 * call-seq:
11963 * IO.pipe(**opts) -> [read_io, write_io]
11964 * IO.pipe(enc, **opts) -> [read_io, write_io]
11965 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11966 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11967 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11968 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11969 *
11970 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11971 * connected to each other.
11972 *
11973 * If argument +enc_string+ is given, it must be a string containing one of:
11974 *
11975 * - The name of the encoding to be used as the external encoding.
11976 * - The colon-separated names of two encodings to be used as the external
11977 * and internal encodings.
11978 *
11979 * If argument +int_enc+ is given, it must be an Encoding object
11980 * or encoding name string that specifies the internal encoding to be used;
11981 * if argument +ext_enc+ is also given, it must be an Encoding object
11982 * or encoding name string that specifies the external encoding to be used.
11983 *
11984 * The string read from +read_io+ is tagged with the external encoding;
11985 * if an internal encoding is also specified, the string is converted
11986 * to, and tagged with, that encoding.
11987 *
11988 * If any encoding is specified,
11989 * optional hash arguments specify the conversion option.
11990 *
11991 * Optional keyword arguments +opts+ specify:
11992 *
11993 * - {Open Options}[rdoc-ref:IO@Open+Options].
11994 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11995 *
11996 * With no block given, returns the two endpoints in an array:
11997 *
11998 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11999 *
12000 * With a block given, calls the block with the two endpoints;
12001 * closes both endpoints and returns the value of the block:
12002 *
12003 * IO.pipe {|read_io, write_io| p read_io; p write_io }
12004 *
12005 * Output:
12006 *
12007 * #<IO:fd 6>
12008 * #<IO:fd 7>
12009 *
12010 * Not available on all platforms.
12011 *
12012 * In the example below, the two processes close the ends of the pipe
12013 * that they are not using. This is not just a cosmetic nicety. The
12014 * read end of a pipe will not generate an end of file condition if
12015 * there are any writers with the pipe still open. In the case of the
12016 * parent process, the <tt>rd.read</tt> will never return if it
12017 * does not first issue a <tt>wr.close</tt>:
12018 *
12019 * rd, wr = IO.pipe
12020 *
12021 * if fork
12022 * wr.close
12023 * puts "Parent got: <#{rd.read}>"
12024 * rd.close
12025 * Process.wait
12026 * else
12027 * rd.close
12028 * puts 'Sending message to parent'
12029 * wr.write "Hi Dad"
12030 * wr.close
12031 * end
12032 *
12033 * <em>produces:</em>
12034 *
12035 * Sending message to parent
12036 * Parent got: <Hi Dad>
12037 *
12038 */
12039
12040static VALUE
12041rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
12042{
12043 int pipes[2], state;
12044 VALUE r, w, args[3], v1, v2;
12045 VALUE opt;
12046 rb_io_t *fptr, *fptr2;
12047 struct io_encoding_set_args ies_args;
12048 enum rb_io_mode fmode = 0;
12049 VALUE ret;
12050
12051 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
12052 if (rb_pipe(pipes) < 0)
12053 rb_sys_fail(0);
12054
12055 args[0] = klass;
12056 args[1] = INT2NUM(pipes[0]);
12057 args[2] = INT2FIX(O_RDONLY);
12058 r = rb_protect(io_new_instance, (VALUE)args, &state);
12059 if (state) {
12060 close(pipes[0]);
12061 close(pipes[1]);
12062 rb_jump_tag(state);
12063 }
12064 GetOpenFile(r, fptr);
12065
12066 ies_args.fptr = fptr;
12067 ies_args.v1 = v1;
12068 ies_args.v2 = v2;
12069 ies_args.opt = opt;
12070 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
12071 if (state) {
12072 close(pipes[1]);
12073 io_close(r);
12074 rb_jump_tag(state);
12075 }
12076
12077 args[1] = INT2NUM(pipes[1]);
12078 args[2] = INT2FIX(O_WRONLY);
12079 w = rb_protect(io_new_instance, (VALUE)args, &state);
12080 if (state) {
12081 close(pipes[1]);
12082 if (!NIL_P(r)) rb_io_close(r);
12083 rb_jump_tag(state);
12084 }
12085 GetOpenFile(w, fptr2);
12086 rb_io_synchronized(fptr2);
12087
12088 extract_binmode(opt, &fmode);
12089
12090 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
12093 }
12094
12095#if DEFAULT_TEXTMODE
12096 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12097 fptr->mode &= ~FMODE_TEXTMODE;
12098 setmode(fptr->fd, O_BINARY);
12099 }
12100#if RUBY_CRLF_ENVIRONMENT
12103 }
12104#endif
12105#endif
12106 fptr->mode |= fmode;
12107#if DEFAULT_TEXTMODE
12108 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12109 fptr2->mode &= ~FMODE_TEXTMODE;
12110 setmode(fptr2->fd, O_BINARY);
12111 }
12112#endif
12113 fptr2->mode |= fmode;
12114
12115 ret = rb_assoc_new(r, w);
12116 if (rb_block_given_p()) {
12117 VALUE rw[2];
12118 rw[0] = r;
12119 rw[1] = w;
12120 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12121 }
12122 return ret;
12123}
12124
12126 int argc;
12127 VALUE *argv;
12128 VALUE io;
12129};
12130
12131static void
12132open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12133{
12134 VALUE path, v;
12135 VALUE vmode = Qnil, vperm = Qnil;
12136
12137 path = *argv++;
12138 argc--;
12139 FilePathValue(path);
12140 arg->io = 0;
12141 arg->argc = argc;
12142 arg->argv = argv;
12143 if (NIL_P(opt)) {
12144 vmode = INT2NUM(O_RDONLY);
12145 vperm = INT2FIX(0666);
12146 }
12147 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12148 int n;
12149
12150 v = rb_to_array_type(v);
12151 n = RARRAY_LENINT(v);
12152 rb_check_arity(n, 0, 3); /* rb_io_open */
12153 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12154 }
12155 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12156}
12157
12158static VALUE
12159io_s_foreach(VALUE v)
12160{
12161 struct getline_arg *arg = (void *)v;
12162 VALUE str;
12163
12164 if (arg->limit == 0)
12165 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12166 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12167 rb_lastline_set(str);
12168 rb_yield(str);
12169 }
12171 return Qnil;
12172}
12173
12174/*
12175 * call-seq:
12176 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12177 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12178 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12179 * IO.foreach(...) -> an_enumerator
12180 *
12181 * Calls the block with each successive line read from the stream.
12182 *
12183 * The first argument must be a string that is the path to a file.
12184 *
12185 * With only argument +path+ given, parses lines from the file at the given +path+,
12186 * as determined by the default line separator,
12187 * and calls the block with each successive line:
12188 *
12189 * File.foreach('t.txt') {|line| p line }
12190 *
12191 * Output: the same as above.
12192 *
12193 * For both forms, command and path, the remaining arguments are the same.
12194 *
12195 * With argument +sep+ given, parses lines as determined by that line separator
12196 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12197 *
12198 * File.foreach('t.txt', 'li') {|line| p line }
12199 *
12200 * Output:
12201 *
12202 * "First li"
12203 * "ne\nSecond li"
12204 * "ne\n\nThird li"
12205 * "ne\nFourth li"
12206 * "ne\n"
12207 *
12208 * Each paragraph:
12209 *
12210 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12211 *
12212 * Output:
12213 *
12214 * "First line\nSecond line\n\n"
12215 * "Third line\nFourth line\n"
12216 *
12217 * With argument +limit+ given, parses lines as determined by the default
12218 * line separator and the given line-length limit
12219 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12220 *
12221 * File.foreach('t.txt', 7) {|line| p line }
12222 *
12223 * Output:
12224 *
12225 * "First l"
12226 * "ine\n"
12227 * "Second "
12228 * "line\n"
12229 * "\n"
12230 * "Third l"
12231 * "ine\n"
12232 * "Fourth l"
12233 * "line\n"
12234 *
12235 * With arguments +sep+ and +limit+ given,
12236 * combines the two behaviors
12237 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12238 *
12239 * Optional keyword arguments +opts+ specify:
12240 *
12241 * - {Open Options}[rdoc-ref:IO@Open+Options].
12242 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12243 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12244 *
12245 * Returns an Enumerator if no block is given.
12246 *
12247 */
12248
12249static VALUE
12250rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12251{
12252 VALUE opt;
12253 int orig_argc = argc;
12254 struct foreach_arg arg;
12255 struct getline_arg garg;
12256
12257 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12258 RETURN_ENUMERATOR(self, orig_argc, argv);
12259 extract_getline_args(argc-1, argv+1, &garg);
12260 open_key_args(self, argc, argv, opt, &arg);
12261 if (NIL_P(arg.io)) return Qnil;
12262 extract_getline_opts(opt, &garg);
12263 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12264 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12265}
12266
12267static VALUE
12268io_s_readlines(VALUE v)
12269{
12270 struct getline_arg *arg = (void *)v;
12271 return io_readlines(arg, arg->io);
12272}
12273
12274/*
12275 * call-seq:
12276 * IO.readlines(path, sep = $/, **opts) -> array
12277 * IO.readlines(path, limit, **opts) -> array
12278 * IO.readlines(path, sep, limit, **opts) -> array
12279 *
12280 * Returns an array of all lines read from the stream.
12281 *
12282 * The first argument must be a string that is the path to a file.
12283 *
12284 * With only argument +path+ given, parses lines from the file at the given +path+,
12285 * as determined by the default line separator,
12286 * and returns those lines in an array:
12287 *
12288 * IO.readlines('t.txt')
12289 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12290 *
12291 * With argument +sep+ given, parses lines as determined by that line separator
12292 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12293 *
12294 * # Ordinary separator.
12295 * IO.readlines('t.txt', 'li')
12296 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12297 * # Get-paragraphs separator.
12298 * IO.readlines('t.txt', '')
12299 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12300 * # Get-all separator.
12301 * IO.readlines('t.txt', nil)
12302 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12303 *
12304 * With argument +limit+ given, parses lines as determined by the default
12305 * line separator and the given line-length limit
12306 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12307 *
12308 * IO.readlines('t.txt', 7)
12309 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12310 *
12311 * With arguments +sep+ and +limit+ given,
12312 * combines the two behaviors
12313 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12314 *
12315 * Optional keyword arguments +opts+ specify:
12316 *
12317 * - {Open Options}[rdoc-ref:IO@Open+Options].
12318 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12319 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12320 *
12321 */
12322
12323static VALUE
12324rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12325{
12326 VALUE opt;
12327 struct foreach_arg arg;
12328 struct getline_arg garg;
12329
12330 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12331 extract_getline_args(argc-1, argv+1, &garg);
12332 open_key_args(io, argc, argv, opt, &arg);
12333 if (NIL_P(arg.io)) return Qnil;
12334 extract_getline_opts(opt, &garg);
12335 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12336 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12337}
12338
12339static VALUE
12340io_s_read(VALUE v)
12341{
12342 struct foreach_arg *arg = (void *)v;
12343 return io_read(arg->argc, arg->argv, arg->io);
12344}
12345
12346struct seek_arg {
12347 VALUE io;
12348 VALUE offset;
12349 int mode;
12350};
12351
12352static VALUE
12353seek_before_access(VALUE argp)
12354{
12355 struct seek_arg *arg = (struct seek_arg *)argp;
12356 rb_io_binmode(arg->io);
12357 return rb_io_seek(arg->io, arg->offset, arg->mode);
12358}
12359
12360/*
12361 * call-seq:
12362 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12363 *
12364 * Opens the stream, reads and returns some or all of its content,
12365 * and closes the stream; returns +nil+ if no bytes were read.
12366 *
12367 * The first argument must be a string that is the path to a file.
12368 *
12369 * With only argument +path+ given, reads in text mode and returns the entire content
12370 * of the file at the given path:
12371 *
12372 * File.read('t.txt')
12373 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
12374 * File.read('t.ja')
12375 * # => "こんにちは"
12376 * File.read('t.dat')
12377 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12378 *
12379 * On Windows, text mode can terminate reading and leave bytes in the file
12380 * unread when encountering certain special bytes. Consider using
12381 * IO.binread if all bytes in the file should be read.
12382 *
12383 * With argument +length+, returns +length+ bytes if available:
12384 *
12385 * File.read('t.txt', 7)
12386 * # => "First l"
12387 * File.read('t.ja', 7)
12388 * # => "\xE3\x81\x93\xE3\x82\x93\xE3"
12389 * File.read('t.dat', 7)
12390 * # => "\xFE\xFF\x99\x90\x99\x91\x99"
12391 *
12392 * Returns all bytes if +length+ is larger than the files size:
12393 *
12394 * File.read('t.txt', 700)
12395 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12396 * File.read('t.ja', 700)
12397 * # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
12398 * File.read('t.dat', 700)
12399 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12400 *
12401 * With arguments +length+ and +offset+, returns +length+ bytes
12402 * if available, beginning at the given +offset+:
12403 *
12404 * File.read('t.txt', 10, 2)
12405 * # => "rst line\r\n"
12406 * File.read('t.ja', 10, 2)
12407 * # => "\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1"
12408 * File.read('t.dat', 10, 2)
12409 * # => "\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12410 *
12411 * Returns +nil+ if +offset+ is past the end of the stream:
12412 *
12413 * File.read('t.txt', 10, 200)
12414 * # => nil
12415 *
12416 * Optional keyword arguments +opts+ specify:
12417 *
12418 * - {Open Options}[rdoc-ref:IO@Open+Options].
12419 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12420 *
12421 */
12422
12423static VALUE
12424rb_io_s_read(int argc, VALUE *argv, VALUE io)
12425{
12426 VALUE opt, offset;
12427 long off;
12428 struct foreach_arg arg;
12429
12430 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12431 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12432 rb_raise(rb_eArgError, "negative offset %ld given", off);
12433 }
12434 open_key_args(io, argc, argv, opt, &arg);
12435 if (NIL_P(arg.io)) return Qnil;
12436 if (!NIL_P(offset)) {
12437 struct seek_arg sarg;
12438 int state = 0;
12439 sarg.io = arg.io;
12440 sarg.offset = offset;
12441 sarg.mode = SEEK_SET;
12442 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12443 if (state) {
12444 rb_io_close(arg.io);
12445 rb_jump_tag(state);
12446 }
12447 if (arg.argc == 2) arg.argc = 1;
12448 }
12449 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12450}
12451
12452/*
12453 * call-seq:
12454 * IO.binread(path, length = nil, offset = 0) -> string or nil
12455 *
12456 * Behaves like IO.read, except that the stream is opened in binary mode
12457 * with ASCII-8BIT encoding.
12458 *
12459 */
12460
12461static VALUE
12462rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12463{
12464 VALUE offset;
12465 struct foreach_arg arg;
12466 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12467 enum {
12468 oflags = O_RDONLY
12469#ifdef O_BINARY
12470 |O_BINARY
12471#endif
12472 };
12473 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12474
12475 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12476 FilePathValue(argv[0]);
12477 convconfig.enc = rb_ascii8bit_encoding();
12478 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12479 if (NIL_P(arg.io)) return Qnil;
12480 arg.argv = argv+1;
12481 arg.argc = (argc > 1) ? 1 : 0;
12482 if (!NIL_P(offset)) {
12483 struct seek_arg sarg;
12484 int state = 0;
12485 sarg.io = arg.io;
12486 sarg.offset = offset;
12487 sarg.mode = SEEK_SET;
12488 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12489 if (state) {
12490 rb_io_close(arg.io);
12491 rb_jump_tag(state);
12492 }
12493 }
12494 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12495}
12496
12497static VALUE
12498io_s_write0(VALUE v)
12499{
12500 struct write_arg *arg = (void *)v;
12501 return io_write(arg->io,arg->str,arg->nosync);
12502}
12503
12504static VALUE
12505io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12506{
12507 VALUE string, offset, opt;
12508 struct foreach_arg arg;
12509 struct write_arg warg;
12510
12511 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12512
12513 if (NIL_P(opt)) opt = rb_hash_new();
12514 else opt = rb_hash_dup(opt);
12515
12516
12517 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12518 int mode = O_WRONLY|O_CREAT;
12519#ifdef O_BINARY
12520 if (binary) mode |= O_BINARY;
12521#endif
12522 if (NIL_P(offset)) mode |= O_TRUNC;
12523 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12524 }
12525 open_key_args(klass, argc, argv, opt, &arg);
12526
12527#ifndef O_BINARY
12528 if (binary) rb_io_binmode_m(arg.io);
12529#endif
12530
12531 if (NIL_P(arg.io)) return Qnil;
12532 if (!NIL_P(offset)) {
12533 struct seek_arg sarg;
12534 int state = 0;
12535 sarg.io = arg.io;
12536 sarg.offset = offset;
12537 sarg.mode = SEEK_SET;
12538 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12539 if (state) {
12540 rb_io_close(arg.io);
12541 rb_jump_tag(state);
12542 }
12543 }
12544
12545 warg.io = arg.io;
12546 warg.str = string;
12547 warg.nosync = 0;
12548
12549 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12550}
12551
12552/*
12553 * call-seq:
12554 * IO.write(path, data, offset = 0, **opts) -> nonnegative_integer
12555 *
12556 * Opens the stream, writes the given +data+ to it,
12557 * and closes the stream; returns the number of bytes written.
12558 *
12559 * The first argument must be a string that is the path to a file.
12560 *
12561 * With only arguments +path+ and +data+ given,
12562 * writes the given data to the file at that path:
12563 *
12564 * path = 't.tmp'
12565 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n") # => 47
12566 * File.write(path, 'こんにちは') # => 15
12567 * File.write(path, "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94") # => 12
12568 *
12569 * When +offset+ is zero (the default), the entire file content is overwritten:
12570 *
12571 * File.read(path) # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12572 * File.write(path, 'foo')
12573 * File.read(path) # => "foo"
12574 *
12575 * When +offset+ in within the file content, the file content is partly overwritten,
12576 * beginning at byte +offset+:
12577 *
12578 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12579 * File.write(path, 'LINE', 6)
12580 * File.read(path) # => "First LINE\nSecond line\n\nFourth line\nFifth line\n"
12581 *
12582 * When the file contains multi-byte characters,
12583 * the effect of writing may disturb some characters:
12584 *
12585 * File.write(path, "こんにちは")
12586 * File.write(path, 'FOO', 3) # Replace one 3-byte character.
12587 * File.read(path) # => "こFOOにちは"
12588 * File.write(path, 'BAR', 7) # Replace bytes in two different 3-byte characters.
12589 * File.read(path) # => "こFOO\xE3BAR\x81\xA1は"
12590 *
12591 * If +offset+ is outside the file content,
12592 * the file is padded with null characters <tt>"\u0000"</tt>:
12593 *
12594 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12595 * File.write(path, 'FOO', 55)
12596 * File.read(path)
12597 * # => "First line\nSecond line\n\nFourth line\nFifth line\n\u0000\u0000\u0000FOO"
12598 *
12599 * Optional keyword arguments +opts+ specify:
12600 *
12601 * - {Open Options}[rdoc-ref:IO@Open+Options].
12602 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12603 *
12604 */
12605
12606static VALUE
12607rb_io_s_write(int argc, VALUE *argv, VALUE io)
12608{
12609 return io_s_write(argc, argv, io, 0);
12610}
12611
12612/*
12613 * call-seq:
12614 * IO.binwrite(path, string, offset = 0, **opts) -> integer
12615 *
12616 * Behaves like IO.write, except that the stream is opened in binary mode
12617 * with ASCII-8BIT encoding.
12618 *
12619 */
12620
12621static VALUE
12622rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12623{
12624 return io_s_write(argc, argv, io, 1);
12625}
12626
12628 VALUE src;
12629 VALUE dst;
12630 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12631 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12632
12633 rb_io_t *src_fptr;
12634 rb_io_t *dst_fptr;
12635 unsigned close_src : 1;
12636 unsigned close_dst : 1;
12637 int error_no;
12638 rb_off_t total;
12639 const char *syserr;
12640 const char *notimp;
12641 VALUE th;
12642 struct stat src_stat;
12643 struct stat dst_stat;
12644#ifdef HAVE_FCOPYFILE
12645 copyfile_state_t copyfile_state;
12646#endif
12647};
12648
12649static void *
12650exec_interrupts(void *arg)
12651{
12652 VALUE th = (VALUE)arg;
12653 rb_thread_execute_interrupts(th);
12654 return NULL;
12655}
12656
12657/*
12658 * returns TRUE if the preceding system call was interrupted
12659 * so we can continue. If the thread was interrupted, we
12660 * reacquire the GVL to execute interrupts before continuing.
12661 */
12662static int
12663maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12664{
12665 switch (errno) {
12666 case EINTR:
12667#if defined(ERESTART)
12668 case ERESTART:
12669#endif
12670 if (rb_thread_interrupted(stp->th)) {
12671 if (has_gvl)
12672 rb_thread_execute_interrupts(stp->th);
12673 else
12674 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12675 }
12676 return TRUE;
12677 }
12678 return FALSE;
12679}
12680
12682 VALUE scheduler;
12683
12684 rb_io_t *fptr;
12685 short events;
12686
12687 VALUE result;
12688};
12689
12690static void *
12691fiber_scheduler_wait_for(void * _arguments)
12692{
12693 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12694
12695 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12696
12697 return NULL;
12698}
12699
12700#if USE_POLL
12701# define IOWAIT_SYSCALL "poll"
12702STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12703STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12704static int
12705nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12706{
12708 if (scheduler != Qnil) {
12709 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12710 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12711 return RTEST(args.result);
12712 }
12713
12714 int fd = fptr->fd;
12715 if (fd == -1) return 0;
12716
12717 struct pollfd fds;
12718
12719 fds.fd = fd;
12720 fds.events = events;
12721
12722 int timeout_milliseconds = -1;
12723
12724 if (timeout) {
12725 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12726 }
12727
12728 return poll(&fds, 1, timeout_milliseconds);
12729}
12730#else /* !USE_POLL */
12731# define IOWAIT_SYSCALL "select"
12732static int
12733nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12734{
12736 if (scheduler != Qnil) {
12737 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12738 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12739 return RTEST(args.result);
12740 }
12741
12742 int fd = fptr->fd;
12743
12744 if (fd == -1) {
12745 errno = EBADF;
12746 return -1;
12747 }
12748
12749 rb_fdset_t fds;
12750 int ret;
12751
12752 rb_fd_init(&fds);
12753 rb_fd_set(fd, &fds);
12754
12755 switch (events) {
12756 case RB_WAITFD_IN:
12757 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12758 break;
12759 case RB_WAITFD_OUT:
12760 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12761 break;
12762 default:
12763 VM_UNREACHABLE(nogvl_wait_for);
12764 }
12765
12766 rb_fd_term(&fds);
12767
12768 // On timeout, this returns 0.
12769 return ret;
12770}
12771#endif /* !USE_POLL */
12772
12773static int
12774maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12775{
12776 int ret;
12777
12778 do {
12779 if (has_gvl) {
12781 }
12782 else {
12783 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12784 }
12785 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, 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
12795static int
12796nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12797{
12798 int ret;
12799
12800 do {
12801 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12802 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12803
12804 if (ret < 0) {
12805 stp->syserr = IOWAIT_SYSCALL;
12806 stp->error_no = errno;
12807 return ret;
12808 }
12809 return 0;
12810}
12811
12812#ifdef USE_COPY_FILE_RANGE
12813
12814static ssize_t
12815simple_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)
12816{
12817#ifdef HAVE_COPY_FILE_RANGE
12818 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12819#else
12820 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12821#endif
12822}
12823
12824static int
12825nogvl_copy_file_range(struct copy_stream_struct *stp)
12826{
12827 ssize_t ss;
12828 rb_off_t src_size;
12829 rb_off_t copy_length, src_offset, *src_offset_ptr;
12830
12831 if (!S_ISREG(stp->src_stat.st_mode))
12832 return 0;
12833
12834 src_size = stp->src_stat.st_size;
12835 src_offset = stp->src_offset;
12836 if (src_offset >= (rb_off_t)0) {
12837 src_offset_ptr = &src_offset;
12838 }
12839 else {
12840 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12841 }
12842
12843 copy_length = stp->copy_length;
12844 if (copy_length < (rb_off_t)0) {
12845 if (src_offset < (rb_off_t)0) {
12846 rb_off_t current_offset;
12847 errno = 0;
12848 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12849 if (current_offset < (rb_off_t)0 && errno) {
12850 stp->syserr = "lseek";
12851 stp->error_no = errno;
12852 return (int)current_offset;
12853 }
12854 copy_length = src_size - current_offset;
12855 }
12856 else {
12857 copy_length = src_size - src_offset;
12858 }
12859 }
12860
12861 retry_copy_file_range:
12862# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12863 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12864 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12865# else
12866 ss = (ssize_t)copy_length;
12867# endif
12868 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12869 if (0 < ss) {
12870 stp->total += ss;
12871 copy_length -= ss;
12872 if (0 < copy_length) {
12873 goto retry_copy_file_range;
12874 }
12875 }
12876 if (ss < 0) {
12877 if (maygvl_copy_stream_continue_p(0, stp)) {
12878 goto retry_copy_file_range;
12879 }
12880 switch (errno) {
12881 case EINVAL:
12882 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12883 docker container) */
12884#ifdef ENOSYS
12885 case ENOSYS:
12886#endif
12887#ifdef EXDEV
12888 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12889#endif
12890 return 0;
12891 case EAGAIN:
12892#if EWOULDBLOCK != EAGAIN
12893 case EWOULDBLOCK:
12894#endif
12895 {
12896 int ret = nogvl_copy_stream_wait_write(stp);
12897 if (ret < 0) return ret;
12898 }
12899 goto retry_copy_file_range;
12900 case EBADF:
12901 {
12902 int e = errno;
12903 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12904
12905 if (flags != -1 && flags & O_APPEND) {
12906 return 0;
12907 }
12908 errno = e;
12909 }
12910 }
12911 stp->syserr = "copy_file_range";
12912 stp->error_no = errno;
12913 return (int)ss;
12914 }
12915 return 1;
12916}
12917#endif
12918
12919#ifdef HAVE_FCOPYFILE
12920static int
12921nogvl_fcopyfile(struct copy_stream_struct *stp)
12922{
12923 rb_off_t cur, ss = 0;
12924 const rb_off_t src_offset = stp->src_offset;
12925 int ret;
12926
12927 if (stp->copy_length >= (rb_off_t)0) {
12928 /* copy_length can't be specified in fcopyfile(3) */
12929 return 0;
12930 }
12931
12932 if (!S_ISREG(stp->src_stat.st_mode))
12933 return 0;
12934
12935 if (!S_ISREG(stp->dst_stat.st_mode))
12936 return 0;
12937 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12938 return 0;
12939 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12940 /* fcopyfile(3) appends src IO to dst IO and then truncates
12941 * dst IO to src IO's original size. */
12942 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12943 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12944 if (end > (rb_off_t)0) return 0;
12945 }
12946
12947 if (src_offset > (rb_off_t)0) {
12948 rb_off_t r;
12949
12950 /* get current offset */
12951 errno = 0;
12952 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12953 if (cur < (rb_off_t)0 && errno) {
12954 stp->error_no = errno;
12955 return 1;
12956 }
12957
12958 errno = 0;
12959 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12960 if (r < (rb_off_t)0 && errno) {
12961 stp->error_no = errno;
12962 return 1;
12963 }
12964 }
12965
12966 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12967 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12968 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12969
12970 if (ret == 0) { /* success */
12971 stp->total = ss;
12972 if (src_offset > (rb_off_t)0) {
12973 rb_off_t r;
12974 errno = 0;
12975 /* reset offset */
12976 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12977 if (r < (rb_off_t)0 && errno) {
12978 stp->error_no = errno;
12979 return 1;
12980 }
12981 }
12982 }
12983 else {
12984 switch (errno) {
12985 case ENOTSUP:
12986 case EPERM:
12987 case EINVAL:
12988 return 0;
12989 }
12990 stp->syserr = "fcopyfile";
12991 stp->error_no = errno;
12992 return (int)ret;
12993 }
12994 return 1;
12995}
12996#endif
12997
12998#ifdef HAVE_SENDFILE
12999
13000# ifdef __linux__
13001# define USE_SENDFILE
13002
13003# ifdef HAVE_SYS_SENDFILE_H
13004# include <sys/sendfile.h>
13005# endif
13006
13007static ssize_t
13008simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13009{
13010 return sendfile(out_fd, in_fd, offset, (size_t)count);
13011}
13012
13013# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
13014/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
13015 * without cpuset -l 0.
13016 */
13017# define USE_SENDFILE
13018
13019static ssize_t
13020simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13021{
13022 int r;
13023 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
13024 rb_off_t sbytes;
13025# ifdef __APPLE__
13026 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
13027 sbytes = count;
13028# else
13029 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
13030# endif
13031 if (r != 0 && sbytes == 0) return r;
13032 if (offset) {
13033 *offset += sbytes;
13034 }
13035 else {
13036 lseek(in_fd, sbytes, SEEK_CUR);
13037 }
13038 return (ssize_t)sbytes;
13039}
13040
13041# endif
13042
13043#endif
13044
13045#ifdef USE_SENDFILE
13046static int
13047nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
13048{
13049 ssize_t ss;
13050 rb_off_t src_size;
13051 rb_off_t copy_length;
13052 rb_off_t src_offset;
13053 int use_pread;
13054
13055 if (!S_ISREG(stp->src_stat.st_mode))
13056 return 0;
13057
13058 src_size = stp->src_stat.st_size;
13059#ifndef __linux__
13060 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
13061 return 0;
13062#endif
13063
13064 src_offset = stp->src_offset;
13065 use_pread = src_offset >= (rb_off_t)0;
13066
13067 copy_length = stp->copy_length;
13068 if (copy_length < (rb_off_t)0) {
13069 if (use_pread)
13070 copy_length = src_size - src_offset;
13071 else {
13072 rb_off_t cur;
13073 errno = 0;
13074 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13075 if (cur < (rb_off_t)0 && errno) {
13076 stp->syserr = "lseek";
13077 stp->error_no = errno;
13078 return (int)cur;
13079 }
13080 copy_length = src_size - cur;
13081 }
13082 }
13083
13084 retry_sendfile:
13085# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13086 /* we are limited by the 32-bit ssize_t return value on 32-bit */
13087 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13088# else
13089 ss = (ssize_t)copy_length;
13090# endif
13091 if (use_pread) {
13092 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
13093 }
13094 else {
13095 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
13096 }
13097 if (0 < ss) {
13098 stp->total += ss;
13099 copy_length -= ss;
13100 if (0 < copy_length) {
13101 goto retry_sendfile;
13102 }
13103 }
13104 if (ss < 0) {
13105 if (maygvl_copy_stream_continue_p(0, stp))
13106 goto retry_sendfile;
13107 switch (errno) {
13108 case EINVAL:
13109#ifdef ENOSYS
13110 case ENOSYS:
13111#endif
13112#ifdef EOPNOTSUP
13113 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
13114 see also: [Feature #16965] */
13115 case EOPNOTSUP:
13116#endif
13117 return 0;
13118 case EAGAIN:
13119#if EWOULDBLOCK != EAGAIN
13120 case EWOULDBLOCK:
13121#endif
13122 {
13123 int ret;
13124#ifndef __linux__
13125 /*
13126 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
13127 * select() reports regular files to always be "ready", so
13128 * there is no need to select() on it.
13129 * Other OSes may have the same limitation for sendfile() which
13130 * allow us to bypass maygvl_copy_stream_wait_read()...
13131 */
13132 ret = maygvl_copy_stream_wait_read(0, stp);
13133 if (ret < 0) return ret;
13134#endif
13135 ret = nogvl_copy_stream_wait_write(stp);
13136 if (ret < 0) return ret;
13137 }
13138 goto retry_sendfile;
13139 }
13140 stp->syserr = "sendfile";
13141 stp->error_no = errno;
13142 return (int)ss;
13143 }
13144 return 1;
13145}
13146#endif
13147
13148static ssize_t
13149maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13150{
13151 if (has_gvl)
13152 return rb_io_read_memory(fptr, buf, count);
13153 else
13154 return read(fptr->fd, buf, count);
13155}
13156
13157static ssize_t
13158maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13159{
13160 ssize_t ss;
13161 retry_read:
13162 if (offset < (rb_off_t)0) {
13163 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13164 }
13165 else {
13166 ss = pread(stp->src_fptr->fd, buf, len, offset);
13167 }
13168 if (ss == 0) {
13169 return 0;
13170 }
13171 if (ss < 0) {
13172 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13173 goto retry_read;
13174 switch (errno) {
13175 case EAGAIN:
13176#if EWOULDBLOCK != EAGAIN
13177 case EWOULDBLOCK:
13178#endif
13179 {
13180 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13181 if (ret < 0) return ret;
13182 }
13183 goto retry_read;
13184#ifdef ENOSYS
13185 case ENOSYS:
13186 stp->notimp = "pread";
13187 return ss;
13188#endif
13189 }
13190 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13191 stp->error_no = errno;
13192 }
13193 return ss;
13194}
13195
13196static int
13197nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13198{
13199 ssize_t ss;
13200 int off = 0;
13201 while (len) {
13202 ss = write(stp->dst_fptr->fd, buf+off, len);
13203 if (ss < 0) {
13204 if (maygvl_copy_stream_continue_p(0, stp))
13205 continue;
13206 if (io_again_p(errno)) {
13207 int ret = nogvl_copy_stream_wait_write(stp);
13208 if (ret < 0) return ret;
13209 continue;
13210 }
13211 stp->syserr = "write";
13212 stp->error_no = errno;
13213 return (int)ss;
13214 }
13215 off += (int)ss;
13216 len -= (int)ss;
13217 stp->total += ss;
13218 }
13219 return 0;
13220}
13221
13222static void
13223nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13224{
13225 char buf[1024*16];
13226 size_t len;
13227 ssize_t ss;
13228 int ret;
13229 rb_off_t copy_length;
13230 rb_off_t src_offset;
13231 int use_eof;
13232 int use_pread;
13233
13234 copy_length = stp->copy_length;
13235 use_eof = copy_length < (rb_off_t)0;
13236 src_offset = stp->src_offset;
13237 use_pread = src_offset >= (rb_off_t)0;
13238
13239 if (use_pread && stp->close_src) {
13240 rb_off_t r;
13241 errno = 0;
13242 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13243 if (r < (rb_off_t)0 && errno) {
13244 stp->syserr = "lseek";
13245 stp->error_no = errno;
13246 return;
13247 }
13248 src_offset = (rb_off_t)-1;
13249 use_pread = 0;
13250 }
13251
13252 while (use_eof || 0 < copy_length) {
13253 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13254 len = (size_t)copy_length;
13255 }
13256 else {
13257 len = sizeof(buf);
13258 }
13259 if (use_pread) {
13260 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13261 if (0 < ss)
13262 src_offset += ss;
13263 }
13264 else {
13265 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13266 }
13267 if (ss <= 0) /* EOF or error */
13268 return;
13269
13270 ret = nogvl_copy_stream_write(stp, buf, ss);
13271 if (ret < 0)
13272 return;
13273
13274 if (!use_eof)
13275 copy_length -= ss;
13276 }
13277}
13278
13279static void *
13280nogvl_copy_stream_func(void *arg)
13281{
13282 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13283#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13284 int ret;
13285#endif
13286
13287#ifdef USE_COPY_FILE_RANGE
13288 ret = nogvl_copy_file_range(stp);
13289 if (ret != 0)
13290 goto finish; /* error or success */
13291#endif
13292
13293#ifdef HAVE_FCOPYFILE
13294 ret = nogvl_fcopyfile(stp);
13295 if (ret != 0)
13296 goto finish; /* error or success */
13297#endif
13298
13299#ifdef USE_SENDFILE
13300 ret = nogvl_copy_stream_sendfile(stp);
13301 if (ret != 0)
13302 goto finish; /* error or success */
13303#endif
13304
13305 nogvl_copy_stream_read_write(stp);
13306
13307#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13308 finish:
13309#endif
13310 return 0;
13311}
13312
13313static VALUE
13314copy_stream_fallback_body(VALUE arg)
13315{
13316 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13317 const int buflen = 16*1024;
13318 VALUE n;
13319 VALUE buf = rb_str_buf_new(buflen);
13320 rb_off_t rest = stp->copy_length;
13321 rb_off_t off = stp->src_offset;
13322 ID read_method = id_readpartial;
13323
13324 if (!stp->src_fptr) {
13325 if (!rb_respond_to(stp->src, read_method)) {
13326 read_method = id_read;
13327 }
13328 }
13329
13330 while (1) {
13331 long numwrote;
13332 long l;
13333 rb_str_make_independent(buf);
13334 if (stp->copy_length < (rb_off_t)0) {
13335 l = buflen;
13336 }
13337 else {
13338 if (rest == 0) {
13339 rb_str_resize(buf, 0);
13340 break;
13341 }
13342 l = buflen < rest ? buflen : (long)rest;
13343 }
13344 if (!stp->src_fptr) {
13345 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13346
13347 if (read_method == id_read && NIL_P(rc))
13348 break;
13349 }
13350 else {
13351 ssize_t ss;
13352 rb_str_resize(buf, buflen);
13353 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13354 rb_str_resize(buf, ss > 0 ? ss : 0);
13355 if (ss < 0)
13356 return Qnil;
13357 if (ss == 0)
13358 rb_eof_error();
13359 if (off >= (rb_off_t)0)
13360 off += ss;
13361 }
13362 n = rb_io_write(stp->dst, buf);
13363 numwrote = NUM2LONG(n);
13364 stp->total += numwrote;
13365 rest -= numwrote;
13366 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13367 break;
13368 }
13369 }
13370
13371 return Qnil;
13372}
13373
13374static VALUE
13375copy_stream_fallback(struct copy_stream_struct *stp)
13376{
13377 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13378 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13379 }
13380 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13381 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13382 rb_eEOFError, (VALUE)0);
13383 return Qnil;
13384}
13385
13386static VALUE
13387copy_stream_body(VALUE arg)
13388{
13389 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13390 VALUE src_io = stp->src, dst_io = stp->dst;
13391 const int common_oflags = 0
13392#ifdef O_NOCTTY
13393 | O_NOCTTY
13394#endif
13395 ;
13396
13397 stp->th = rb_thread_current();
13398
13399 stp->total = 0;
13400
13401 if (src_io == argf ||
13402 !(RB_TYPE_P(src_io, T_FILE) ||
13403 RB_TYPE_P(src_io, T_STRING) ||
13404 rb_respond_to(src_io, rb_intern("to_path")))) {
13405 stp->src_fptr = NULL;
13406 }
13407 else {
13408 int stat_ret;
13409 VALUE tmp_io = rb_io_check_io(src_io);
13410 if (!NIL_P(tmp_io)) {
13411 src_io = tmp_io;
13412 }
13413 else if (!RB_TYPE_P(src_io, T_FILE)) {
13414 VALUE args[2];
13415 FilePathValue(src_io);
13416 args[0] = src_io;
13417 args[1] = INT2NUM(O_RDONLY|common_oflags);
13418 src_io = rb_class_new_instance(2, args, rb_cFile);
13419 stp->src = src_io;
13420 stp->close_src = 1;
13421 }
13422 RB_IO_POINTER(src_io, stp->src_fptr);
13423 rb_io_check_byte_readable(stp->src_fptr);
13424
13425 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13426 if (stat_ret < 0) {
13427 stp->syserr = "fstat";
13428 stp->error_no = errno;
13429 return Qnil;
13430 }
13431 }
13432
13433 if (dst_io == argf ||
13434 !(RB_TYPE_P(dst_io, T_FILE) ||
13435 RB_TYPE_P(dst_io, T_STRING) ||
13436 rb_respond_to(dst_io, rb_intern("to_path")))) {
13437 stp->dst_fptr = NULL;
13438 }
13439 else {
13440 int stat_ret;
13441 VALUE tmp_io = rb_io_check_io(dst_io);
13442 if (!NIL_P(tmp_io)) {
13443 dst_io = GetWriteIO(tmp_io);
13444 }
13445 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13446 VALUE args[3];
13447 FilePathValue(dst_io);
13448 args[0] = dst_io;
13449 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13450 args[2] = INT2FIX(0666);
13451 dst_io = rb_class_new_instance(3, args, rb_cFile);
13452 stp->dst = dst_io;
13453 stp->close_dst = 1;
13454 }
13455 else {
13456 dst_io = GetWriteIO(dst_io);
13457 stp->dst = dst_io;
13458 }
13459 RB_IO_POINTER(dst_io, stp->dst_fptr);
13460 rb_io_check_writable(stp->dst_fptr);
13461
13462 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13463 if (stat_ret < 0) {
13464 stp->syserr = "fstat";
13465 stp->error_no = errno;
13466 return Qnil;
13467 }
13468 }
13469
13470#ifdef O_BINARY
13471 if (stp->src_fptr)
13472 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13473#endif
13474 if (stp->dst_fptr)
13475 io_ascii8bit_binmode(stp->dst_fptr);
13476
13477 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13478 size_t len = stp->src_fptr->rbuf.len;
13479 VALUE str;
13480 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13481 len = (size_t)stp->copy_length;
13482 }
13483 str = rb_str_buf_new(len);
13484 rb_str_resize(str,len);
13485 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13486 if (stp->dst_fptr) { /* IO or filename */
13487 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13488 rb_sys_fail_on_write(stp->dst_fptr);
13489 }
13490 else /* others such as StringIO */
13491 rb_io_write(dst_io, str);
13492 rb_str_resize(str, 0);
13493 stp->total += len;
13494 if (stp->copy_length >= (rb_off_t)0)
13495 stp->copy_length -= len;
13496 }
13497
13498 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13499 rb_raise(rb_eIOError, "flush failed");
13500 }
13501
13502 if (stp->copy_length == 0)
13503 return Qnil;
13504
13505 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13506 return copy_stream_fallback(stp);
13507 }
13508
13509 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13510 return Qnil;
13511}
13512
13513static VALUE
13514copy_stream_finalize(VALUE arg)
13515{
13516 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13517
13518#ifdef HAVE_FCOPYFILE
13519 if (stp->copyfile_state) {
13520 copyfile_state_free(stp->copyfile_state);
13521 }
13522#endif
13523
13524 if (stp->close_src) {
13525 rb_io_close_m(stp->src);
13526 }
13527 if (stp->close_dst) {
13528 rb_io_close_m(stp->dst);
13529 }
13530 if (stp->syserr) {
13531 rb_syserr_fail(stp->error_no, stp->syserr);
13532 }
13533 if (stp->notimp) {
13534 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13535 }
13536 return Qnil;
13537}
13538
13539/*
13540 * call-seq:
13541 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13542 *
13543 * Copies from the given +src+ to the given +dst+,
13544 * returning the number of bytes copied.
13545 *
13546 * - The given +src+ must be one of the following:
13547 *
13548 * - The path to a readable file, from which source data is to be read.
13549 * - An \IO-like object, opened for reading and capable of responding
13550 * to method +:readpartial+ or method +:read+.
13551 *
13552 * - The given +dst+ must be one of the following:
13553 *
13554 * - The path to a writable file, to which data is to be written.
13555 * - An \IO-like object, opened for writing and capable of responding
13556 * to method +:write+.
13557 *
13558 * The examples here use file <tt>t.txt</tt> as source:
13559 *
13560 * File.read('t.txt')
13561 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13562 * File.read('t.txt').size # => 47
13563 *
13564 * If only arguments +src+ and +dst+ are given,
13565 * the entire source stream is copied:
13566 *
13567 * # Paths.
13568 * IO.copy_stream('t.txt', 't.tmp') # => 47
13569 *
13570 * # IOs (recall that a File is also an IO).
13571 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13572 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13573 * IO.copy_stream(src_io, dst_io) # => 47
13574 * src_io.close
13575 * dst_io.close
13576 *
13577 * With argument +src_length+ a non-negative integer,
13578 * no more than that many bytes are copied:
13579 *
13580 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13581 * File.read('t.tmp') # => "First line"
13582 *
13583 * With argument +src_offset+ also given,
13584 * the source stream is read beginning at that offset:
13585 *
13586 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13587 * IO.read('t.tmp') # => "Second line"
13588 *
13589 */
13590static VALUE
13591rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13592{
13593 VALUE src, dst, length, src_offset;
13594 struct copy_stream_struct st;
13595
13596 MEMZERO(&st, struct copy_stream_struct, 1);
13597
13598 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13599
13600 st.src = src;
13601 st.dst = dst;
13602
13603 st.src_fptr = NULL;
13604 st.dst_fptr = NULL;
13605
13606 if (NIL_P(length))
13607 st.copy_length = (rb_off_t)-1;
13608 else
13609 st.copy_length = NUM2OFFT(length);
13610
13611 if (NIL_P(src_offset))
13612 st.src_offset = (rb_off_t)-1;
13613 else
13614 st.src_offset = NUM2OFFT(src_offset);
13615
13616 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13617
13618 return OFFT2NUM(st.total);
13619}
13620
13621/*
13622 * call-seq:
13623 * external_encoding -> encoding or nil
13624 *
13625 * Returns the Encoding object that represents the encoding of the stream,
13626 * or +nil+ if the stream is in write mode and no encoding is specified.
13627 *
13628 * See {Encodings}[rdoc-ref:File@Encodings].
13629 *
13630 */
13631
13632static VALUE
13633rb_io_external_encoding(VALUE io)
13634{
13635 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13636
13637 if (fptr->encs.enc2) {
13638 return rb_enc_from_encoding(fptr->encs.enc2);
13639 }
13640 if (fptr->mode & FMODE_WRITABLE) {
13641 if (fptr->encs.enc)
13642 return rb_enc_from_encoding(fptr->encs.enc);
13643 return Qnil;
13644 }
13645 return rb_enc_from_encoding(io_read_encoding(fptr));
13646}
13647
13648/*
13649 * call-seq:
13650 * internal_encoding -> encoding or nil
13651 *
13652 * Returns the Encoding object that represents the encoding of the internal string,
13653 * if conversion is specified,
13654 * or +nil+ otherwise.
13655 *
13656 * See {Encodings}[rdoc-ref:File@Encodings].
13657 *
13658 */
13659
13660static VALUE
13661rb_io_internal_encoding(VALUE io)
13662{
13663 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13664
13665 if (!fptr->encs.enc2) return Qnil;
13666 return rb_enc_from_encoding(io_read_encoding(fptr));
13667}
13668
13669/*
13670 * call-seq:
13671 * set_encoding(ext_enc) -> self
13672 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13673 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13674 *
13675 * See {Encodings}[rdoc-ref:File@Encodings].
13676 *
13677 * Argument +ext_enc+, if given, must be an Encoding object
13678 * or a String with the encoding name;
13679 * it is assigned as the encoding for the stream.
13680 *
13681 * Argument +int_enc+, if given, must be an Encoding object
13682 * or a String with the encoding name;
13683 * it is assigned as the encoding for the internal string.
13684 *
13685 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13686 * containing two colon-separated encoding names;
13687 * corresponding Encoding objects are assigned as the external
13688 * and internal encodings for the stream.
13689 *
13690 * If the external encoding of a string is binary/ASCII-8BIT,
13691 * the internal encoding of the string is set to nil, since no
13692 * transcoding is needed.
13693 *
13694 * Optional keyword arguments +enc_opts+ specify
13695 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13696 *
13697 */
13698
13699static VALUE
13700rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13701{
13702 rb_io_t *fptr;
13703 VALUE v1, v2, opt;
13704
13705 if (!RB_TYPE_P(io, T_FILE)) {
13706 return forward(io, id_set_encoding, argc, argv);
13707 }
13708
13709 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13710 GetOpenFile(io, fptr);
13711 io_encoding_set(fptr, v1, v2, opt);
13712 return io;
13713}
13714
13715void
13716rb_stdio_set_default_encoding(void)
13717{
13718 VALUE val = Qnil;
13719
13720#ifdef _WIN32
13721 if (isatty(fileno(stdin))) {
13722 rb_encoding *external = rb_locale_encoding();
13723 rb_encoding *internal = rb_default_internal_encoding();
13724 if (!internal) internal = rb_default_external_encoding();
13725 io_encoding_set(RFILE(rb_stdin)->fptr,
13726 rb_enc_from_encoding(external),
13727 rb_enc_from_encoding(internal),
13728 Qnil);
13729 }
13730 else
13731#endif
13732 rb_io_set_encoding(1, &val, rb_stdin);
13733 rb_io_set_encoding(1, &val, rb_stdout);
13734 rb_io_set_encoding(1, &val, rb_stderr);
13735}
13736
13737static inline int
13738global_argf_p(VALUE arg)
13739{
13740 return arg == argf;
13741}
13742
13743typedef VALUE (*argf_encoding_func)(VALUE io);
13744
13745static VALUE
13746argf_encoding(VALUE argf, argf_encoding_func func)
13747{
13748 if (!RTEST(ARGF.current_file)) {
13749 return rb_enc_default_external();
13750 }
13751 return func(rb_io_check_io(ARGF.current_file));
13752}
13753
13754/*
13755 * call-seq:
13756 * ARGF.external_encoding -> encoding
13757 *
13758 * Returns the external encoding for files read from ARGF as an Encoding
13759 * object. The external encoding is the encoding of the text as stored in a
13760 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13761 * represent this text within Ruby.
13762 *
13763 * To set the external encoding use ARGF.set_encoding.
13764 *
13765 * For example:
13766 *
13767 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13768 *
13769 */
13770static VALUE
13771argf_external_encoding(VALUE argf)
13772{
13773 return argf_encoding(argf, rb_io_external_encoding);
13774}
13775
13776/*
13777 * call-seq:
13778 * ARGF.internal_encoding -> encoding
13779 *
13780 * Returns the internal encoding for strings read from ARGF as an
13781 * Encoding object.
13782 *
13783 * If ARGF.set_encoding has been called with two encoding names, the second
13784 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13785 * value is returned. Failing that, if a default external encoding was
13786 * specified on the command-line, that value is used. If the encoding is
13787 * unknown, +nil+ is returned.
13788 */
13789static VALUE
13790argf_internal_encoding(VALUE argf)
13791{
13792 return argf_encoding(argf, rb_io_internal_encoding);
13793}
13794
13795/*
13796 * call-seq:
13797 * ARGF.set_encoding(ext_enc) -> ARGF
13798 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13799 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13800 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13801 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13802 *
13803 * If single argument is specified, strings read from ARGF are tagged with
13804 * the encoding specified.
13805 *
13806 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13807 * the read string is converted from the first encoding (external encoding)
13808 * to the second encoding (internal encoding), then tagged with the second
13809 * encoding.
13810 *
13811 * If two arguments are specified, they must be encoding objects or encoding
13812 * names. Again, the first specifies the external encoding; the second
13813 * specifies the internal encoding.
13814 *
13815 * If the external encoding and the internal encoding are specified, the
13816 * optional Hash argument can be used to adjust the conversion process. The
13817 * structure of this hash is explained in the String#encode documentation.
13818 *
13819 * For example:
13820 *
13821 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13822 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13823 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13824 * # to UTF-8.
13825 */
13826static VALUE
13827argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13828{
13829 rb_io_t *fptr;
13830
13831 if (!next_argv()) {
13832 rb_raise(rb_eArgError, "no stream to set encoding");
13833 }
13834 rb_io_set_encoding(argc, argv, ARGF.current_file);
13835 GetOpenFile(ARGF.current_file, fptr);
13836 ARGF.encs = fptr->encs;
13837 RB_OBJ_WRITTEN(argf, Qundef, ARGF.encs.ecopts);
13838 return argf;
13839}
13840
13841/*
13842 * call-seq:
13843 * ARGF.tell -> Integer
13844 * ARGF.pos -> Integer
13845 *
13846 * Returns the current offset (in bytes) of the current file in ARGF.
13847 *
13848 * ARGF.pos #=> 0
13849 * ARGF.gets #=> "This is line one\n"
13850 * ARGF.pos #=> 17
13851 *
13852 */
13853static VALUE
13854argf_tell(VALUE argf)
13855{
13856 if (!next_argv()) {
13857 rb_raise(rb_eArgError, "no stream to tell");
13858 }
13859 ARGF_FORWARD(0, 0);
13860 return rb_io_tell(ARGF.current_file);
13861}
13862
13863/*
13864 * call-seq:
13865 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13866 *
13867 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13868 * the value of _whence_. See IO#seek for further details.
13869 */
13870static VALUE
13871argf_seek_m(int argc, VALUE *argv, VALUE argf)
13872{
13873 if (!next_argv()) {
13874 rb_raise(rb_eArgError, "no stream to seek");
13875 }
13876 ARGF_FORWARD(argc, argv);
13877 return rb_io_seek_m(argc, argv, ARGF.current_file);
13878}
13879
13880/*
13881 * call-seq:
13882 * ARGF.pos = position -> Integer
13883 *
13884 * Seeks to the position given by _position_ (in bytes) in ARGF.
13885 *
13886 * For example:
13887 *
13888 * ARGF.pos = 17
13889 * ARGF.gets #=> "This is line two\n"
13890 */
13891static VALUE
13892argf_set_pos(VALUE argf, VALUE offset)
13893{
13894 if (!next_argv()) {
13895 rb_raise(rb_eArgError, "no stream to set position");
13896 }
13897 ARGF_FORWARD(1, &offset);
13898 return rb_io_set_pos(ARGF.current_file, offset);
13899}
13900
13901/*
13902 * call-seq:
13903 * ARGF.rewind -> 0
13904 *
13905 * Positions the current file to the beginning of input, resetting
13906 * ARGF.lineno to zero.
13907 *
13908 * ARGF.readline #=> "This is line one\n"
13909 * ARGF.rewind #=> 0
13910 * ARGF.lineno #=> 0
13911 * ARGF.readline #=> "This is line one\n"
13912 */
13913static VALUE
13914argf_rewind(VALUE argf)
13915{
13916 VALUE ret;
13917 int old_lineno;
13918
13919 if (!next_argv()) {
13920 rb_raise(rb_eArgError, "no stream to rewind");
13921 }
13922 ARGF_FORWARD(0, 0);
13923 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13924 ret = rb_io_rewind(ARGF.current_file);
13925 if (!global_argf_p(argf)) {
13926 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13927 }
13928 return ret;
13929}
13930
13931/*
13932 * call-seq:
13933 * ARGF.fileno -> integer
13934 * ARGF.to_i -> integer
13935 *
13936 * Returns an integer representing the numeric file descriptor for
13937 * the current file. Raises an ArgumentError if there isn't a current file.
13938 *
13939 * ARGF.fileno #=> 3
13940 */
13941static VALUE
13942argf_fileno(VALUE argf)
13943{
13944 if (!next_argv()) {
13945 rb_raise(rb_eArgError, "no stream");
13946 }
13947 ARGF_FORWARD(0, 0);
13948 return rb_io_fileno(ARGF.current_file);
13949}
13950
13951/*
13952 * call-seq:
13953 * ARGF.to_io -> IO
13954 *
13955 * Returns an IO object representing the current file. This will be a
13956 * File object unless the current file is a stream such as STDIN.
13957 *
13958 * For example:
13959 *
13960 * ARGF.to_io #=> #<File:glark.txt>
13961 * ARGF.to_io #=> #<IO:<STDIN>>
13962 */
13963static VALUE
13964argf_to_io(VALUE argf)
13965{
13966 next_argv();
13967 ARGF_FORWARD(0, 0);
13968 return ARGF.current_file;
13969}
13970
13971/*
13972 * call-seq:
13973 * ARGF.eof? -> true or false
13974 * ARGF.eof -> true or false
13975 *
13976 * Returns true if the current file in ARGF is at end of file, i.e. it has
13977 * no data to read. The stream must be opened for reading or an IOError
13978 * will be raised.
13979 *
13980 * $ echo "eof" | ruby argf.rb
13981 *
13982 * ARGF.eof? #=> false
13983 * 3.times { ARGF.readchar }
13984 * ARGF.eof? #=> false
13985 * ARGF.readchar #=> "\n"
13986 * ARGF.eof? #=> true
13987 */
13988
13989static VALUE
13990argf_eof(VALUE argf)
13991{
13992 next_argv();
13993 if (RTEST(ARGF.current_file)) {
13994 if (ARGF.init_p == 0) return Qtrue;
13995 next_argv();
13996 ARGF_FORWARD(0, 0);
13997 if (rb_io_eof(ARGF.current_file)) {
13998 return Qtrue;
13999 }
14000 }
14001 return Qfalse;
14002}
14003
14004/*
14005 * call-seq:
14006 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
14007 *
14008 * Reads _length_ bytes from ARGF. The files named on the command line
14009 * are concatenated and treated as a single file by this method, so when
14010 * called without arguments the contents of this pseudo file are returned in
14011 * their entirety.
14012 *
14013 * _length_ must be a non-negative integer or +nil+.
14014 *
14015 * If _length_ is a positive integer, +read+ tries to read
14016 * _length_ bytes without any conversion (binary mode).
14017 * It returns +nil+ if an EOF is encountered before anything can be read.
14018 * Fewer than _length_ bytes are returned if an EOF is encountered during
14019 * the read.
14020 * In the case of an integer _length_, the resulting string is always
14021 * in ASCII-8BIT encoding.
14022 *
14023 * If _length_ is omitted or is +nil+, it reads until EOF
14024 * and the encoding conversion is applied, if applicable.
14025 * A string is returned even if EOF is encountered before any data is read.
14026 *
14027 * If _length_ is zero, it returns an empty string (<code>""</code>).
14028 *
14029 * If the optional _outbuf_ argument is present,
14030 * it must reference a String, which will receive the data.
14031 * The _outbuf_ will contain only the received data after the method call
14032 * even if it is not empty at the beginning.
14033 *
14034 * For example:
14035 *
14036 * $ echo "small" > small.txt
14037 * $ echo "large" > large.txt
14038 * $ ./glark.rb small.txt large.txt
14039 *
14040 * ARGF.read #=> "small\nlarge"
14041 * ARGF.read(200) #=> "small\nlarge"
14042 * ARGF.read(2) #=> "sm"
14043 * ARGF.read(0) #=> ""
14044 *
14045 * Note that this method behaves like the fread() function in C.
14046 * This means it retries to invoke read(2) system calls to read data
14047 * with the specified length.
14048 * If you need the behavior like a single read(2) system call,
14049 * consider ARGF#readpartial or ARGF#read_nonblock.
14050 */
14051
14052static VALUE
14053argf_read(int argc, VALUE *argv, VALUE argf)
14054{
14055 VALUE tmp, str, length;
14056 long len = 0;
14057
14058 rb_scan_args(argc, argv, "02", &length, &str);
14059 if (!NIL_P(length)) {
14060 len = NUM2LONG(argv[0]);
14061 }
14062 if (!NIL_P(str)) {
14063 StringValue(str);
14064 rb_str_resize(str,0);
14065 argv[1] = Qnil;
14066 }
14067
14068 retry:
14069 if (!next_argv()) {
14070 return str;
14071 }
14072 if (ARGF_GENERIC_INPUT_P()) {
14073 tmp = argf_forward(argc, argv, argf);
14074 }
14075 else {
14076 tmp = io_read(argc, argv, ARGF.current_file);
14077 }
14078 if (NIL_P(str)) str = tmp;
14079 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
14080 if (NIL_P(tmp) || NIL_P(length)) {
14081 if (ARGF.next_p != -1) {
14082 argf_close(argf);
14083 ARGF.next_p = 1;
14084 goto retry;
14085 }
14086 }
14087 else if (argc >= 1) {
14088 long slen = RSTRING_LEN(str);
14089 if (slen < len) {
14090 argv[0] = LONG2NUM(len - slen);
14091 goto retry;
14092 }
14093 }
14094 return str;
14095}
14096
14098 int argc;
14099 VALUE *argv;
14100 VALUE argf;
14101};
14102
14103static VALUE
14104argf_forward_call(VALUE arg)
14105{
14106 struct argf_call_arg *p = (struct argf_call_arg *)arg;
14107 argf_forward(p->argc, p->argv, p->argf);
14108 return Qnil;
14109}
14110
14111static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
14112 int nonblock);
14113
14114/*
14115 * call-seq:
14116 * ARGF.readpartial(maxlen) -> string
14117 * ARGF.readpartial(maxlen, outbuf) -> outbuf
14118 *
14119 * Reads at most _maxlen_ bytes from the ARGF stream.
14120 *
14121 * If the optional _outbuf_ argument is present,
14122 * it must reference a String, which will receive the data.
14123 * The _outbuf_ will contain only the received data after the method call
14124 * even if it is not empty at the beginning.
14125 *
14126 * It raises EOFError on end of ARGF stream.
14127 * Since ARGF stream is a concatenation of multiple files,
14128 * internally EOF is occur for each file.
14129 * ARGF.readpartial returns empty strings for EOFs except the last one and
14130 * raises EOFError for the last one.
14131 *
14132 */
14133
14134static VALUE
14135argf_readpartial(int argc, VALUE *argv, VALUE argf)
14136{
14137 return argf_getpartial(argc, argv, argf, Qnil, 0);
14138}
14139
14140/*
14141 * call-seq:
14142 * ARGF.read_nonblock(maxlen[, options]) -> string
14143 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14144 *
14145 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14146 */
14147
14148static VALUE
14149argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14150{
14151 VALUE opts;
14152
14153 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14154
14155 if (!NIL_P(opts))
14156 argc--;
14157
14158 return argf_getpartial(argc, argv, argf, opts, 1);
14159}
14160
14161static VALUE
14162argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14163{
14164 VALUE tmp, str, length;
14165 int no_exception;
14166
14167 rb_scan_args(argc, argv, "11", &length, &str);
14168 if (!NIL_P(str)) {
14169 StringValue(str);
14170 argv[1] = str;
14171 }
14172 no_exception = no_exception_p(opts);
14173
14174 if (!next_argv()) {
14175 if (!NIL_P(str)) {
14176 rb_str_resize(str, 0);
14177 }
14178 rb_eof_error();
14179 }
14180 if (ARGF_GENERIC_INPUT_P()) {
14181 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14182 struct argf_call_arg arg;
14183 arg.argc = argc;
14184 arg.argv = argv;
14185 arg.argf = argf;
14186 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14187 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14188 }
14189 else {
14190 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14191 }
14192 if (NIL_P(tmp)) {
14193 if (ARGF.next_p == -1) {
14194 return io_nonblock_eof(no_exception);
14195 }
14196 argf_close(argf);
14197 ARGF.next_p = 1;
14198 if (RARRAY_LEN(ARGF.argv) == 0) {
14199 return io_nonblock_eof(no_exception);
14200 }
14201 if (NIL_P(str))
14202 str = rb_str_new(NULL, 0);
14203 return str;
14204 }
14205 return tmp;
14206}
14207
14208/*
14209 * call-seq:
14210 * ARGF.getc -> String or nil
14211 *
14212 * Reads the next character from ARGF and returns it as a String. Returns
14213 * +nil+ at the end of the stream.
14214 *
14215 * ARGF treats the files named on the command line as a single file created
14216 * by concatenating their contents. After returning the last character of the
14217 * first file, it returns the first character of the second file, and so on.
14218 *
14219 * For example:
14220 *
14221 * $ echo "foo" > file
14222 * $ ruby argf.rb file
14223 *
14224 * ARGF.getc #=> "f"
14225 * ARGF.getc #=> "o"
14226 * ARGF.getc #=> "o"
14227 * ARGF.getc #=> "\n"
14228 * ARGF.getc #=> nil
14229 * ARGF.getc #=> nil
14230 */
14231static VALUE
14232argf_getc(VALUE argf)
14233{
14234 VALUE ch;
14235
14236 retry:
14237 if (!next_argv()) return Qnil;
14238 if (ARGF_GENERIC_INPUT_P()) {
14239 ch = forward_current(rb_intern("getc"), 0, 0);
14240 }
14241 else {
14242 ch = rb_io_getc(ARGF.current_file);
14243 }
14244 if (NIL_P(ch) && ARGF.next_p != -1) {
14245 argf_close(argf);
14246 ARGF.next_p = 1;
14247 goto retry;
14248 }
14249
14250 return ch;
14251}
14252
14253/*
14254 * call-seq:
14255 * ARGF.getbyte -> Integer or nil
14256 *
14257 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14258 * the end of the stream.
14259 *
14260 * For example:
14261 *
14262 * $ echo "foo" > file
14263 * $ ruby argf.rb file
14264 *
14265 * ARGF.getbyte #=> 102
14266 * ARGF.getbyte #=> 111
14267 * ARGF.getbyte #=> 111
14268 * ARGF.getbyte #=> 10
14269 * ARGF.getbyte #=> nil
14270 */
14271static VALUE
14272argf_getbyte(VALUE argf)
14273{
14274 VALUE ch;
14275
14276 retry:
14277 if (!next_argv()) return Qnil;
14278 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14279 ch = forward_current(rb_intern("getbyte"), 0, 0);
14280 }
14281 else {
14282 ch = rb_io_getbyte(ARGF.current_file);
14283 }
14284 if (NIL_P(ch) && ARGF.next_p != -1) {
14285 argf_close(argf);
14286 ARGF.next_p = 1;
14287 goto retry;
14288 }
14289
14290 return ch;
14291}
14292
14293/*
14294 * call-seq:
14295 * ARGF.readchar -> String or nil
14296 *
14297 * Reads the next character from ARGF and returns it as a String. Raises
14298 * an EOFError after the last character of the last file has been read.
14299 *
14300 * For example:
14301 *
14302 * $ echo "foo" > file
14303 * $ ruby argf.rb file
14304 *
14305 * ARGF.readchar #=> "f"
14306 * ARGF.readchar #=> "o"
14307 * ARGF.readchar #=> "o"
14308 * ARGF.readchar #=> "\n"
14309 * ARGF.readchar #=> end of file reached (EOFError)
14310 */
14311static VALUE
14312argf_readchar(VALUE argf)
14313{
14314 VALUE ch;
14315
14316 retry:
14317 if (!next_argv()) rb_eof_error();
14318 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14319 ch = forward_current(rb_intern("getc"), 0, 0);
14320 }
14321 else {
14322 ch = rb_io_getc(ARGF.current_file);
14323 }
14324 if (NIL_P(ch) && ARGF.next_p != -1) {
14325 argf_close(argf);
14326 ARGF.next_p = 1;
14327 goto retry;
14328 }
14329
14330 return ch;
14331}
14332
14333/*
14334 * call-seq:
14335 * ARGF.readbyte -> Integer
14336 *
14337 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14338 * an EOFError after the last byte of the last file has been read.
14339 *
14340 * For example:
14341 *
14342 * $ echo "foo" > file
14343 * $ ruby argf.rb file
14344 *
14345 * ARGF.readbyte #=> 102
14346 * ARGF.readbyte #=> 111
14347 * ARGF.readbyte #=> 111
14348 * ARGF.readbyte #=> 10
14349 * ARGF.readbyte #=> end of file reached (EOFError)
14350 */
14351static VALUE
14352argf_readbyte(VALUE argf)
14353{
14354 VALUE c;
14355
14356 NEXT_ARGF_FORWARD(0, 0);
14357 c = argf_getbyte(argf);
14358 if (NIL_P(c)) {
14359 rb_eof_error();
14360 }
14361 return c;
14362}
14363
14364#define FOREACH_ARGF() while (next_argv())
14365
14366static VALUE
14367argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14368{
14369 const VALUE current = ARGF.current_file;
14370 rb_yield_values2(argc, argv);
14371 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14373 }
14374 return Qnil;
14375}
14376
14377#define ARGF_block_call(mid, argc, argv, func, argf) \
14378 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14379 func, argf, rb_keyword_given_p())
14380
14381static void
14382argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14383{
14384 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14385 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14386}
14387
14388static VALUE
14389argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14390{
14391 if (!global_argf_p(argf)) {
14392 ARGF.last_lineno = ++ARGF.lineno;
14393 }
14394 return argf_block_call_i(i, argf, argc, argv, blockarg);
14395}
14396
14397static void
14398argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14399{
14400 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14401 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14402}
14403
14404/*
14405 * call-seq:
14406 * ARGF.each(sep=$/) {|line| block } -> ARGF
14407 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14408 * ARGF.each(...) -> an_enumerator
14409 *
14410 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14411 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14412 * ARGF.each_line(...) -> an_enumerator
14413 *
14414 * Returns an enumerator which iterates over each line (separated by _sep_,
14415 * which defaults to your platform's newline character) of each file in
14416 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14417 * block, otherwise an enumerator is returned.
14418 * The optional _limit_ argument is an Integer specifying the maximum
14419 * length of each line; longer lines will be split according to this limit.
14420 *
14421 * This method allows you to treat the files supplied on the command line as
14422 * a single file consisting of the concatenation of each named file. After
14423 * the last line of the first file has been returned, the first line of the
14424 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14425 * used to determine the filename of the current line and line number of the
14426 * whole input, respectively.
14427 *
14428 * For example, the following code prints out each line of each named file
14429 * prefixed with its line number, displaying the filename once per file:
14430 *
14431 * ARGF.each_line do |line|
14432 * puts ARGF.filename if ARGF.file.lineno == 1
14433 * puts "#{ARGF.file.lineno}: #{line}"
14434 * end
14435 *
14436 * While the following code prints only the first file's name at first, and
14437 * the contents with line number counted through all named files.
14438 *
14439 * ARGF.each_line do |line|
14440 * puts ARGF.filename if ARGF.lineno == 1
14441 * puts "#{ARGF.lineno}: #{line}"
14442 * end
14443 */
14444static VALUE
14445argf_each_line(int argc, VALUE *argv, VALUE argf)
14446{
14447 RETURN_ENUMERATOR(argf, argc, argv);
14448 FOREACH_ARGF() {
14449 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14450 }
14451 return argf;
14452}
14453
14454/*
14455 * call-seq:
14456 * ARGF.each_byte {|byte| block } -> ARGF
14457 * ARGF.each_byte -> an_enumerator
14458 *
14459 * Iterates over each byte of each file in +ARGV+.
14460 * A byte is returned as an Integer in the range 0..255.
14461 *
14462 * This method allows you to treat the files supplied on the command line as
14463 * a single file consisting of the concatenation of each named file. After
14464 * the last byte of the first file has been returned, the first byte of the
14465 * second file is returned. The ARGF.filename method can be used to
14466 * determine the filename of the current byte.
14467 *
14468 * If no block is given, an enumerator is returned instead.
14469 *
14470 * For example:
14471 *
14472 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14473 *
14474 */
14475static VALUE
14476argf_each_byte(VALUE argf)
14477{
14478 RETURN_ENUMERATOR(argf, 0, 0);
14479 FOREACH_ARGF() {
14480 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14481 }
14482 return argf;
14483}
14484
14485/*
14486 * call-seq:
14487 * ARGF.each_char {|char| block } -> ARGF
14488 * ARGF.each_char -> an_enumerator
14489 *
14490 * Iterates over each character of each file in ARGF.
14491 *
14492 * This method allows you to treat the files supplied on the command line as
14493 * a single file consisting of the concatenation of each named file. After
14494 * the last character of the first file has been returned, the first
14495 * character of the second file is returned. The ARGF.filename method can
14496 * be used to determine the name of the file in which the current character
14497 * appears.
14498 *
14499 * If no block is given, an enumerator is returned instead.
14500 */
14501static VALUE
14502argf_each_char(VALUE argf)
14503{
14504 RETURN_ENUMERATOR(argf, 0, 0);
14505 FOREACH_ARGF() {
14506 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14507 }
14508 return argf;
14509}
14510
14511/*
14512 * call-seq:
14513 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14514 * ARGF.each_codepoint -> an_enumerator
14515 *
14516 * Iterates over each codepoint of each file in ARGF.
14517 *
14518 * This method allows you to treat the files supplied on the command line as
14519 * a single file consisting of the concatenation of each named file. After
14520 * the last codepoint of the first file has been returned, the first
14521 * codepoint of the second file is returned. The ARGF.filename method can
14522 * be used to determine the name of the file in which the current codepoint
14523 * appears.
14524 *
14525 * If no block is given, an enumerator is returned instead.
14526 */
14527static VALUE
14528argf_each_codepoint(VALUE argf)
14529{
14530 RETURN_ENUMERATOR(argf, 0, 0);
14531 FOREACH_ARGF() {
14532 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14533 }
14534 return argf;
14535}
14536
14537/*
14538 * call-seq:
14539 * ARGF.filename -> String
14540 * ARGF.path -> String
14541 *
14542 * Returns the current filename. "-" is returned when the current file is
14543 * STDIN.
14544 *
14545 * For example:
14546 *
14547 * $ echo "foo" > foo
14548 * $ echo "bar" > bar
14549 * $ echo "glark" > glark
14550 *
14551 * $ ruby argf.rb foo bar glark
14552 *
14553 * ARGF.filename #=> "foo"
14554 * ARGF.read(5) #=> "foo\nb"
14555 * ARGF.filename #=> "bar"
14556 * ARGF.skip
14557 * ARGF.filename #=> "glark"
14558 */
14559static VALUE
14560argf_filename(VALUE argf)
14561{
14562 next_argv();
14563 return ARGF.filename;
14564}
14565
14566static VALUE
14567argf_filename_getter(ID id, VALUE *var)
14568{
14569 return argf_filename(*var);
14570}
14571
14572/*
14573 * call-seq:
14574 * ARGF.file -> IO or File object
14575 *
14576 * Returns the current file as an IO or File object.
14577 * <code>$stdin</code> is returned when the current file is STDIN.
14578 *
14579 * For example:
14580 *
14581 * $ echo "foo" > foo
14582 * $ echo "bar" > bar
14583 *
14584 * $ ruby argf.rb foo bar
14585 *
14586 * ARGF.file #=> #<File:foo>
14587 * ARGF.read(5) #=> "foo\nb"
14588 * ARGF.file #=> #<File:bar>
14589 */
14590static VALUE
14591argf_file(VALUE argf)
14592{
14593 next_argv();
14594 return ARGF.current_file;
14595}
14596
14597/*
14598 * call-seq:
14599 * ARGF.binmode -> ARGF
14600 *
14601 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14602 * be reset to non-binary mode. This option has the following effects:
14603 *
14604 * * Newline conversion is disabled.
14605 * * Encoding conversion is disabled.
14606 * * Content is treated as ASCII-8BIT.
14607 */
14608static VALUE
14609argf_binmode_m(VALUE argf)
14610{
14611 ARGF.binmode = 1;
14612 next_argv();
14613 ARGF_FORWARD(0, 0);
14614 rb_io_ascii8bit_binmode(ARGF.current_file);
14615 return argf;
14616}
14617
14618/*
14619 * call-seq:
14620 * ARGF.binmode? -> true or false
14621 *
14622 * Returns true if ARGF is being read in binary mode; false otherwise.
14623 * To enable binary mode use ARGF.binmode.
14624 *
14625 * For example:
14626 *
14627 * ARGF.binmode? #=> false
14628 * ARGF.binmode
14629 * ARGF.binmode? #=> true
14630 */
14631static VALUE
14632argf_binmode_p(VALUE argf)
14633{
14634 return RBOOL(ARGF.binmode);
14635}
14636
14637/*
14638 * call-seq:
14639 * ARGF.skip -> ARGF
14640 *
14641 * Sets the current file to the next file in ARGV. If there aren't any more
14642 * files it has no effect.
14643 *
14644 * For example:
14645 *
14646 * $ ruby argf.rb foo bar
14647 * ARGF.filename #=> "foo"
14648 * ARGF.skip
14649 * ARGF.filename #=> "bar"
14650 */
14651static VALUE
14652argf_skip(VALUE argf)
14653{
14654 if (ARGF.init_p && ARGF.next_p == 0) {
14655 argf_close(argf);
14656 ARGF.next_p = 1;
14657 }
14658 return argf;
14659}
14660
14661/*
14662 * call-seq:
14663 * ARGF.close -> ARGF
14664 *
14665 * Closes the current file and skips to the next file in ARGV. If there are
14666 * no more files to open, just closes the current file. STDIN will not be
14667 * closed.
14668 *
14669 * For example:
14670 *
14671 * $ ruby argf.rb foo bar
14672 *
14673 * ARGF.filename #=> "foo"
14674 * ARGF.close
14675 * ARGF.filename #=> "bar"
14676 * ARGF.close
14677 */
14678static VALUE
14679argf_close_m(VALUE argf)
14680{
14681 next_argv();
14682 argf_close(argf);
14683 if (ARGF.next_p != -1) {
14684 ARGF.next_p = 1;
14685 }
14686 ARGF.lineno = 0;
14687 return argf;
14688}
14689
14690/*
14691 * call-seq:
14692 * ARGF.closed? -> true or false
14693 *
14694 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14695 * ARGF.close to actually close the current file.
14696 */
14697static VALUE
14698argf_closed(VALUE argf)
14699{
14700 next_argv();
14701 ARGF_FORWARD(0, 0);
14702 return rb_io_closed_p(ARGF.current_file);
14703}
14704
14705/*
14706 * call-seq:
14707 * ARGF.to_s -> String
14708 *
14709 * Returns "ARGF".
14710 */
14711static VALUE
14712argf_to_s(VALUE argf)
14713{
14714 return rb_str_new2("ARGF");
14715}
14716
14717/*
14718 * call-seq:
14719 * ARGF.inplace_mode -> String
14720 *
14721 * Returns the file extension appended to the names of backup copies of
14722 * modified files under in-place edit mode. This value can be set using
14723 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14724 */
14725static VALUE
14726argf_inplace_mode_get(VALUE argf)
14727{
14728 if (!ARGF.inplace) return Qnil;
14729 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14730 return rb_str_dup(ARGF.inplace);
14731}
14732
14733static VALUE
14734opt_i_get(ID id, VALUE *var)
14735{
14736 return argf_inplace_mode_get(*var);
14737}
14738
14739/*
14740 * call-seq:
14741 * ARGF.inplace_mode = ext -> ARGF
14742 *
14743 * Sets the filename extension for in-place editing mode to the given String.
14744 * The backup copy of each file being edited has this value appended to its
14745 * filename.
14746 *
14747 * For example:
14748 *
14749 * $ ruby argf.rb file.txt
14750 *
14751 * ARGF.inplace_mode = '.bak'
14752 * ARGF.each_line do |line|
14753 * print line.sub("foo","bar")
14754 * end
14755 *
14756 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14757 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14758 * "bar".
14759 */
14760static VALUE
14761argf_inplace_mode_set(VALUE argf, VALUE val)
14762{
14763 if (!RTEST(val)) {
14764 ARGF.inplace = Qfalse;
14765 }
14766 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14767 ARGF.inplace = Qnil;
14768 }
14769 else {
14770 ARGF_SET(inplace, rb_str_new_frozen(val));
14771 }
14772 return argf;
14773}
14774
14775static void
14776opt_i_set(VALUE val, ID id, VALUE *var)
14777{
14778 argf_inplace_mode_set(*var, val);
14779}
14780
14781void
14782ruby_set_inplace_mode(const char *suffix)
14783{
14784 ARGF_SET(inplace, !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix)));
14785}
14786
14787/*
14788 * call-seq:
14789 * ARGF.argv -> ARGV
14790 *
14791 * Returns the +ARGV+ array, which contains the arguments passed to your
14792 * script, one per element.
14793 *
14794 * For example:
14795 *
14796 * $ ruby argf.rb -v glark.txt
14797 *
14798 * ARGF.argv #=> ["-v", "glark.txt"]
14799 *
14800 */
14801static VALUE
14802argf_argv(VALUE argf)
14803{
14804 return ARGF.argv;
14805}
14806
14807static VALUE
14808argf_argv_getter(ID id, VALUE *var)
14809{
14810 return argf_argv(*var);
14811}
14812
14813VALUE
14815{
14816 return ARGF.argv;
14817}
14818
14819/*
14820 * call-seq:
14821 * ARGF.to_write_io -> io
14822 *
14823 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14824 * enabled.
14825 */
14826static VALUE
14827argf_write_io(VALUE argf)
14828{
14829 if (!RTEST(ARGF.current_file)) {
14830 rb_raise(rb_eIOError, "not opened for writing");
14831 }
14832 return GetWriteIO(ARGF.current_file);
14833}
14834
14835/*
14836 * call-seq:
14837 * ARGF.write(*objects) -> integer
14838 *
14839 * Writes each of the given +objects+ if inplace mode.
14840 */
14841static VALUE
14842argf_write(int argc, VALUE *argv, VALUE argf)
14843{
14844 return rb_io_writev(argf_write_io(argf), argc, argv);
14845}
14846
14847void
14848rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14849{
14850 rb_readwrite_syserr_fail(waiting, errno, mesg);
14851}
14852
14853void
14854rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14855{
14856 VALUE arg, c = Qnil;
14857 arg = mesg ? rb_str_new2(mesg) : Qnil;
14858 switch (waiting) {
14859 case RB_IO_WAIT_WRITABLE:
14860 switch (n) {
14861 case EAGAIN:
14862 c = rb_eEAGAINWaitWritable;
14863 break;
14864#if EAGAIN != EWOULDBLOCK
14865 case EWOULDBLOCK:
14866 c = rb_eEWOULDBLOCKWaitWritable;
14867 break;
14868#endif
14869 case EINPROGRESS:
14870 c = rb_eEINPROGRESSWaitWritable;
14871 break;
14872 default:
14874 }
14875 break;
14876 case RB_IO_WAIT_READABLE:
14877 switch (n) {
14878 case EAGAIN:
14879 c = rb_eEAGAINWaitReadable;
14880 break;
14881#if EAGAIN != EWOULDBLOCK
14882 case EWOULDBLOCK:
14883 c = rb_eEWOULDBLOCKWaitReadable;
14884 break;
14885#endif
14886 case EINPROGRESS:
14887 c = rb_eEINPROGRESSWaitReadable;
14888 break;
14889 default:
14891 }
14892 break;
14893 default:
14894 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14895 }
14897}
14898
14899static VALUE
14900get_LAST_READ_LINE(ID _x, VALUE *_y)
14901{
14902 return rb_lastline_get();
14903}
14904
14905static void
14906set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14907{
14908 rb_lastline_set(val);
14909}
14910
14911/*
14912 * Document-class: IOError
14913 *
14914 * Raised when an IO operation fails.
14915 *
14916 * File.open("/etc/hosts") {|f| f << "example"}
14917 * #=> IOError: not opened for writing
14918 *
14919 * File.open("/etc/hosts") {|f| f.close; f.read }
14920 * #=> IOError: closed stream
14921 *
14922 * Note that some IO failures raise <code>SystemCallError</code>s
14923 * and these are not subclasses of IOError:
14924 *
14925 * File.open("does/not/exist")
14926 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14927 */
14928
14929/*
14930 * Document-class: EOFError
14931 *
14932 * Raised by some IO operations when reaching the end of file. Many IO
14933 * methods exist in two forms,
14934 *
14935 * one that returns +nil+ when the end of file is reached, the other
14936 * raises EOFError.
14937 *
14938 * EOFError is a subclass of IOError.
14939 *
14940 * file = File.open("/etc/hosts")
14941 * file.read
14942 * file.gets #=> nil
14943 * file.readline #=> EOFError: end of file reached
14944 * file.close
14945 */
14946
14947/*
14948 * Document-class: ARGF
14949 *
14950 * == \ARGF and +ARGV+
14951 *
14952 * The \ARGF object works with the array at global variable +ARGV+
14953 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14954 *
14955 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14956 *
14957 * Initially, it contains the command-line arguments and options
14958 * that are passed to the Ruby program;
14959 * the program can modify that array as it likes.
14960 *
14961 * - **ARGF** may be thought of as the <b>argument files</b> object.
14962 *
14963 * It can access file streams and/or the <tt>$stdin</tt> stream,
14964 * based on what it finds in +ARGV+.
14965 * This provides a convenient way for the command line
14966 * to specify streams for a Ruby program to read.
14967 *
14968 * == Reading
14969 *
14970 * \ARGF may read from _source_ streams,
14971 * which at any particular time are determined by the content of +ARGV+.
14972 *
14973 * === Simplest Case
14974 *
14975 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14976 * the source is <tt>$stdin</tt>:
14977 *
14978 * - \File +t.rb+:
14979 *
14980 * p ['ARGV', ARGV]
14981 * p ['ARGF.read', ARGF.read]
14982 *
14983 * - Commands and outputs
14984 * (see below for the content of files +foo.txt+ and +bar.txt+):
14985 *
14986 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14987 * ["ARGV", []]
14988 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14989 *
14990 * $ cat foo.txt bar.txt | ruby t.rb
14991 * ["ARGV", []]
14992 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14993 *
14994 * === About the Examples
14995 *
14996 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14997 *
14998 * $ cat foo.txt
14999 * Foo 0
15000 * Foo 1
15001 * $ cat bar.txt
15002 * Bar 0
15003 * Bar 1
15004 * Bar 2
15005 * Bar 3
15006 *
15007 * === Sources in +ARGV+
15008 *
15009 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
15010 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
15011 * the sources are found in +ARGV+.
15012 *
15013 * \ARGF assumes that each element in array +ARGV+ is a potential source,
15014 * and is one of:
15015 *
15016 * - The string path to a file that may be opened as a stream.
15017 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
15018 *
15019 * Each element that is _not_ one of these
15020 * should be removed from +ARGV+ before \ARGF accesses that source.
15021 *
15022 * In the following example:
15023 *
15024 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
15025 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
15026 *
15027 * Example:
15028 *
15029 * - \File +t.rb+:
15030 *
15031 * # Print arguments (and options, if any) found on command line.
15032 * p ['ARGV', ARGV]
15033 *
15034 * - Command and output:
15035 *
15036 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
15037 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
15038 *
15039 * \ARGF's stream access considers the elements of +ARGV+, left to right:
15040 *
15041 * - \File +t.rb+:
15042 *
15043 * p "ARGV: #{ARGV}"
15044 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
15045 *
15046 * - Command and output:
15047 *
15048 * $ ruby t.rb foo.txt bar.txt
15049 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15050 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15051 *
15052 * Because the value at +ARGV+ is an ordinary array,
15053 * you can manipulate it to control which sources \ARGF considers:
15054 *
15055 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
15056 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
15057 *
15058 * Each element in +ARGV+ is removed when its corresponding source is accessed;
15059 * when all sources have been accessed, the array is empty:
15060 *
15061 * - \File +t.rb+:
15062 *
15063 * until ARGV.empty? && ARGF.eof?
15064 * p "ARGV: #{ARGV}"
15065 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
15066 * end
15067 *
15068 * - Command and output:
15069 *
15070 * $ ruby t.rb foo.txt bar.txt
15071 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15072 * "Line: Foo 0\n"
15073 * "ARGV: [\"bar.txt\"]"
15074 * "Line: Foo 1\n"
15075 * "ARGV: [\"bar.txt\"]"
15076 * "Line: Bar 0\n"
15077 * "ARGV: []"
15078 * "Line: Bar 1\n"
15079 * "ARGV: []"
15080 * "Line: Bar 2\n"
15081 * "ARGV: []"
15082 * "Line: Bar 3\n"
15083 *
15084 * ==== Filepaths in +ARGV+
15085 *
15086 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
15087 *
15088 * This program prints what it reads from files at the paths specified
15089 * on the command line:
15090 *
15091 * - \File +t.rb+:
15092 *
15093 * p ['ARGV', ARGV]
15094 * # Read and print all content from the specified sources.
15095 * p ['ARGF.read', ARGF.read]
15096 *
15097 * - Command and output:
15098 *
15099 * $ ruby t.rb foo.txt bar.txt
15100 * ["ARGV", [foo.txt, bar.txt]
15101 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
15102 *
15103 * ==== Specifying <tt>$stdin</tt> in +ARGV+
15104 *
15105 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
15106 *
15107 * - \File +t.rb+:
15108 *
15109 * p ['ARGV', ARGV]
15110 * p ['ARGF.read', ARGF.read]
15111 *
15112 * - Command and output:
15113 *
15114 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
15115 * ["ARGV", ["-"]]
15116 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15117 *
15118 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored.
15119 *
15120 * - Command and output:
15121 *
15122 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
15123 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15124 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15125 *
15126 * ==== Mixtures and Repetitions in +ARGV+
15127 *
15128 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
15129 * and character <tt>'-'</tt>, including repetitions.
15130 *
15131 * ==== Modifications to +ARGV+
15132 *
15133 * The running Ruby program may make any modifications to the +ARGV+ array;
15134 * the current value of +ARGV+ affects \ARGF reading.
15135 *
15136 * ==== Empty +ARGV+
15137 *
15138 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15139 * or raises an exception, depending on the specific method.
15140 *
15141 * === More Read Methods
15142 *
15143 * As seen above, method ARGF#read reads the content of all sources
15144 * into a single string.
15145 * Other \ARGF methods provide other ways to access that content;
15146 * these include:
15147 *
15148 * - Byte access: #each_byte, #getbyte, #readbyte.
15149 * - Character access: #each_char, #getc, #readchar.
15150 * - Codepoint access: #each_codepoint.
15151 * - Line access: #each_line, #gets, #readline, #readlines.
15152 * - Source access: #read, #read_nonblock, #readpartial.
15153 *
15154 * === About \Enumerable
15155 *
15156 * \ARGF includes module Enumerable.
15157 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15158 *
15159 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15160 * _not_ from +ARGV+;
15161 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15162 * not an array of the strings from +ARGV+:
15163 *
15164 * - \File +t.rb+:
15165 *
15166 * p ['ARGV', ARGV]
15167 * p ['ARGF.entries', ARGF.entries]
15168 *
15169 * - Command and output:
15170 *
15171 * $ ruby t.rb foo.txt bar.txt
15172 * ["ARGV", ["foo.txt", "bar.txt"]]
15173 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15174 *
15175 * == Writing
15176 *
15177 * If <i>inplace mode</i> is in effect,
15178 * \ARGF may write to target streams,
15179 * which at any particular time are determined by the content of ARGV.
15180 *
15181 * Methods about inplace mode:
15182 *
15183 * - #inplace_mode
15184 * - #inplace_mode=
15185 * - #to_write_io
15186 *
15187 * Methods for writing:
15188 *
15189 * - #print
15190 * - #printf
15191 * - #putc
15192 * - #puts
15193 * - #write
15194 *
15195 */
15196
15197/*
15198 * An instance of class \IO (commonly called a _stream_)
15199 * represents an input/output stream in the underlying operating system.
15200 * Class \IO is the basis for input and output in Ruby.
15201 *
15202 * Class File is the only class in the Ruby core that is a subclass of \IO.
15203 * Some classes in the Ruby standard library are also subclasses of \IO;
15204 * these include TCPSocket and UDPSocket.
15205 *
15206 * The global constant ARGF (also accessible as <tt>$<</tt>)
15207 * provides an IO-like stream that allows access to all file paths
15208 * found in ARGV (or found in STDIN if ARGV is empty).
15209 * ARGF is not itself a subclass of \IO.
15210 *
15211 * Class StringIO provides an IO-like stream that handles a String.
15212 * StringIO is not itself a subclass of \IO.
15213 *
15214 * Important objects based on \IO include:
15215 *
15216 * - $stdin.
15217 * - $stdout.
15218 * - $stderr.
15219 * - Instances of class File.
15220 *
15221 * An instance of \IO may be created using:
15222 *
15223 * - IO.new: returns a new \IO object for the given integer file descriptor.
15224 * - IO.open: passes a new \IO object to the given block.
15225 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15226 * of a newly-launched subprocess.
15227 * - Kernel#open: Returns a new \IO object connected to a given source:
15228 * stream, file, or subprocess.
15229 *
15230 * Like a File stream, an \IO stream has:
15231 *
15232 * - A read/write mode, which may be read-only, write-only, or read/write;
15233 * see {Read/Write Mode}[rdoc-ref:File@ReadWrite+Mode].
15234 * - A data mode, which may be text-only or binary;
15235 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15236 * - Internal and external encodings;
15237 * see {Encodings}[rdoc-ref:File@Encodings].
15238 *
15239 * And like other \IO streams, it has:
15240 *
15241 * - A position, which determines where in the stream the next
15242 * read or write is to occur;
15243 * see {Position}[rdoc-ref:IO@Position].
15244 * - A line number, which is a special, line-oriented, "position"
15245 * (different from the position mentioned above);
15246 * see {Line Number}[rdoc-ref:IO@Line+Number].
15247 *
15248 * == Extension <tt>io/console</tt>
15249 *
15250 * Extension <tt>io/console</tt> provides numerous methods
15251 * for interacting with the console;
15252 * requiring it adds numerous methods to class \IO.
15253 *
15254 * == Example Files
15255 *
15256 * Many examples here use these variables:
15257 *
15258 * :include: doc/examples/files.rdoc
15259 *
15260 * == Open Options
15261 *
15262 * A number of \IO methods accept optional keyword arguments
15263 * that determine how a new stream is to be opened:
15264 *
15265 * - +:mode+: Stream mode.
15266 * - +:flags+: Integer file open flags;
15267 * If +mode+ is also given, the two are bitwise-ORed.
15268 * - +:external_encoding+: External encoding for the stream.
15269 * - +:internal_encoding+: Internal encoding for the stream.
15270 * <tt>'-'</tt> is a synonym for the default internal encoding.
15271 * If the value is +nil+ no conversion occurs.
15272 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15273 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15274 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15275 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15276 * when the stream closes; otherwise it remains open.
15277 * - +:path+: If a string value is provided, it is used in #inspect and is available as
15278 * #path method.
15279 *
15280 * Also available are the options offered in String#encode,
15281 * which may control conversion between external and internal encoding.
15282 *
15283 * == Basic \IO
15284 *
15285 * You can perform basic stream \IO with these methods,
15286 * which typically operate on multi-byte strings:
15287 *
15288 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15289 * - IO#write: Writes zero or more strings to the stream;
15290 * each given object that is not already a string is converted via +to_s+.
15291 *
15292 * === Position
15293 *
15294 * An \IO stream has a nonnegative integer _position_,
15295 * which is the byte offset at which the next read or write is to occur.
15296 * A new stream has position zero (and line number zero);
15297 * method +rewind+ resets the position (and line number) to zero.
15298 *
15299 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15300 * Encoding::Converter instances used for that \IO.
15301 *
15302 * The relevant methods:
15303 *
15304 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15305 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15306 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15307 * relative to a given position +whence+
15308 * (indicating the beginning, end, or current position).
15309 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15310 *
15311 * === Open and Closed Streams
15312 *
15313 * A new \IO stream may be open for reading, open for writing, or both.
15314 *
15315 * A stream is automatically closed when claimed by the garbage collector.
15316 *
15317 * Attempted reading or writing on a closed stream raises an exception.
15318 *
15319 * The relevant methods:
15320 *
15321 * - IO#close: Closes the stream for both reading and writing.
15322 * - IO#close_read: Closes the stream for reading.
15323 * - IO#close_write: Closes the stream for writing.
15324 * - IO#closed?: Returns whether the stream is closed.
15325 *
15326 * === End-of-Stream
15327 *
15328 * You can query whether a stream is positioned at its end:
15329 *
15330 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15331 *
15332 * You can reposition to end-of-stream by using method IO#seek:
15333 *
15334 * f = File.new('t.txt')
15335 * f.eof? # => false
15336 * f.seek(0, :END)
15337 * f.eof? # => true
15338 * f.close
15339 *
15340 * Or by reading all stream content (which is slower than using IO#seek):
15341 *
15342 * f.rewind
15343 * f.eof? # => false
15344 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15345 * f.eof? # => true
15346 *
15347 * == Line \IO
15348 *
15349 * Class \IO supports line-oriented
15350 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15351 *
15352 * === Line Input
15353 *
15354 * Class \IO supports line-oriented input for
15355 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input].
15356 *
15357 * ==== Line Input Options
15358 *
15359 * Optional keyword argument +chomp+ (default: +false+)
15360 * specifies whether line separators are to be excluded from the result of a read.
15361 *
15362 * ==== \File Line Input
15363 *
15364 * You can read lines from a file using these methods:
15365 *
15366 * - IO.foreach: Reads each line and passes it to the given block.
15367 * - IO.readlines: Reads and returns all lines in an array.
15368 *
15369 * For each of these methods:
15370 *
15371 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15372 * - Line parsing depends on the effective <i>line separator</i>;
15373 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15374 * - The length of each returned line depends on the effective <i>line limit</i>;
15375 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15376 *
15377 * ==== Stream Line Input
15378 *
15379 * You can read lines from an \IO stream using these methods:
15380 *
15381 * - IO#each_line: Reads each remaining line, passing it to the given block.
15382 * - IO#gets: Returns the next line.
15383 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15384 * - IO#readlines: Returns all remaining lines in an array.
15385 *
15386 * For each of these methods:
15387 *
15388 * - Reading may begin mid-line,
15389 * depending on the stream's _position_;
15390 * see {Position}[rdoc-ref:IO@Position].
15391 * - Line parsing depends on the effective <i>line separator</i>;
15392 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15393 * - The length of each returned line depends on the effective <i>line limit</i>;
15394 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15395 *
15396 * ===== Line Separator
15397 *
15398 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15399 * the string that determines what is considered a line;
15400 * it is sometimes called the <i>input record separator</i>.
15401 *
15402 * The default line separator is taken from global variable <tt>$/</tt>,
15403 * whose initial value is <tt>"\n"</tt>.
15404 *
15405 * Generally, the line to be read next is all data
15406 * from the current {position}[rdoc-ref:IO@Position]
15407 * to the next line separator
15408 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15409 *
15410 * f = File.new('t.txt')
15411 * # Method gets with no sep argument returns the next line, according to $/.
15412 * f.gets # => "First line\n"
15413 * f.gets # => "Second line\n"
15414 * f.gets # => "\n"
15415 * f.gets # => "Fourth line\n"
15416 * f.gets # => "Fifth line\n"
15417 * f.close
15418 *
15419 * You can use a different line separator by passing argument +sep+:
15420 *
15421 * f = File.new('t.txt')
15422 * f.gets('l') # => "First l"
15423 * f.gets('li') # => "ine\nSecond li"
15424 * f.gets('lin') # => "ne\n\nFourth lin"
15425 * f.gets # => "e\n"
15426 * f.close
15427 *
15428 * Or by setting global variable <tt>$/</tt>:
15429 *
15430 * f = File.new('t.txt')
15431 * $/ = 'l'
15432 * f.gets # => "First l"
15433 * f.gets # => "ine\nSecond l"
15434 * f.gets # => "ine\n\nFourth l"
15435 * f.close
15436 *
15437 * ===== Special Line Separator Values
15438 *
15439 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15440 * accepts two special values for parameter +sep+:
15441 *
15442 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15443 *
15444 * f = File.new('t.txt')
15445 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15446 * f.close
15447 *
15448 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15449 * (paragraphs being separated by two consecutive line separators):
15450 *
15451 * f = File.new('t.txt')
15452 * f.gets('') # => "First line\nSecond line\n\n"
15453 * f.gets('') # => "Fourth line\nFifth line\n"
15454 * f.close
15455 *
15456 * ===== Line Limit
15457 *
15458 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15459 * uses an integer <i>line limit</i>,
15460 * which restricts the number of bytes that may be returned.
15461 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15462 * than the limit).
15463 *
15464 * The default limit value is <tt>-1</tt>;
15465 * any negative limit value means that there is no limit.
15466 *
15467 * If there is no limit, the line is determined only by +sep+.
15468 *
15469 * # Text with 1-byte characters.
15470 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15471 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15472 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15473 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15474 * # No more than one line.
15475 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15476 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15477 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15478 *
15479 * # Text with 3-byte characters, which will not be split.
15480 * File.read('t.ja') # => "こんにちは"
15481 * File.open('t.ja') {|f| f.gets(1).size } # => 1
15482 * File.open('t.ja') {|f| f.gets(2).size } # => 1
15483 * File.open('t.ja') {|f| f.gets(3).size } # => 1
15484 * File.open('t.ja') {|f| f.gets(4).size } # => 2
15485 * File.open('t.ja') {|f| f.gets(5).size } # => 2
15486 *
15487 * ===== Line Separator and Line Limit
15488 *
15489 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15490 *
15491 * - Returns the next line as determined by line separator +sep+.
15492 * - But returns no more bytes than are allowed by the limit +limit+.
15493 *
15494 * Example:
15495 *
15496 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15497 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15498 *
15499 * ===== Line Number
15500 *
15501 * A readable \IO stream has a non-negative integer <i>line number</i>:
15502 *
15503 * - IO#lineno: Returns the line number.
15504 * - IO#lineno=: Resets and returns the line number.
15505 *
15506 * Unless modified by a call to method IO#lineno=,
15507 * the line number is the number of lines read
15508 * by certain line-oriented methods,
15509 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15510 *
15511 * - IO.foreach: Increments the line number on each call to the block.
15512 * - IO#each_line: Increments the line number on each call to the block.
15513 * - IO#gets: Increments the line number.
15514 * - IO#readline: Increments the line number.
15515 * - IO#readlines: Increments the line number for each line read.
15516 *
15517 * A new stream is initially has line number zero (and position zero);
15518 * method +rewind+ resets the line number (and position) to zero:
15519 *
15520 * f = File.new('t.txt')
15521 * f.lineno # => 0
15522 * f.gets # => "First line\n"
15523 * f.lineno # => 1
15524 * f.rewind
15525 * f.lineno # => 0
15526 * f.close
15527 *
15528 * Reading lines from a stream usually changes its line number:
15529 *
15530 * f = File.new('t.txt', 'r')
15531 * f.lineno # => 0
15532 * f.readline # => "This is line one.\n"
15533 * f.lineno # => 1
15534 * f.readline # => "This is the second line.\n"
15535 * f.lineno # => 2
15536 * f.readline # => "Here's the third line.\n"
15537 * f.lineno # => 3
15538 * f.eof? # => true
15539 * f.close
15540 *
15541 * Iterating over lines in a stream usually changes its line number:
15542 *
15543 * File.open('t.txt') do |f|
15544 * f.each_line do |line|
15545 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15546 * end
15547 * end
15548 *
15549 * Output:
15550 *
15551 * "position=11 eof?=false lineno=1"
15552 * "position=23 eof?=false lineno=2"
15553 * "position=24 eof?=false lineno=3"
15554 * "position=36 eof?=false lineno=4"
15555 * "position=47 eof?=true lineno=5"
15556 *
15557 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15558 * the line number does not affect where the next read or write will occur:
15559 *
15560 * f = File.new('t.txt')
15561 * f.lineno = 1000
15562 * f.lineno # => 1000
15563 * f.gets # => "First line\n"
15564 * f.lineno # => 1001
15565 * f.close
15566 *
15567 * Associated with the line number is the global variable <tt>$.</tt>:
15568 *
15569 * - When a stream is opened, <tt>$.</tt> is not set;
15570 * its value is left over from previous activity in the process:
15571 *
15572 * $. = 41
15573 * f = File.new('t.txt')
15574 * $. = 41
15575 * # => 41
15576 * f.close
15577 *
15578 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15579 *
15580 * f0 = File.new('t.txt')
15581 * f1 = File.new('t.dat')
15582 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15583 * $. # => 5
15584 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15585 * $. # => 1
15586 * f0.close
15587 * f1.close
15588 *
15589 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15590 *
15591 * f = File.new('t.txt')
15592 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15593 * $. # => 5
15594 * f.rewind
15595 * f.seek(0, :SET)
15596 * $. # => 5
15597 * f.close
15598 *
15599 * === Line Output
15600 *
15601 * You can write to an \IO stream line-by-line using this method:
15602 *
15603 * - IO#puts: Writes objects to the stream.
15604 *
15605 * == Character \IO
15606 *
15607 * You can process an \IO stream character-by-character using these methods:
15608 *
15609 * - IO#getc: Reads and returns the next character from the stream.
15610 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15611 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15612 * - IO#putc: Writes a character to the stream.
15613 * - IO#each_char: Reads each remaining character in the stream,
15614 * passing the character to the given block.
15615 *
15616 * == Byte \IO
15617 *
15618 * You can process an \IO stream byte-by-byte using these methods:
15619 *
15620 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15621 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15622 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15623 * - IO#each_byte: Reads each remaining byte in the stream,
15624 * passing the byte to the given block.
15625 *
15626 * == Codepoint \IO
15627 *
15628 * You can process an \IO stream codepoint-by-codepoint:
15629 *
15630 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15631 *
15632 * == What's Here
15633 *
15634 * First, what's elsewhere. Class \IO:
15635 *
15636 * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
15637 * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
15638 * which provides dozens of additional methods.
15639 *
15640 * Here, class \IO provides methods that are useful for:
15641 *
15642 * - {Creating}[rdoc-ref:IO@Creating]
15643 * - {Reading}[rdoc-ref:IO@Reading]
15644 * - {Writing}[rdoc-ref:IO@Writing]
15645 * - {Positioning}[rdoc-ref:IO@Positioning]
15646 * - {Iterating}[rdoc-ref:IO@Iterating]
15647 * - {Settings}[rdoc-ref:IO@Settings]
15648 * - {Querying}[rdoc-ref:IO@Querying]
15649 * - {Buffering}[rdoc-ref:IO@Buffering]
15650 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15651 * - {Other}[rdoc-ref:IO@Other]
15652 *
15653 * === Creating
15654 *
15655 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15656 * integer file descriptor.
15657 * - ::open: Creates a new \IO object.
15658 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15659 * - ::popen: Creates an \IO object to interact with a subprocess.
15660 * - ::select: Selects which given \IO instances are ready for reading,
15661 * writing, or have pending exceptions.
15662 *
15663 * === Reading
15664 *
15665 * - ::binread: Returns a binary string with all or a subset of bytes
15666 * from the given file.
15667 * - ::read: Returns a string with all or a subset of bytes from the given file.
15668 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15669 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15670 * - #getc: Returns the next character read from +self+ as a string.
15671 * - #gets: Returns the line read from +self+.
15672 * - #pread: Returns all or the next _n_ bytes read from +self+,
15673 * not updating the receiver's offset.
15674 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15675 * for a given _n_.
15676 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15677 * in non-block mode.
15678 * - #readbyte: Returns the next byte read from +self+;
15679 * same as #getbyte, but raises an exception on end-of-stream.
15680 * - #readchar: Returns the next character read from +self+;
15681 * same as #getc, but raises an exception on end-of-stream.
15682 * - #readline: Returns the next line read from +self+;
15683 * same as #getline, but raises an exception of end-of-stream.
15684 * - #readlines: Returns an array of all lines read read from +self+.
15685 * - #readpartial: Returns up to the given number of bytes from +self+.
15686 *
15687 * === Writing
15688 *
15689 * - ::binwrite: Writes the given string to the file at the given filepath,
15690 * in binary mode.
15691 * - ::write: Writes the given string to +self+.
15692 * - #<<: Appends the given string to +self+.
15693 * - #print: Prints last read line or given objects to +self+.
15694 * - #printf: Writes to +self+ based on the given format string and objects.
15695 * - #putc: Writes a character to +self+.
15696 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15697 * - #pwrite: Writes the given string at the given offset,
15698 * not updating the receiver's offset.
15699 * - #write: Writes one or more given strings to +self+.
15700 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15701 *
15702 * === Positioning
15703 *
15704 * - #lineno: Returns the current line number in +self+.
15705 * - #lineno=: Sets the line number is +self+.
15706 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15707 * - #pos=: Sets the byte offset in +self+.
15708 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15709 * - #rewind: Positions +self+ to the beginning of input.
15710 * - #seek: Sets the offset for +self+ relative to given position.
15711 *
15712 * === Iterating
15713 *
15714 * - ::foreach: Yields each line of given file to the block.
15715 * - #each (aliased as #each_line): Calls the given block
15716 * with each successive line in +self+.
15717 * - #each_byte: Calls the given block with each successive byte in +self+
15718 * as an integer.
15719 * - #each_char: Calls the given block with each successive character in +self+
15720 * as a string.
15721 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15722 * as an integer.
15723 *
15724 * === Settings
15725 *
15726 * - #autoclose=: Sets whether +self+ auto-closes.
15727 * - #binmode: Sets +self+ to binary mode.
15728 * - #close: Closes +self+.
15729 * - #close_on_exec=: Sets the close-on-exec flag.
15730 * - #close_read: Closes +self+ for reading.
15731 * - #close_write: Closes +self+ for writing.
15732 * - #set_encoding: Sets the encoding for +self+.
15733 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15734 * Unicode byte-order-mark.
15735 * - #sync=: Sets the sync-mode to the given value.
15736 *
15737 * === Querying
15738 *
15739 * - #autoclose?: Returns whether +self+ auto-closes.
15740 * - #binmode?: Returns whether +self+ is in binary mode.
15741 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15742 * - #closed?: Returns whether +self+ is closed.
15743 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15744 * - #external_encoding: Returns the external encoding object for +self+.
15745 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15746 * - #internal_encoding: Returns the internal encoding object for +self+.
15747 * - #pid: Returns the process ID of a child process associated with +self+,
15748 * if +self+ was created by ::popen.
15749 * - #stat: Returns the File::Stat object containing status information for +self+.
15750 * - #sync: Returns whether +self+ is in sync-mode.
15751 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15752 *
15753 * === Buffering
15754 *
15755 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15756 * - #flush: Flushes any buffered data within +self+ to the underlying
15757 * operating system.
15758 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15759 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15760 * - #ungetc: Prepends buffer for +self+ with given string.
15761 *
15762 * === Low-Level Access
15763 *
15764 * - ::sysopen: Opens the file given by its path,
15765 * returning the integer file descriptor.
15766 * - #advise: Announces the intention to access data from +self+ in a specific way.
15767 * - #fcntl: Passes a low-level command to the file specified
15768 * by the given file descriptor.
15769 * - #ioctl: Passes a low-level command to the device specified
15770 * by the given file descriptor.
15771 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15772 * - #sysseek: Sets the offset for +self+.
15773 * - #syswrite: Writes the given string to +self+ using a low-level write.
15774 *
15775 * === Other
15776 *
15777 * - ::copy_stream: Copies data from a source to a destination,
15778 * each of which is a filepath or an \IO-like object.
15779 * - ::try_convert: Returns a new \IO object resulting from converting
15780 * the given object.
15781 * - #inspect: Returns the string representation of +self+.
15782 *
15783 */
15784
15785void
15786Init_IO(void)
15787{
15788 VALUE rb_cARGF;
15789#ifdef __CYGWIN__
15790#include <sys/cygwin.h>
15791 static struct __cygwin_perfile pf[] =
15792 {
15793 {"", O_RDONLY | O_BINARY},
15794 {"", O_WRONLY | O_BINARY},
15795 {"", O_RDWR | O_BINARY},
15796 {"", O_APPEND | O_BINARY},
15797 {NULL, 0}
15798 };
15799 cygwin_internal(CW_PERFILE, pf);
15800#endif
15801
15802 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
15803 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
15804
15805 id_write = rb_intern_const("write");
15806 id_read = rb_intern_const("read");
15807 id_flush = rb_intern_const("flush");
15808 id_readpartial = rb_intern_const("readpartial");
15809 id_set_encoding = rb_intern_const("set_encoding");
15810 id_fileno = rb_intern_const("fileno");
15811
15812 rb_define_global_function("syscall", rb_f_syscall, -1);
15813
15814 rb_define_global_function("open", rb_f_open, -1);
15815 rb_define_global_function("printf", rb_f_printf, -1);
15816 rb_define_global_function("print", rb_f_print, -1);
15817 rb_define_global_function("putc", rb_f_putc, 1);
15818 rb_define_global_function("puts", rb_f_puts, -1);
15819 rb_define_global_function("gets", rb_f_gets, -1);
15820 rb_define_global_function("readline", rb_f_readline, -1);
15821 rb_define_global_function("select", rb_f_select, -1);
15822
15823 rb_define_global_function("readlines", rb_f_readlines, -1);
15824
15825 rb_define_global_function("`", rb_f_backquote, 1);
15826
15827 rb_define_global_function("p", rb_f_p, -1);
15828 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15829
15830 rb_cIO = rb_define_class("IO", rb_cObject);
15832
15833 /* Can be raised by IO operations when IO#timeout= is set. */
15834 rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
15835
15836 /* Readable event mask for IO#wait. */
15837 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15838 /* Writable event mask for IO#wait. */
15839 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15840 /* Priority event mask for IO#wait. */
15841 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15842
15843 /* exception to wait for reading. see IO.select. */
15844 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
15845 /* exception to wait for writing. see IO.select. */
15846 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
15847 /* exception to wait for reading by EAGAIN. see IO.select. */
15848 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15849 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15850 /* exception to wait for writing by EAGAIN. see IO.select. */
15851 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15852 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15853#if EAGAIN == EWOULDBLOCK
15854 /* same as IO::EAGAINWaitReadable */
15855 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15856 /* same as IO::EAGAINWaitWritable */
15857 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15858#else
15859 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15860 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15861 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15862 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15863 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15864 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15865#endif
15866 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15867 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15868 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15869 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15870 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15871 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15872
15873#if 0
15874 /* This is necessary only for forcing rdoc handle File::open */
15875 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15876#endif
15877
15878 rb_define_alloc_func(rb_cIO, io_alloc);
15879 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15880 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15881 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15882 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15883 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15884 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15885 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15886 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15887 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15888 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15889 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15890 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15891 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15892 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15893 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15894
15895 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15896
15898 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
15899
15900 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15901 rb_vm_register_global_object(rb_default_rs);
15902 rb_rs = rb_default_rs;
15904 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15905 rb_gvar_ractor_local("$/"); // not local but ractor safe
15906 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15907 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15908 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
15909
15910 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15911 rb_gvar_ractor_local("$_");
15912 rb_gvar_box_dynamic("$_");
15913
15914 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15915 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15916
15917 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15918 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15919 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15920 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15921
15922 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15923 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15924 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15925 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15926 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15927
15928 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15929 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15930
15931 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15932 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15933
15934 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15935 rb_define_alias(rb_cIO, "to_i", "fileno");
15936 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15937
15938 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15939 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15940
15941 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15942 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15943 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15944 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15945
15946 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15947 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15948
15949 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15950
15951 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15952 rb_define_method(rb_cIO, "read", io_read, -1);
15953 rb_define_method(rb_cIO, "write", io_write_m, -1);
15954 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15955 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15956 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15957 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15958 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15959 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15960 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15962 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15963 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15964 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15965 /* Set I/O position from the beginning */
15966 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15967 /* Set I/O position from the current position */
15968 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15969 /* Set I/O position from the end */
15970 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15971#ifdef SEEK_DATA
15972 /* Set I/O position to the next location containing data */
15973 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15974#endif
15975#ifdef SEEK_HOLE
15976 /* Set I/O position to the next hole */
15977 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15978#endif
15979 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15980 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15981 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15982 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15983 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15984
15985 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15986 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15987
15988 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15989 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15990 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15991 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15992
15993 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15994 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15995 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15996 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15997 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15998 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15999
16000 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
16001 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
16002 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
16003
16004 rb_define_method(rb_cIO, "path", rb_io_path, 0);
16005 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
16006
16007 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
16008
16009 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
16010 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
16011 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
16012 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
16013
16014 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
16015 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
16016
16017 rb_define_method(rb_cIO, "wait", io_wait, -1);
16018
16019 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
16020 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
16021 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
16022
16023 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
16024 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
16025 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
16026 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
16027
16028 rb_gvar_ractor_local("$stdin");
16029 rb_gvar_ractor_local("$stdout");
16030 rb_gvar_ractor_local("$>");
16031 rb_gvar_ractor_local("$stderr");
16032
16033 rb_gvar_box_dynamic("$stdin");
16034 rb_gvar_box_dynamic("$stdout");
16035 rb_gvar_box_dynamic("$>");
16036 rb_gvar_box_dynamic("$stderr");
16037
16039 rb_stdin = rb_io_prep_stdin();
16041 rb_stdout = rb_io_prep_stdout();
16043 rb_stderr = rb_io_prep_stderr();
16044
16045 orig_stdout = rb_stdout;
16046 orig_stderr = rb_stderr;
16047
16048 /* Holds the original stdin */
16050 /* Holds the original stdout */
16052 /* Holds the original stderr */
16054
16055#if 0
16056 /* Hack to get rdoc to regard ARGF as a class: */
16057 rb_cARGF = rb_define_class("ARGF", rb_cObject);
16058#endif
16059
16060 rb_cARGF = rb_class_new(rb_cObject);
16061 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
16062 rb_define_alloc_func(rb_cARGF, argf_alloc);
16063
16065
16066 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
16067 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
16068 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
16069 rb_define_alias(rb_cARGF, "inspect", "to_s");
16070 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
16071
16072 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
16073 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
16074 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
16075 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
16076 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
16077 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
16078 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
16079 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
16080 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
16081
16082 rb_define_method(rb_cARGF, "read", argf_read, -1);
16083 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
16084 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
16085 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
16086 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
16087 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
16088 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
16089 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
16090 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
16091 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
16092 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
16093 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
16094 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
16095 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
16096 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
16097 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
16098 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
16099 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
16100 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
16101 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
16102
16103 rb_define_method(rb_cARGF, "write", argf_write, -1);
16104 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
16105 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
16106 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
16107 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
16108
16109 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
16110 rb_define_method(rb_cARGF, "path", argf_filename, 0);
16111 rb_define_method(rb_cARGF, "file", argf_file, 0);
16112 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
16113 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
16114 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
16115
16116 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
16117 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
16118
16119 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
16120 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
16121
16122 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
16123 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
16124 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
16125
16126 argf = rb_class_new_instance(0, 0, rb_cARGF);
16127
16129 /*
16130 * ARGF is a stream designed for use in scripts that process files given
16131 * as command-line arguments or passed in via STDIN.
16132 *
16133 * See ARGF (the class) for more details.
16134 */
16136
16137 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
16138 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
16139 ARGF_SET(filename, rb_str_new2("-"));
16140
16141 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
16142 rb_gvar_ractor_local("$-i");
16143
16144 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16145
16146#if defined (_WIN32) || defined(__CYGWIN__)
16147 atexit(pipe_atexit);
16148#endif
16149
16150 Init_File();
16151
16152 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16153
16154 sym_mode = ID2SYM(rb_intern_const("mode"));
16155 sym_perm = ID2SYM(rb_intern_const("perm"));
16156 sym_flags = ID2SYM(rb_intern_const("flags"));
16157 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16158 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16159 sym_encoding = ID2SYM(rb_id_encoding());
16160 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16161 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16162 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16163 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16164 sym_normal = ID2SYM(rb_intern_const("normal"));
16165 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16166 sym_random = ID2SYM(rb_intern_const("random"));
16167 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16168 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16169 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16170 sym_SET = ID2SYM(rb_intern_const("SET"));
16171 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16172 sym_END = ID2SYM(rb_intern_const("END"));
16173#ifdef SEEK_DATA
16174 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16175#endif
16176#ifdef SEEK_HOLE
16177 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16178#endif
16179 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16180 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16181}
16182
16183static void init_builtin_io(void);
16184#define Init_builtin_io init_builtin_io
16185#include "io.rbinc"
16186#undef Init_builtin_io
16187
16188void
16189Init_builtin_io(void)
16190{
16191 init_builtin_io();
16192
16193 /* Init_IO is called earlier than `loaded_features` is initialized */
16194 rb_provide("io/wait.rb");
16195 rb_provide("io/wait.so");
16196}
#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:1765
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:849
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:3086
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:3389
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:3376
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:3165
#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:1473
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:4074
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:14854
VALUE rb_eIOError
IOError exception.
Definition io.c:193
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1460
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:4164
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:4080
#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:1463
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:14848
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:1461
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:1483
@ 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:192
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:8734
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4410
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:8867
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:9296
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:5282
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5187
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:9477
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:9276
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:6525
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6479
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5346
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7522
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10565
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:7410
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:7417
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5882
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:2983
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:2131
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:3673
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:3551
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:4085
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
Definition variable.c:888
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:162
enum rb_io_mode rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
Definition io.c:6611
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:6744
#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:7227
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:6893
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2997
#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:9523
#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:3076
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:7018
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:5793
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:5990
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:3531
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:9389
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:7514
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:14814
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9175
#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:4856
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.