Ruby 4.1.0dev (2026-09-21 revision 8befacf9e6c898a0f79dcb53bdd2e4cea24e0d1c)
io.c (8befacf9e6c898a0f79dcb53bdd2e4cea24e0d1c)
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 * call-seq:
3059 * path -> string or nil
3060 *
3061 * Returns the path associated with the IO, or +nil+ if there is no path
3062 * associated with the IO. It is not guaranteed that the path exists on
3063 * the filesystem.
3064 *
3065 * $stdin.path # => "<STDIN>"
3066 *
3067 * File.open("testfile") {|f| f.path} # => "testfile"
3068 */
3069
3070VALUE
3072{
3073 rb_io_t *fptr = RFILE(io)->fptr;
3074
3075 if (!fptr)
3076 return Qnil;
3077
3078 return rb_obj_dup(fptr->pathv);
3079}
3080
3081/*
3082 * call-seq:
3083 * inspect -> string
3084 *
3085 * Returns a string representation of +self+:
3086 *
3087 * f = File.open('t.txt')
3088 * f.inspect # => "#<File:t.txt>"
3089 * f.close
3090 *
3091 */
3092
3093static VALUE
3094rb_io_inspect(VALUE obj)
3095{
3096 rb_io_t *fptr;
3097 VALUE result;
3098 static const char closed[] = " (closed)";
3099
3100 fptr = RFILE(obj)->fptr;
3101 if (!fptr) return rb_any_to_s(obj);
3102 result = rb_str_new_cstr("#<");
3103 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3104 rb_str_cat2(result, ":");
3105 if (NIL_P(fptr->pathv)) {
3106 if (fptr->fd < 0) {
3107 rb_str_cat(result, closed+1, strlen(closed)-1);
3108 }
3109 else {
3110 rb_str_catf(result, "fd %d", fptr->fd);
3111 }
3112 }
3113 else {
3114 rb_str_append(result, fptr->pathv);
3115 if (fptr->fd < 0) {
3116 rb_str_cat(result, closed, strlen(closed));
3117 }
3118 }
3119 return rb_str_cat2(result, ">");
3120}
3121
3122/*
3123 * call-seq:
3124 * to_io -> self
3125 *
3126 * Returns +self+.
3127 *
3128 */
3129
3130static VALUE
3131rb_io_to_io(VALUE io)
3132{
3133 return io;
3134}
3135
3136/* reading functions */
3137static long
3138read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3139{
3140 int n;
3141
3142 n = READ_DATA_PENDING_COUNT(fptr);
3143 if (n <= 0) return 0;
3144 if (n > len) n = (int)len;
3145 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3146 fptr->rbuf.off += n;
3147 fptr->rbuf.len -= n;
3148 return n;
3149}
3150
3151static long
3152io_bufread(char *ptr, long len, rb_io_t *fptr)
3153{
3154 long offset = 0;
3155 long n = len;
3156 long c;
3157
3158 if (READ_DATA_PENDING(fptr) == 0) {
3159 while (n > 0) {
3160 again:
3161 rb_io_check_closed(fptr);
3162 c = rb_io_read_memory(fptr, ptr+offset, n);
3163 if (c == 0) break;
3164 if (c < 0) {
3165 if (fptr_wait_readable(fptr))
3166 goto again;
3167 return -1;
3168 }
3169 offset += c;
3170 if ((n -= c) <= 0) break;
3171 }
3172 return len - n;
3173 }
3174
3175 while (n > 0) {
3176 c = read_buffered_data(ptr+offset, n, fptr);
3177 if (c > 0) {
3178 offset += c;
3179 if ((n -= c) <= 0) break;
3180 }
3181 rb_io_check_closed(fptr);
3182 if (io_fillbuf(fptr) < 0) {
3183 break;
3184 }
3185 }
3186 return len - n;
3187}
3188
3189static int io_setstrbuf(VALUE *str, long len);
3190
3192 char *str_ptr;
3193 long len;
3194 rb_io_t *fptr;
3195};
3196
3197static VALUE
3198bufread_call(VALUE arg)
3199{
3200 struct bufread_arg *p = (struct bufread_arg *)arg;
3201 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3202 return Qundef;
3203}
3204
3205static long
3206io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3207{
3208 long len;
3209 struct bufread_arg arg;
3210
3211 io_setstrbuf(&str, offset + size);
3212 arg.str_ptr = RSTRING_PTR(str) + offset;
3213 arg.len = size;
3214 arg.fptr = fptr;
3215 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3216 len = arg.len;
3217 if (len < 0) rb_sys_fail_path(fptr->pathv);
3218 return len;
3219}
3220
3221static long
3222remain_size(rb_io_t *fptr)
3223{
3224 struct stat st;
3225 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3226 rb_off_t pos;
3227
3228 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3229#if defined(__HAIKU__)
3230 && (st.st_dev > 3)
3231#endif
3232 )
3233 {
3234 if (io_fflush(fptr) < 0)
3235 rb_sys_fail_on_write(fptr);
3236 pos = lseek(fptr->fd, 0, SEEK_CUR);
3237 if (st.st_size >= pos && pos >= 0) {
3238 siz += st.st_size - pos;
3239 if (siz > LONG_MAX) {
3240 rb_raise(rb_eIOError, "file too big for single read");
3241 }
3242 }
3243 }
3244 else {
3245 siz += BUFSIZ;
3246 }
3247 return (long)siz;
3248}
3249
3250static VALUE
3251io_enc_str(VALUE str, rb_io_t *fptr)
3252{
3253 rb_enc_associate(str, io_read_encoding(fptr));
3254 return str;
3255}
3256
3257static void
3258make_readconv(rb_io_t *fptr, int size)
3259{
3260 if (!fptr->readconv) {
3261 int ecflags;
3262 VALUE ecopts;
3263 const char *sname, *dname;
3264 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3265 ecopts = fptr->encs.ecopts;
3266 if (fptr->encs.enc2) {
3267 sname = rb_enc_name(fptr->encs.enc2);
3268 dname = rb_enc_name(io_read_encoding(fptr));
3269 }
3270 else {
3271 sname = dname = "";
3272 }
3273 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3274 if (!fptr->readconv)
3275 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3276 fptr->cbuf.off = 0;
3277 fptr->cbuf.len = 0;
3278 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3279 fptr->cbuf.capa = size;
3280 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3281 }
3282}
3283
3284#define MORE_CHAR_SUSPENDED Qtrue
3285#define MORE_CHAR_FINISHED Qnil
3286static VALUE
3287fill_cbuf(rb_io_t *fptr, int ec_flags)
3288{
3289 const unsigned char *ss, *sp, *se;
3290 unsigned char *ds, *dp, *de;
3292 int putbackable;
3293 int cbuf_len0;
3294 VALUE exc;
3295
3296 ec_flags |= ECONV_PARTIAL_INPUT;
3297
3298 if (fptr->cbuf.len == fptr->cbuf.capa)
3299 return MORE_CHAR_SUSPENDED; /* cbuf full */
3300 if (fptr->cbuf.len == 0)
3301 fptr->cbuf.off = 0;
3302 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3303 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3304 fptr->cbuf.off = 0;
3305 }
3306
3307 cbuf_len0 = fptr->cbuf.len;
3308
3309 while (1) {
3310 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3311 se = sp + fptr->rbuf.len;
3312 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3313 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3314 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3315 fptr->rbuf.off += (int)(sp - ss);
3316 fptr->rbuf.len -= (int)(sp - ss);
3317 fptr->cbuf.len += (int)(dp - ds);
3318
3319 putbackable = rb_econv_putbackable(fptr->readconv);
3320 if (putbackable) {
3321 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3322 fptr->rbuf.off -= putbackable;
3323 fptr->rbuf.len += putbackable;
3324 }
3325
3326 exc = rb_econv_make_exception(fptr->readconv);
3327 if (!NIL_P(exc))
3328 return exc;
3329
3330 if (cbuf_len0 != fptr->cbuf.len)
3331 return MORE_CHAR_SUSPENDED;
3332
3333 if (res == econv_finished) {
3334 return MORE_CHAR_FINISHED;
3335 }
3336
3337 if (res == econv_source_buffer_empty) {
3338 if (fptr->rbuf.len == 0) {
3339 READ_CHECK(fptr);
3340 if (io_fillbuf(fptr) < 0) {
3341 if (!fptr->readconv) {
3342 return MORE_CHAR_FINISHED;
3343 }
3344 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3345 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3346 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3347 fptr->cbuf.len += (int)(dp - ds);
3349 break;
3350 }
3351 }
3352 }
3353 }
3354 if (cbuf_len0 != fptr->cbuf.len)
3355 return MORE_CHAR_SUSPENDED;
3356
3357 return MORE_CHAR_FINISHED;
3358}
3359
3360static VALUE
3361more_char(rb_io_t *fptr)
3362{
3363 VALUE v;
3364 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3365 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3366 rb_exc_raise(v);
3367 return v;
3368}
3369
3370static VALUE
3371io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3372{
3373 VALUE str = Qnil;
3374 if (strp) {
3375 str = *strp;
3376 if (NIL_P(str)) {
3377 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3378 }
3379 else {
3380 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3381 }
3382 rb_enc_associate(str, fptr->encs.enc);
3383 }
3384 fptr->cbuf.off += len;
3385 fptr->cbuf.len -= len;
3386 /* xxx: set coderange */
3387 if (fptr->cbuf.len == 0)
3388 fptr->cbuf.off = 0;
3389 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3390 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3391 fptr->cbuf.off = 0;
3392 }
3393 return str;
3394}
3395
3396static int
3397io_setstrbuf(VALUE *str, long len)
3398{
3399 if (NIL_P(*str)) {
3400 *str = rb_str_new(0, len);
3401 return TRUE;
3402 }
3403 else {
3404 VALUE s = StringValue(*str);
3405 rb_str_modify(s);
3406
3407 long clen = RSTRING_LEN(s);
3408 if (clen >= len) {
3409 return FALSE;
3410 }
3411 len -= clen;
3412 }
3413 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3415 }
3416 return FALSE;
3417}
3418
3419#define MAX_REALLOC_GAP 4096
3420static void
3421io_shrink_read_string(VALUE str, long n)
3422{
3423 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3424 rb_str_resize(str, n);
3425 }
3426}
3427
3428static void
3429io_set_read_length(VALUE str, long n, int shrinkable)
3430{
3431 if (RSTRING_LEN(str) != n) {
3432 rb_str_modify(str);
3433 rb_str_set_len(str, n);
3434 if (shrinkable) io_shrink_read_string(str, n);
3435 }
3436}
3437
3438static VALUE
3439read_all(rb_io_t *fptr, long siz, VALUE str)
3440{
3441 long bytes;
3442 long n;
3443 long pos;
3444 rb_encoding *enc;
3445 int cr;
3446 int shrinkable;
3447
3448 if (NEED_READCONV(fptr)) {
3449 int first = !NIL_P(str);
3450 SET_BINARY_MODE(fptr);
3451 shrinkable = io_setstrbuf(&str,0);
3452 make_readconv(fptr, 0);
3453 while (1) {
3454 VALUE v;
3455 if (fptr->cbuf.len) {
3456 if (first) rb_str_set_len(str, first = 0);
3457 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3458 }
3459 v = fill_cbuf(fptr, 0);
3460 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3461 if (fptr->cbuf.len) {
3462 if (first) rb_str_set_len(str, first = 0);
3463 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3464 }
3465 rb_exc_raise(v);
3466 }
3467 if (v == MORE_CHAR_FINISHED) {
3468 clear_readconv(fptr);
3469 if (first) rb_str_set_len(str, first = 0);
3470 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3471 return io_enc_str(str, fptr);
3472 }
3473 }
3474 }
3475
3476 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3477 bytes = 0;
3478 pos = 0;
3479
3480 enc = io_read_encoding(fptr);
3481 cr = 0;
3482
3483 if (siz == 0) {
3484 siz = BUFSIZ;
3485 }
3486 else {
3487 // If `siz` is set, we got it from `stat(2)`.
3488 // We attempt to read one extra byte because:
3489 // - If the file was appended to since then, we'll continue reading.
3490 // - If the file is still the same length, we won't issue a second `io_fread`.
3491 siz++;
3492 }
3493 shrinkable = io_setstrbuf(&str, siz);
3494 for (;;) {
3495 READ_CHECK(fptr);
3496 n = io_fread(str, bytes, siz - bytes, fptr);
3497 if (n == 0 && bytes == 0) {
3498 rb_str_set_len(str, 0);
3499 break;
3500 }
3501 bytes += n;
3502 rb_str_set_len(str, bytes);
3503 if (cr != ENC_CODERANGE_BROKEN)
3504 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3505 if (bytes < siz) break;
3506 siz += BUFSIZ;
3507
3508 size_t capa = rb_str_capacity(str);
3509 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3510 if (capa < BUFSIZ) {
3511 capa = BUFSIZ;
3512 }
3513 else if (capa > IO_MAX_BUFFER_GROWTH) {
3514 capa = IO_MAX_BUFFER_GROWTH;
3515 }
3517 }
3518 }
3519 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3520 str = io_enc_str(str, fptr);
3521 ENC_CODERANGE_SET(str, cr);
3522 return str;
3523}
3524
3525void
3527{
3528 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3529 rb_sys_fail_path(fptr->pathv);
3530 }
3531}
3532
3533static VALUE
3534io_read_memory_call(VALUE arg)
3535{
3536 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3537
3538 VALUE scheduler = rb_fiber_scheduler_current();
3539 if (scheduler != Qnil) {
3540 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa);
3541
3542 if (!UNDEF_P(result)) {
3543 // This is actually returned as a pseudo-VALUE and later cast to a long:
3545 }
3546 }
3547
3548 if (iis->nonblock) {
3549 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3550 }
3551 else {
3552 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3553 }
3554}
3555
3556static long
3557io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3558{
3559 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3560}
3561
3562#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3563
3564static VALUE
3565io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3566{
3567 rb_io_t *fptr;
3568 VALUE length, str;
3569 long n, len;
3570 struct io_internal_read_struct iis;
3571 int shrinkable;
3572
3573 rb_scan_args(argc, argv, "11", &length, &str);
3574
3575 if ((len = NUM2LONG(length)) < 0) {
3576 rb_raise(rb_eArgError, "negative length %ld given", len);
3577 }
3578
3579 shrinkable = io_setstrbuf(&str, len);
3580
3581 GetOpenFile(io, fptr);
3583
3584 if (len == 0) {
3585 io_set_read_length(str, 0, shrinkable);
3586 return str;
3587 }
3588
3589 if (!nonblock)
3590 READ_CHECK(fptr);
3591 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3592 if (n <= 0) {
3593 again:
3594 if (nonblock) {
3595 rb_io_set_nonblock(fptr);
3596 }
3597 io_setstrbuf(&str, len);
3598 iis.th = rb_thread_current();
3599 iis.fptr = fptr;
3600 iis.nonblock = nonblock;
3601 iis.fd = fptr->fd;
3602 iis.buf = RSTRING_PTR(str);
3603 iis.capa = len;
3604 iis.timeout = NULL;
3605 n = io_read_memory_locktmp(str, &iis);
3606 if (n < 0) {
3607 int e = errno;
3608 if (!nonblock && fptr_wait_readable(fptr))
3609 goto again;
3610 if (nonblock && (io_again_p(e))) {
3611 if (no_exception)
3612 return sym_wait_readable;
3613 else
3614 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3615 e, "read would block");
3616 }
3617 rb_syserr_fail_path(e, fptr->pathv);
3618 }
3619 }
3620 io_set_read_length(str, n, shrinkable);
3621
3622 if (n == 0)
3623 return Qnil;
3624 else
3625 return str;
3626}
3627
3628/*
3629 * call-seq:
3630 * readpartial(maxlen) -> string
3631 * readpartial(maxlen, out_string) -> out_string
3632 *
3633 * Reads up to +maxlen+ bytes from the stream;
3634 * returns a string (either a new string or the given +out_string+).
3635 * Its encoding is:
3636 *
3637 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3638 * - ASCII-8BIT, otherwise.
3639 *
3640 * - Contains +maxlen+ bytes from the stream, if available.
3641 * - Otherwise contains all available bytes, if any available.
3642 * - Is an empty string if +maxlen+ is zero.
3643 *
3644 * With the single non-negative integer argument +maxlen+ given,
3645 * returns a new string:
3646 *
3647 * f = File.new('t.txt')
3648 * f.readpartial(20) # => "First line\nSecond l"
3649 * f.readpartial(20) # => "ine\n\nFourth line\n"
3650 * f.readpartial(20) # => "Fifth line\n"
3651 * f.readpartial(20) # Raises EOFError.
3652 * f.close
3653 *
3654 * With both argument +maxlen+ and string argument +out_string+ given,
3655 * returns modified +out_string+:
3656 *
3657 * f = File.new('t.txt')
3658 * s = 'foo'
3659 * f.readpartial(20, s) # => "First line\nSecond l"
3660 * s = 'bar'
3661 * f.readpartial(0, s) # => ""
3662 * f.close
3663 *
3664 * This method is useful for a stream such as a pipe, a socket, or a tty.
3665 * It blocks only when no data is immediately available.
3666 * This means that it blocks only when _all_ of the following are true:
3667 *
3668 * - The byte buffer in the stream is empty.
3669 * - The content of the stream is empty.
3670 * - The stream is not at EOF.
3671 *
3672 * When blocked, the method waits for either more data or EOF on the stream:
3673 *
3674 * - If more data is read, the method returns the data.
3675 * - If EOF is reached, the method raises EOFError.
3676 *
3677 * When not blocked, the method responds immediately:
3678 *
3679 * - Returns data from the buffer if there is any.
3680 * - Otherwise returns data from the stream if there is any.
3681 * - Otherwise raises EOFError if the stream has reached EOF.
3682 *
3683 * Note that this method is similar to sysread. The differences are:
3684 *
3685 * - If the byte buffer is not empty, read from the byte buffer
3686 * instead of "sysread for buffered IO (IOError)".
3687 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3688 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3689 * readpartial retries the system call.
3690 *
3691 * The latter means that readpartial is non-blocking-flag insensitive.
3692 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3693 * if the fd is blocking mode.
3694 *
3695 * Examples:
3696 *
3697 * # # Returned Buffer Content Pipe Content
3698 * r, w = IO.pipe #
3699 * w << 'abc' # "" "abc".
3700 * r.readpartial(4096) # => "abc" "" ""
3701 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3702 *
3703 * # # Returned Buffer Content Pipe Content
3704 * r, w = IO.pipe #
3705 * w << 'abc' # "" "abc"
3706 * w.close # "" "abc" EOF
3707 * r.readpartial(4096) # => "abc" "" EOF
3708 * r.readpartial(4096) # raises EOFError
3709 *
3710 * # # Returned Buffer Content Pipe Content
3711 * r, w = IO.pipe #
3712 * w << "abc\ndef\n" # "" "abc\ndef\n"
3713 * r.gets # => "abc\n" "def\n" ""
3714 * w << "ghi\n" # "def\n" "ghi\n"
3715 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3716 * r.readpartial(4096) # => "ghi\n" "" ""
3717 *
3718 */
3719
3720static VALUE
3721io_readpartial(int argc, VALUE *argv, VALUE io)
3722{
3723 VALUE ret;
3724
3725 ret = io_getpartial(argc, argv, io, Qnil, 0);
3726 if (NIL_P(ret))
3727 rb_eof_error();
3728 return ret;
3729}
3730
3731static VALUE
3732io_nonblock_eof(int no_exception)
3733{
3734 if (!no_exception) {
3735 rb_eof_error();
3736 }
3737 return Qnil;
3738}
3739
3740/* :nodoc: */
3741static VALUE
3742io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3743{
3744 rb_io_t *fptr;
3745 long n, len;
3746 struct io_internal_read_struct iis;
3747 int shrinkable;
3748
3749 if ((len = NUM2LONG(length)) < 0) {
3750 rb_raise(rb_eArgError, "negative length %ld given", len);
3751 }
3752
3753 shrinkable = io_setstrbuf(&str, len);
3754 rb_bool_expected(ex, "exception", TRUE);
3755
3756 GetOpenFile(io, fptr);
3758
3759 if (len == 0) {
3760 io_set_read_length(str, 0, shrinkable);
3761 return str;
3762 }
3763
3764 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3765 if (n <= 0) {
3766 rb_fd_set_nonblock(fptr->fd);
3767 shrinkable |= io_setstrbuf(&str, len);
3768 iis.fptr = fptr;
3769 iis.nonblock = 1;
3770 iis.fd = fptr->fd;
3771 iis.buf = RSTRING_PTR(str);
3772 iis.capa = len;
3773 iis.timeout = NULL;
3774 n = io_read_memory_locktmp(str, &iis);
3775 if (n < 0) {
3776 int e = errno;
3777 if (io_again_p(e)) {
3778 if (!ex) return sym_wait_readable;
3779 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3780 e, "read would block");
3781 }
3782 rb_syserr_fail_path(e, fptr->pathv);
3783 }
3784 }
3785 io_set_read_length(str, n, shrinkable);
3786
3787 if (n == 0) {
3788 if (!ex) return Qnil;
3789 rb_eof_error();
3790 }
3791
3792 return str;
3793}
3794
3795/* :nodoc: */
3796static VALUE
3797io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3798{
3799 rb_io_t *fptr;
3800 long n;
3801
3802 if (!RB_TYPE_P(str, T_STRING))
3803 str = rb_obj_as_string(str);
3804 rb_bool_expected(ex, "exception", TRUE);
3805
3806 io = GetWriteIO(io);
3807 GetOpenFile(io, fptr);
3809
3810 if (io_fflush(fptr) < 0)
3811 rb_sys_fail_on_write(fptr);
3812
3813 rb_fd_set_nonblock(fptr->fd);
3814 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3815 RB_GC_GUARD(str);
3816
3817 if (n < 0) {
3818 int e = errno;
3819 if (io_again_p(e)) {
3820 if (!ex) {
3821 return sym_wait_writable;
3822 }
3823 else {
3824 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3825 }
3826 }
3827 rb_syserr_fail_path(e, fptr->pathv);
3828 }
3829
3830 return LONG2FIX(n);
3831}
3832
3833/*
3834 * call-seq:
3835 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3836 *
3837 * Reads bytes from the stream; the stream must be opened for reading
3838 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3839 *
3840 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3841 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3842 *
3843 * Returns a string (either a new string or the given +out_string+)
3844 * containing the bytes read.
3845 * The encoding of the string depends on both +maxLen+ and +out_string+:
3846 *
3847 * - +maxlen+ is +nil+: uses internal encoding of +self+
3848 * (regardless of whether +out_string+ was given).
3849 * - +maxlen+ not +nil+:
3850 *
3851 * - +out_string+ given: encoding of +out_string+ not modified.
3852 * - +out_string+ not given: ASCII-8BIT is used.
3853 *
3854 * <b>Without Argument +out_string+</b>
3855 *
3856 * When argument +out_string+ is omitted,
3857 * the returned value is a new string:
3858 *
3859 * f = File.new('t.txt')
3860 * f.read
3861 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3862 * f.rewind
3863 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3864 * f.read(30) # => "rth line\r\nFifth line\r\n"
3865 * f.read(30) # => nil
3866 * f.close
3867 *
3868 * If +maxlen+ is zero, returns an empty string.
3869 *
3870 * <b> With Argument +out_string+</b>
3871 *
3872 * When argument +out_string+ is given,
3873 * the returned value is +out_string+, whose content is replaced:
3874 *
3875 * f = File.new('t.txt')
3876 * s = 'foo' # => "foo"
3877 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3878 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3879 * f.rewind
3880 * s = 'bar'
3881 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3882 * s # => "First line\r\nSecond line\r\n\r\nFou"
3883 * s = 'baz'
3884 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3885 * s # => "rth line\r\nFifth line\r\n"
3886 * s = 'bat'
3887 * f.read(30, s) # => nil
3888 * s # => ""
3889 * f.close
3890 *
3891 * Note that this method behaves like the fread() function in C.
3892 * This means it retries to invoke read(2) system calls to read data
3893 * with the specified maxlen (or until EOF).
3894 *
3895 * This behavior is preserved even if the stream is in non-blocking mode.
3896 * (This method is non-blocking-flag insensitive as other methods.)
3897 *
3898 * If you need the behavior like a single read(2) system call,
3899 * consider #readpartial, #read_nonblock, and #sysread.
3900 *
3901 * Related: IO#write.
3902 */
3903
3904static VALUE
3905io_read(int argc, VALUE *argv, VALUE io)
3906{
3907 rb_io_t *fptr;
3908 long n, len;
3909 VALUE length, str;
3910 int shrinkable;
3911#if RUBY_CRLF_ENVIRONMENT
3912 int previous_mode;
3913#endif
3914
3915 rb_scan_args(argc, argv, "02", &length, &str);
3916
3917 if (NIL_P(length)) {
3918 GetOpenFile(io, fptr);
3920 return read_all(fptr, remain_size(fptr), str);
3921 }
3922 len = NUM2LONG(length);
3923 if (len < 0) {
3924 rb_raise(rb_eArgError, "negative length %ld given", len);
3925 }
3926
3927 shrinkable = io_setstrbuf(&str,len);
3928
3929 GetOpenFile(io, fptr);
3931 if (len == 0) {
3932 io_set_read_length(str, 0, shrinkable);
3933 return str;
3934 }
3935
3936 READ_CHECK(fptr);
3937#if RUBY_CRLF_ENVIRONMENT
3938 previous_mode = set_binary_mode_with_seek_cur(fptr);
3939#endif
3940 n = io_fread(str, 0, len, fptr);
3941 io_set_read_length(str, n, shrinkable);
3942#if RUBY_CRLF_ENVIRONMENT
3943 if (previous_mode == O_TEXT) {
3944 setmode(fptr->fd, O_TEXT);
3945 }
3946#endif
3947 if (n == 0) return Qnil;
3948
3949 return str;
3950}
3951
3952static void
3953rscheck(const char *rsptr, long rslen, VALUE rs)
3954{
3955 if (!rs) return;
3956 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3957 rb_raise(rb_eRuntimeError, "rs modified");
3958}
3959
3960static const char *
3961search_delim(const char *p, long len, int delim, rb_encoding *enc)
3962{
3963 if (rb_enc_mbminlen(enc) == 1) {
3964 p = memchr(p, delim, len);
3965 if (p) return p + 1;
3966 }
3967 else {
3968 const char *end = p + len;
3969 while (p < end) {
3970 int r = rb_enc_precise_mbclen(p, end, enc);
3971 if (!MBCLEN_CHARFOUND_P(r)) {
3972 p += rb_enc_mbminlen(enc);
3973 continue;
3974 }
3975 int n = MBCLEN_CHARFOUND_LEN(r);
3976 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3977 return p + n;
3978 }
3979 p += n;
3980 }
3981 }
3982 return NULL;
3983}
3984
3985static int
3986appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3987{
3988 VALUE str = *strp;
3989 long limit = *lp;
3990
3991 if (NEED_READCONV(fptr)) {
3992 SET_BINARY_MODE(fptr);
3993 make_readconv(fptr, 0);
3994 do {
3995 const char *p, *e;
3996 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3997 if (searchlen) {
3998 p = READ_CHAR_PENDING_PTR(fptr);
3999 if (0 < limit && limit < searchlen)
4000 searchlen = (int)limit;
4001 e = search_delim(p, searchlen, delim, enc);
4002 if (e) {
4003 int len = (int)(e-p);
4004 if (NIL_P(str))
4005 *strp = str = rb_str_new(p, len);
4006 else
4007 rb_str_buf_cat(str, p, len);
4008 fptr->cbuf.off += len;
4009 fptr->cbuf.len -= len;
4010 limit -= len;
4011 *lp = limit;
4012 return delim;
4013 }
4014
4015 if (NIL_P(str))
4016 *strp = str = rb_str_new(p, searchlen);
4017 else
4018 rb_str_buf_cat(str, p, searchlen);
4019 fptr->cbuf.off += searchlen;
4020 fptr->cbuf.len -= searchlen;
4021 limit -= searchlen;
4022
4023 if (limit == 0) {
4024 *lp = limit;
4025 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4026 }
4027 }
4028 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4029 clear_readconv(fptr);
4030 *lp = limit;
4031 return EOF;
4032 }
4033
4034 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4035 do {
4036 long pending = READ_DATA_PENDING_COUNT(fptr);
4037 if (pending > 0) {
4038 const char *p = READ_DATA_PENDING_PTR(fptr);
4039 const char *e;
4040 long last;
4041
4042 if (limit > 0 && pending > limit) pending = limit;
4043 e = search_delim(p, pending, delim, enc);
4044 if (e) pending = e - p;
4045 if (!NIL_P(str)) {
4046 last = RSTRING_LEN(str);
4047 rb_str_resize(str, last + pending);
4048 }
4049 else {
4050 last = 0;
4051 *strp = str = rb_str_buf_new(pending);
4052 rb_str_set_len(str, pending);
4053 }
4054 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
4055 limit -= pending;
4056 *lp = limit;
4057 if (e) return delim;
4058 if (limit == 0)
4059 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4060 }
4061 READ_CHECK(fptr);
4062 } while (io_fillbuf(fptr) >= 0);
4063 *lp = limit;
4064 return EOF;
4065}
4066
4067static inline int
4068swallow(rb_io_t *fptr, int term)
4069{
4070 if (NEED_READCONV(fptr)) {
4071 rb_encoding *enc = io_read_encoding(fptr);
4072 int needconv = rb_enc_mbminlen(enc) != 1;
4073 SET_BINARY_MODE(fptr);
4074 make_readconv(fptr, 0);
4075 do {
4076 size_t cnt;
4077 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4078 const char *p = READ_CHAR_PENDING_PTR(fptr);
4079 int i;
4080 if (!needconv) {
4081 if (*p != term) return TRUE;
4082 i = (int)cnt;
4083 while (--i && *++p == term);
4084 }
4085 else {
4086 const char *e = p + cnt;
4087 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
4088 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4089 i = (int)(e - p);
4090 }
4091 io_shift_cbuf(fptr, (int)cnt - i, NULL);
4092 }
4093 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4094 return FALSE;
4095 }
4096
4097 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4098 do {
4099 size_t cnt;
4100 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4101 char buf[1024];
4102 const char *p = READ_DATA_PENDING_PTR(fptr);
4103 int i;
4104 if (cnt > sizeof buf) cnt = sizeof buf;
4105 if (*p != term) return TRUE;
4106 i = (int)cnt;
4107 while (--i && *++p == term);
4108 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4109 rb_sys_fail_path(fptr->pathv);
4110 }
4111 READ_CHECK(fptr);
4112 } while (io_fillbuf(fptr) == 0);
4113 return FALSE;
4114}
4115
4116static VALUE
4117rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4118{
4119 VALUE str = Qnil;
4120 int len = 0;
4121 long pos = 0;
4122 int cr = 0;
4123
4124 do {
4125 int pending = READ_DATA_PENDING_COUNT(fptr);
4126
4127 if (pending > 0) {
4128 const char *p = READ_DATA_PENDING_PTR(fptr);
4129 const char *e;
4130 int chomplen = 0;
4131
4132 e = memchr(p, '\n', pending);
4133 if (e) {
4134 pending = (int)(e - p + 1);
4135 if (chomp) {
4136 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4137 }
4138 }
4139 if (NIL_P(str)) {
4140 str = rb_str_new(p, pending - chomplen);
4141 fptr->rbuf.off += pending;
4142 fptr->rbuf.len -= pending;
4143 }
4144 else {
4145 rb_str_resize(str, len + pending - chomplen);
4146 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4147 fptr->rbuf.off += chomplen;
4148 fptr->rbuf.len -= chomplen;
4149 if (pending == 1 && chomplen == 1 && len > 0) {
4150 if (RSTRING_PTR(str)[len-1] == '\r') {
4151 rb_str_resize(str, --len);
4152 break;
4153 }
4154 }
4155 }
4156 len += pending - chomplen;
4157 if (cr != ENC_CODERANGE_BROKEN)
4158 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4159 if (e) break;
4160 }
4161 READ_CHECK(fptr);
4162 } while (io_fillbuf(fptr) >= 0);
4163 if (NIL_P(str)) return Qnil;
4164
4165 str = io_enc_str(str, fptr);
4166 ENC_CODERANGE_SET(str, cr);
4167 fptr->lineno++;
4168
4169 return str;
4170}
4171
4173 VALUE io;
4174 VALUE rs;
4175 long limit;
4176 unsigned int chomp: 1;
4177};
4178
4179static void
4180extract_getline_opts(VALUE opts, struct getline_arg *args)
4181{
4182 int chomp = FALSE;
4183 if (!NIL_P(opts)) {
4184 static ID kwds[1];
4185 VALUE vchomp;
4186 if (!kwds[0]) {
4187 kwds[0] = rb_intern_const("chomp");
4188 }
4189 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4190 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4191 }
4192 args->chomp = chomp;
4193}
4194
4195static void
4196extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4197{
4198 VALUE rs = rb_rs, lim = Qnil;
4199
4200 if (argc == 1) {
4201 VALUE tmp = Qnil;
4202
4203 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4204 rs = tmp;
4205 }
4206 else {
4207 lim = argv[0];
4208 }
4209 }
4210 else if (2 <= argc) {
4211 rs = argv[0], lim = argv[1];
4212 if (!NIL_P(rs))
4213 StringValue(rs);
4214 }
4215 args->rs = rs;
4216 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4217}
4218
4219static void
4220check_getline_args(VALUE *rsp, long *limit, VALUE io)
4221{
4222 rb_io_t *fptr;
4223 VALUE rs = *rsp;
4224
4225 if (!NIL_P(rs)) {
4226 rb_encoding *enc_rs, *enc_io;
4227
4228 GetOpenFile(io, fptr);
4229 enc_rs = rb_enc_get(rs);
4230 enc_io = io_read_encoding(fptr);
4231 if (enc_io != enc_rs &&
4232 (!is_ascii_string(rs) ||
4233 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4234 if (rs == rb_default_rs) {
4235 rs = rb_enc_str_new(0, 0, enc_io);
4236 rb_str_buf_cat_ascii(rs, "\n");
4237 *rsp = rs;
4238 }
4239 else {
4240 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4241 rb_enc_name(enc_io),
4242 rb_enc_name(enc_rs));
4243 }
4244 }
4245 }
4246}
4247
4248static void
4249prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4250{
4251 VALUE opts;
4252 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4253 extract_getline_args(argc, argv, args);
4254 extract_getline_opts(opts, args);
4255 check_getline_args(&args->rs, &args->limit, io);
4256}
4257
4258static VALUE
4259rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4260{
4261 VALUE str = Qnil;
4262 int nolimit = 0;
4263 rb_encoding *enc;
4264
4266 if (NIL_P(rs) && limit < 0) {
4267 str = read_all(fptr, 0, Qnil);
4268 if (RSTRING_LEN(str) == 0) return Qnil;
4269 }
4270 else if (limit == 0) {
4271 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4272 }
4273 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4274 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4275 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4276 return rb_io_getline_fast(fptr, enc, chomp);
4277 }
4278 else {
4279 int c, newline = -1;
4280 const char *rsptr = 0;
4281 long rslen = 0;
4282 int rspara = 0;
4283 int extra_limit = 16;
4284 int chomp_cr = chomp;
4285
4286 SET_BINARY_MODE(fptr);
4287 enc = io_read_encoding(fptr);
4288
4289 if (!NIL_P(rs)) {
4290 rslen = RSTRING_LEN(rs);
4291 if (rslen == 0) {
4292 rsptr = "\n\n";
4293 rslen = 2;
4294 rspara = 1;
4295 swallow(fptr, '\n');
4296 rs = 0;
4297 if (!rb_enc_asciicompat(enc)) {
4298 rs = rb_usascii_str_new(rsptr, rslen);
4299 rs = rb_str_conv_enc(rs, 0, enc);
4300 OBJ_FREEZE(rs);
4301 rsptr = RSTRING_PTR(rs);
4302 rslen = RSTRING_LEN(rs);
4303 }
4304 newline = '\n';
4305 }
4306 else if (rb_enc_mbminlen(enc) == 1) {
4307 rsptr = RSTRING_PTR(rs);
4308 newline = (unsigned char)rsptr[rslen - 1];
4309 }
4310 else {
4311 rs = rb_str_conv_enc(rs, 0, enc);
4312 rsptr = RSTRING_PTR(rs);
4313 const char *e = rsptr + rslen;
4314 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4315 int n;
4316 newline = rb_enc_codepoint_len(last, e, &n, enc);
4317 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4318 }
4319 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4320 }
4321
4322 /* MS - Optimization */
4323 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4324 const char *s, *p, *pp, *e;
4325
4326 if (c == newline) {
4327 if (RSTRING_LEN(str) < rslen) continue;
4328 s = RSTRING_PTR(str);
4329 e = RSTRING_END(str);
4330 p = e - rslen;
4331 if (!at_char_boundary(s, p, e, enc)) continue;
4332 if (!rspara) rscheck(rsptr, rslen, rs);
4333 if (memcmp(p, rsptr, rslen) == 0) {
4334 if (chomp) {
4335 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4336 rb_str_set_len(str, p - s);
4337 }
4338 break;
4339 }
4340 }
4341 if (limit == 0) {
4342 s = RSTRING_PTR(str);
4343 p = RSTRING_END(str);
4344 pp = rb_enc_prev_char(s, p, p, enc);
4345 if (extra_limit && pp &&
4346 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4347 /* relax the limit while incomplete character.
4348 * extra_limit limits the relax length */
4349 limit = 1;
4350 extra_limit--;
4351 }
4352 else {
4353 nolimit = 1;
4354 break;
4355 }
4356 }
4357 }
4358
4359 if (rspara && c != EOF)
4360 swallow(fptr, '\n');
4361 if (!NIL_P(str))
4362 str = io_enc_str(str, fptr);
4363 }
4364
4365 if (!NIL_P(str) && !nolimit) {
4366 fptr->lineno++;
4367 }
4368
4369 return str;
4370}
4371
4372static VALUE
4373rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4374{
4375 rb_io_t *fptr;
4376 int old_lineno, new_lineno;
4377 VALUE str;
4378
4379 GetOpenFile(io, fptr);
4380 old_lineno = fptr->lineno;
4381 str = rb_io_getline_0(rs, limit, chomp, fptr);
4382 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4383 if (io == ARGF.current_file) {
4384 ARGF.lineno += new_lineno - old_lineno;
4385 ARGF.last_lineno = ARGF.lineno;
4386 }
4387 else {
4388 ARGF.last_lineno = new_lineno;
4389 }
4390 }
4391
4392 return str;
4393}
4394
4395static VALUE
4396rb_io_getline(int argc, VALUE *argv, VALUE io)
4397{
4398 struct getline_arg args;
4399
4400 prepare_getline_args(argc, argv, &args, io);
4401 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4402}
4403
4404VALUE
4406{
4407 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4408}
4409
4410VALUE
4411rb_io_gets_limit_internal(VALUE io, long limit)
4412{
4413 rb_io_t *fptr;
4414 GetOpenFile(io, fptr);
4415 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4416}
4417
4418VALUE
4419rb_io_gets_internal(VALUE io)
4420{
4421 return rb_io_gets_limit_internal(io, -1);
4422}
4423
4424/*
4425 * call-seq:
4426 * gets(sep = $/, chomp: false) -> string or nil
4427 * gets(limit, chomp: false) -> string or nil
4428 * gets(sep, limit, chomp: false) -> string or nil
4429 *
4430 * Reads and returns a line from the stream;
4431 * assigns the return value to <tt>$_</tt>.
4432 * See {Line IO}[rdoc-ref:IO@Line+IO].
4433 *
4434 * With no arguments given, returns the next line
4435 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4436 *
4437 * f = File.open('t.txt')
4438 * f.gets # => "First line\n"
4439 * $_ # => "First line\n"
4440 * f.gets # => "\n"
4441 * f.gets # => "Fourth line\n"
4442 * f.gets # => "Fifth line\n"
4443 * f.gets # => nil
4444 * f.close
4445 *
4446 * With only string argument +sep+ given,
4447 * returns the next line as determined by line separator +sep+,
4448 * or +nil+ if none;
4449 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4450 *
4451 * f = File.new('t.txt')
4452 * f.gets('l') # => "First l"
4453 * f.gets('li') # => "ine\nSecond li"
4454 * f.gets('lin') # => "ne\n\nFourth lin"
4455 * f.gets # => "e\n"
4456 * f.close
4457 *
4458 * The two special values for +sep+ are honored:
4459 *
4460 * f = File.new('t.txt')
4461 * # Get all.
4462 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4463 * f.rewind
4464 * # Get paragraph (up to two line separators).
4465 * f.gets('') # => "First line\nSecond line\n\n"
4466 * f.close
4467 *
4468 * With only integer argument +limit+ given,
4469 * limits the number of bytes in the line;
4470 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4471 *
4472 * # No more than one line.
4473 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4474 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4475 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4476 *
4477 * With arguments +sep+ and +limit+ given,
4478 * combines the two behaviors
4479 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4480 *
4481 * Optional keyword argument +chomp+ specifies whether line separators
4482 * are to be omitted:
4483 *
4484 * f = File.open('t.txt')
4485 * # Chomp the lines.
4486 * f.gets(chomp: true) # => "First line"
4487 * f.gets(chomp: true) # => "Second line"
4488 * f.gets(chomp: true) # => ""
4489 * f.gets(chomp: true) # => "Fourth line"
4490 * f.gets(chomp: true) # => "Fifth line"
4491 * f.gets(chomp: true) # => nil
4492 * f.close
4493 *
4494 */
4495
4496static VALUE
4497rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4498{
4499 VALUE str;
4500
4501 str = rb_io_getline(argc, argv, io);
4502 rb_lastline_set(str);
4503
4504 return str;
4505}
4506
4507/*
4508 * call-seq:
4509 * lineno -> integer
4510 *
4511 * Returns the current line number for the stream;
4512 * see {Line Number}[rdoc-ref:IO@Line+Number].
4513 *
4514 */
4515
4516static VALUE
4517rb_io_lineno(VALUE io)
4518{
4519 rb_io_t *fptr;
4520
4521 GetOpenFile(io, fptr);
4523 return INT2NUM(fptr->lineno);
4524}
4525
4526/*
4527 * call-seq:
4528 * lineno = integer -> integer
4529 *
4530 * Sets and returns the line number for the stream;
4531 * see {Line Number}[rdoc-ref:IO@Line+Number].
4532 *
4533 */
4534
4535static VALUE
4536rb_io_set_lineno(VALUE io, VALUE lineno)
4537{
4538 rb_io_t *fptr;
4539
4540 GetOpenFile(io, fptr);
4542 fptr->lineno = NUM2INT(lineno);
4543 return lineno;
4544}
4545
4546/* :nodoc: */
4547static VALUE
4548io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4549{
4550 long limit = -1;
4551 if (NIL_P(lim)) {
4552 VALUE tmp = Qnil;
4553 // If sep is specified, but it's not a string and not nil, then assume
4554 // it's the limit (it should be an integer)
4555 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4556 // If the user has specified a non-nil / non-string value
4557 // for the separator, we assume it's the limit and set the
4558 // separator to default: rb_rs.
4559 lim = sep;
4560 limit = NUM2LONG(lim);
4561 sep = rb_rs;
4562 }
4563 else {
4564 sep = tmp;
4565 }
4566 }
4567 else {
4568 if (!NIL_P(sep)) StringValue(sep);
4569 limit = NUM2LONG(lim);
4570 }
4571
4572 check_getline_args(&sep, &limit, io);
4573
4574 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4575 rb_lastline_set_up(line, 1);
4576
4577 if (NIL_P(line)) {
4578 rb_eof_error();
4579 }
4580 return line;
4581}
4582
4583static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4584
4585/*
4586 * call-seq:
4587 * readlines(sep = $/, chomp: false) -> array
4588 * readlines(limit, chomp: false) -> array
4589 * readlines(sep, limit, chomp: false) -> array
4590 *
4591 * Reads and returns all remaining line from the stream;
4592 * does not modify <tt>$_</tt>.
4593 * See {Line IO}[rdoc-ref:IO@Line+IO].
4594 *
4595 * With no arguments given, returns lines
4596 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4597 *
4598 * f = File.new('t.txt')
4599 * f.readlines
4600 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4601 * f.readlines # => []
4602 * f.close
4603 *
4604 * With only string argument +sep+ given,
4605 * returns lines as determined by line separator +sep+,
4606 * or +nil+ if none;
4607 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4608 *
4609 * f = File.new('t.txt')
4610 * f.readlines('li')
4611 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4612 * f.close
4613 *
4614 * The two special values for +sep+ are honored:
4615 *
4616 * f = File.new('t.txt')
4617 * # Get all into one string.
4618 * f.readlines(nil)
4619 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4620 * # Get paragraphs (up to two line separators).
4621 * f.rewind
4622 * f.readlines('')
4623 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4624 * f.close
4625 *
4626 * With only integer argument +limit+ given,
4627 * limits the number of bytes in each line;
4628 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4629 *
4630 * f = File.new('t.txt')
4631 * f.readlines(8)
4632 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4633 * f.close
4634 *
4635 * With arguments +sep+ and +limit+ given,
4636 * combines the two behaviors
4637 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4638 *
4639 * Optional keyword argument +chomp+ specifies whether line separators
4640 * are to be omitted:
4641 *
4642 * f = File.new('t.txt')
4643 * f.readlines(chomp: true)
4644 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4645 * f.close
4646 *
4647 */
4648
4649static VALUE
4650rb_io_readlines(int argc, VALUE *argv, VALUE io)
4651{
4652 struct getline_arg args;
4653
4654 prepare_getline_args(argc, argv, &args, io);
4655 return io_readlines(&args, io);
4656}
4657
4658static VALUE
4659io_readlines(const struct getline_arg *arg, VALUE io)
4660{
4661 VALUE line, ary;
4662
4663 if (arg->limit == 0)
4664 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4665 ary = rb_ary_new();
4666 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4667 rb_ary_push(ary, line);
4668 }
4669 return ary;
4670}
4671
4672/*
4673 * call-seq:
4674 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4675 * each_line(limit, chomp: false) {|line| ... } -> self
4676 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4677 * each_line -> enumerator
4678 *
4679 * Calls the block with each remaining line read from the stream;
4680 * returns +self+.
4681 * Does nothing if already at end-of-stream;
4682 * See {Line IO}[rdoc-ref:IO@Line+IO].
4683 *
4684 * With no arguments given, reads lines
4685 * as determined by line separator <tt>$/</tt>:
4686 *
4687 * f = File.new('t.txt')
4688 * f.each_line {|line| p line }
4689 * f.each_line {|line| fail 'Cannot happen' }
4690 * f.close
4691 *
4692 * Output:
4693 *
4694 * "First line\n"
4695 * "Second line\n"
4696 * "\n"
4697 * "Fourth line\n"
4698 * "Fifth line\n"
4699 *
4700 * With only string argument +sep+ given,
4701 * reads lines as determined by line separator +sep+;
4702 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4703 *
4704 * f = File.new('t.txt')
4705 * f.each_line('li') {|line| p line }
4706 * f.close
4707 *
4708 * Output:
4709 *
4710 * "First li"
4711 * "ne\nSecond li"
4712 * "ne\n\nFourth li"
4713 * "ne\nFifth li"
4714 * "ne\n"
4715 *
4716 * The two special values for +sep+ are honored:
4717 *
4718 * f = File.new('t.txt')
4719 * # Get all into one string.
4720 * f.each_line(nil) {|line| p line }
4721 * f.close
4722 *
4723 * Output:
4724 *
4725 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4726 *
4727 * f.rewind
4728 * # Get paragraphs (up to two line separators).
4729 * f.each_line('') {|line| p line }
4730 *
4731 * Output:
4732 *
4733 * "First line\nSecond line\n\n"
4734 * "Fourth line\nFifth line\n"
4735 *
4736 * With only integer argument +limit+ given,
4737 * limits the number of bytes in each line;
4738 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4739 *
4740 * f = File.new('t.txt')
4741 * f.each_line(8) {|line| p line }
4742 * f.close
4743 *
4744 * Output:
4745 *
4746 * "First li"
4747 * "ne\n"
4748 * "Second l"
4749 * "ine\n"
4750 * "\n"
4751 * "Fourth l"
4752 * "ine\n"
4753 * "Fifth li"
4754 * "ne\n"
4755 *
4756 * With arguments +sep+ and +limit+ given,
4757 * combines the two behaviors
4758 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4759 *
4760 * Optional keyword argument +chomp+ specifies whether line separators
4761 * are to be omitted:
4762 *
4763 * f = File.new('t.txt')
4764 * f.each_line(chomp: true) {|line| p line }
4765 * f.close
4766 *
4767 * Output:
4768 *
4769 * "First line"
4770 * "Second line"
4771 * ""
4772 * "Fourth line"
4773 * "Fifth line"
4774 *
4775 * Returns an Enumerator if no block is given.
4776 */
4777
4778static VALUE
4779rb_io_each_line(int argc, VALUE *argv, VALUE io)
4780{
4781 VALUE str;
4782 struct getline_arg args;
4783
4784 RETURN_ENUMERATOR(io, argc, argv);
4785 prepare_getline_args(argc, argv, &args, io);
4786 if (args.limit == 0)
4787 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4788 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4789 rb_yield(str);
4790 }
4791 return io;
4792}
4793
4794/*
4795 * call-seq:
4796 * each_byte {|byte| ... } -> self
4797 * each_byte -> enumerator
4798 *
4799 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4800 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4801 *
4802 * File.read('t.ja') # => "こんにちは"
4803 * f = File.new('t.ja')
4804 * a = []
4805 * f.each_byte {|b| a << b }
4806 * a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
4807 * f.close
4808 *
4809 * Returns an Enumerator if no block is given.
4810 *
4811 * Related: IO#each_char, IO#each_codepoint.
4812 *
4813 */
4814
4815static VALUE
4816rb_io_each_byte(VALUE io)
4817{
4818 rb_io_t *fptr;
4819
4820 RETURN_ENUMERATOR(io, 0, 0);
4821 GetOpenFile(io, fptr);
4822
4823 do {
4824 while (fptr->rbuf.len > 0) {
4825 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4826 fptr->rbuf.len--;
4827 rb_yield(INT2FIX(*p & 0xff));
4829 errno = 0;
4830 }
4831 READ_CHECK(fptr);
4832 } while (io_fillbuf(fptr) >= 0);
4833 return io;
4834}
4835
4836static VALUE
4837io_getc(rb_io_t *fptr, rb_encoding *enc)
4838{
4839 int r, n, cr = 0;
4840 VALUE str;
4841
4842 if (NEED_READCONV(fptr)) {
4843 rb_encoding *read_enc = io_read_encoding(fptr);
4844
4845 str = Qnil;
4846 SET_BINARY_MODE(fptr);
4847 make_readconv(fptr, 0);
4848
4849 while (1) {
4850 if (fptr->cbuf.len) {
4851 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4852 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4853 read_enc);
4854 if (!MBCLEN_NEEDMORE_P(r))
4855 break;
4856 if (fptr->cbuf.len == fptr->cbuf.capa) {
4857 rb_raise(rb_eIOError, "too long character");
4858 }
4859 }
4860
4861 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4862 if (fptr->cbuf.len == 0) {
4863 clear_readconv(fptr);
4864 return Qnil;
4865 }
4866 /* return an unit of an incomplete character just before EOF */
4867 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4868 fptr->cbuf.off += 1;
4869 fptr->cbuf.len -= 1;
4870 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4872 return str;
4873 }
4874 }
4875 if (MBCLEN_INVALID_P(r)) {
4876 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4877 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4878 read_enc);
4879 io_shift_cbuf(fptr, r, &str);
4881 }
4882 else {
4883 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4885 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4886 ISASCII(RSTRING_PTR(str)[0])) {
4887 cr = ENC_CODERANGE_7BIT;
4888 }
4889 }
4890 str = io_enc_str(str, fptr);
4891 ENC_CODERANGE_SET(str, cr);
4892 return str;
4893 }
4894
4895 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4896 if (io_fillbuf(fptr) < 0) {
4897 return Qnil;
4898 }
4899 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4900 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4901 fptr->rbuf.off += 1;
4902 fptr->rbuf.len -= 1;
4903 cr = ENC_CODERANGE_7BIT;
4904 }
4905 else {
4906 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4907 if (MBCLEN_CHARFOUND_P(r) &&
4908 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4909 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4910 fptr->rbuf.off += n;
4911 fptr->rbuf.len -= n;
4913 }
4914 else if (MBCLEN_NEEDMORE_P(r)) {
4915 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4916 fptr->rbuf.len = 0;
4917 getc_needmore:
4918 if (io_fillbuf(fptr) != -1) {
4919 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4920 fptr->rbuf.off++;
4921 fptr->rbuf.len--;
4922 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4923 if (MBCLEN_NEEDMORE_P(r)) {
4924 goto getc_needmore;
4925 }
4926 else if (MBCLEN_CHARFOUND_P(r)) {
4928 }
4929 }
4930 }
4931 else {
4932 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4933 fptr->rbuf.off++;
4934 fptr->rbuf.len--;
4935 }
4936 }
4937 if (!cr) cr = ENC_CODERANGE_BROKEN;
4938 str = io_enc_str(str, fptr);
4939 ENC_CODERANGE_SET(str, cr);
4940 return str;
4941}
4942
4943/*
4944 * call-seq:
4945 * each_char {|c| ... } -> self
4946 * each_char -> enumerator
4947 *
4948 * Calls the given block with each character in the stream; returns +self+.
4949 * See {Character IO}[rdoc-ref:IO@Character+IO].
4950 *
4951 * File.read('t.ja') # => "こんにちは"
4952 * f = File.new('t.ja')
4953 * a = []
4954 * f.each_char {|c| a << c.ord }
4955 * a # => [12371, 12435, 12395, 12385, 12399]
4956 * f.close
4957 *
4958 * Returns an Enumerator if no block is given.
4959 *
4960 * Related: IO#each_byte, IO#each_codepoint.
4961 *
4962 */
4963
4964static VALUE
4965rb_io_each_char(VALUE io)
4966{
4967 rb_io_t *fptr;
4968 rb_encoding *enc;
4969 VALUE c;
4970
4971 RETURN_ENUMERATOR(io, 0, 0);
4972 GetOpenFile(io, fptr);
4974
4975 enc = io_input_encoding(fptr);
4976 READ_CHECK(fptr);
4977 while (!NIL_P(c = io_getc(fptr, enc))) {
4978 rb_yield(c);
4979 }
4980 return io;
4981}
4982
4983/*
4984 * call-seq:
4985 * each_codepoint {|c| ... } -> self
4986 * each_codepoint -> enumerator
4987 *
4988 * Calls the given block with each codepoint in the stream; returns +self+:
4989 *
4990 * File.read('t.ja') # => "こんにちは"
4991 * f = File.new('t.ja')
4992 * a = []
4993 * f.each_codepoint {|c| a << c }
4994 * a # => [12371, 12435, 12395, 12385, 12399]
4995 * f.close
4996 *
4997 * Returns an Enumerator if no block is given.
4998 *
4999 * Related: IO#each_byte, IO#each_char.
5000 *
5001 */
5002
5003static VALUE
5004rb_io_each_codepoint(VALUE io)
5005{
5006 rb_io_t *fptr;
5007 rb_encoding *enc;
5008 unsigned int c;
5009 int r, n;
5010
5011 RETURN_ENUMERATOR(io, 0, 0);
5012 GetOpenFile(io, fptr);
5014
5015 READ_CHECK(fptr);
5016 enc = io_read_encoding(fptr);
5017 if (NEED_READCONV(fptr)) {
5018 SET_BINARY_MODE(fptr);
5019 r = 1; /* no invalid char yet */
5020 for (;;) {
5021 make_readconv(fptr, 0);
5022 for (;;) {
5023 if (fptr->cbuf.len) {
5024 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
5025 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5026 enc);
5027 if (!MBCLEN_NEEDMORE_P(r))
5028 break;
5029 if (fptr->cbuf.len == fptr->cbuf.capa) {
5030 rb_raise(rb_eIOError, "too long character");
5031 }
5032 }
5033 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5034 clear_readconv(fptr);
5035 if (!MBCLEN_CHARFOUND_P(r)) {
5036 goto invalid;
5037 }
5038 return io;
5039 }
5040 }
5041 if (MBCLEN_INVALID_P(r)) {
5042 goto invalid;
5043 }
5044 n = MBCLEN_CHARFOUND_LEN(r);
5045 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
5046 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5047 enc);
5048 fptr->cbuf.off += n;
5049 fptr->cbuf.len -= n;
5050 rb_yield(UINT2NUM(c));
5052 }
5053 }
5054 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5055 while (io_fillbuf(fptr) >= 0) {
5056 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
5057 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5058 if (MBCLEN_CHARFOUND_P(r) &&
5059 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
5060 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
5061 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5062 fptr->rbuf.off += n;
5063 fptr->rbuf.len -= n;
5064 rb_yield(UINT2NUM(c));
5065 }
5066 else if (MBCLEN_INVALID_P(r)) {
5067 goto invalid;
5068 }
5069 else if (MBCLEN_NEEDMORE_P(r)) {
5070 char cbuf[8], *p = cbuf;
5071 int more = MBCLEN_NEEDMORE_LEN(r);
5072 if (more > numberof(cbuf)) goto invalid;
5073 more += n = fptr->rbuf.len;
5074 if (more > numberof(cbuf)) goto invalid;
5075 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
5076 (p += n, (more -= n) > 0)) {
5077 if (io_fillbuf(fptr) < 0) goto invalid;
5078 if ((n = fptr->rbuf.len) > more) n = more;
5079 }
5080 r = rb_enc_precise_mbclen(cbuf, p, enc);
5081 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
5082 c = rb_enc_codepoint(cbuf, p, enc);
5083 rb_yield(UINT2NUM(c));
5084 }
5085 else {
5086 continue;
5087 }
5089 }
5090 return io;
5091
5092 invalid:
5093 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
5095}
5096
5097/*
5098 * call-seq:
5099 * getc -> character or nil
5100 *
5101 * Reads and returns the next 1-character string from the stream;
5102 * returns +nil+ if already at end-of-stream.
5103 * See {Character IO}[rdoc-ref:IO@Character+IO].
5104 *
5105 * f = File.open('t.txt')
5106 * f.getc # => "F"
5107 * f.close
5108 * File.read('t.ja') # => "こんにちは"
5109 * f = File.open('t.ja')
5110 * f.getc.ord # => 12371
5111 * f.close
5112 *
5113 * Related: IO#readchar (may raise EOFError).
5114 *
5115 */
5116
5117static VALUE
5118rb_io_getc(VALUE io)
5119{
5120 rb_io_t *fptr;
5121 rb_encoding *enc;
5122
5123 GetOpenFile(io, fptr);
5125
5126 enc = io_input_encoding(fptr);
5127 READ_CHECK(fptr);
5128 return io_getc(fptr, enc);
5129}
5130
5131/*
5132 * call-seq:
5133 * readchar -> string
5134 *
5135 * Reads and returns the next 1-character string from the stream;
5136 * raises EOFError if already at end-of-stream.
5137 * See {Character IO}[rdoc-ref:IO@Character+IO].
5138 *
5139 * f = File.open('t.txt')
5140 * f.readchar # => "F"
5141 * f.close
5142 * File.read('t.ja') # => "こんにちは"
5143 * f = File.open('t.ja')
5144 * f.readchar.ord # => 12371
5145 * f.close
5146 *
5147 * Related: IO#getc (will not raise EOFError).
5148 *
5149 */
5150
5151static VALUE
5152rb_io_readchar(VALUE io)
5153{
5154 VALUE c = rb_io_getc(io);
5155
5156 if (NIL_P(c)) {
5157 rb_eof_error();
5158 }
5159 return c;
5160}
5161
5162/*
5163 * call-seq:
5164 * getbyte -> integer or nil
5165 *
5166 * Reads and returns the next byte (in range 0..255) from the stream;
5167 * returns +nil+ if already at end-of-stream.
5168 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5169 *
5170 * f = File.open('t.txt')
5171 * f.getbyte # => 70
5172 * f.close
5173 * File.read('t.ja') # => "こんにちは"
5174 * f = File.open('t.ja')
5175 * f.getbyte # => 227
5176 * f.close
5177 *
5178 * Related: IO#readbyte (may raise EOFError).
5179 */
5180
5181VALUE
5183{
5184 rb_io_t *fptr;
5185 int c;
5186
5187 GetOpenFile(io, fptr);
5189 READ_CHECK(fptr);
5190 VALUE r_stdout = rb_ractor_stdout();
5191 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5192 rb_io_t *ofp;
5193 GetOpenFile(r_stdout, ofp);
5194 if (ofp->mode & FMODE_TTY) {
5195 rb_io_flush(r_stdout);
5196 }
5197 }
5198 if (io_fillbuf(fptr) < 0) {
5199 return Qnil;
5200 }
5201 fptr->rbuf.off++;
5202 fptr->rbuf.len--;
5203 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5204 return INT2FIX(c & 0xff);
5205}
5206
5207/*
5208 * call-seq:
5209 * readbyte -> integer
5210 *
5211 * Reads and returns the next byte (in range 0..255) from the stream;
5212 * raises EOFError if already at end-of-stream.
5213 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5214 *
5215 * f = File.open('t.txt')
5216 * f.readbyte # => 70
5217 * f.close
5218 * File.read('t.ja') # => "こんにちは"
5219 * f = File.open('t.ja')
5220 * f.readbyte # => 227
5221 * f.close
5222 *
5223 * Related: IO#getbyte (will not raise EOFError).
5224 *
5225 */
5226
5227static VALUE
5228rb_io_readbyte(VALUE io)
5229{
5230 VALUE c = rb_io_getbyte(io);
5231
5232 if (NIL_P(c)) {
5233 rb_eof_error();
5234 }
5235 return c;
5236}
5237
5238/*
5239 * call-seq:
5240 * ungetbyte(integer) -> nil
5241 * ungetbyte(string) -> nil
5242 *
5243 * Pushes back ("unshifts") the given data onto the stream's buffer,
5244 * placing the data so that it is next to be read; returns +nil+.
5245 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5246 *
5247 * Note that:
5248 *
5249 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5250 * - Calling #rewind on the stream discards the pushed-back data.
5251 *
5252 * When argument +integer+ is given, uses only its low-order byte:
5253 *
5254 * File.write('t.tmp', '012')
5255 * f = File.open('t.tmp')
5256 * f.ungetbyte(0x41) # => nil
5257 * f.read # => "A012"
5258 * f.rewind
5259 * f.ungetbyte(0x4243) # => nil
5260 * f.read # => "C012"
5261 * f.close
5262 *
5263 * When argument +string+ is given, uses all bytes:
5264 *
5265 * File.write('t.tmp', '012')
5266 * f = File.open('t.tmp')
5267 * f.ungetbyte('A') # => nil
5268 * f.read # => "A012"
5269 * f.rewind
5270 * f.ungetbyte('BCDE') # => nil
5271 * f.read # => "BCDE012"
5272 * f.close
5273 *
5274 */
5275
5276VALUE
5278{
5279 rb_io_t *fptr;
5280
5281 GetOpenFile(io, fptr);
5283 switch (TYPE(b)) {
5284 case T_NIL:
5285 return Qnil;
5286 case T_FIXNUM:
5287 case T_BIGNUM: ;
5288 VALUE v = rb_int_modulo(b, INT2FIX(256));
5289 unsigned char c = NUM2INT(v) & 0xFF;
5290 b = rb_str_new((const char *)&c, 1);
5291 break;
5292 default:
5293 StringValue(b);
5294 }
5295 io_ungetbyte(b, fptr);
5296 return Qnil;
5297}
5298
5299/*
5300 * call-seq:
5301 * ungetc(integer) -> nil
5302 * ungetc(string) -> nil
5303 *
5304 * Pushes back ("unshifts") the given data onto the stream's buffer,
5305 * placing the data so that it is next to be read; returns +nil+.
5306 * See {Character IO}[rdoc-ref:IO@Character+IO].
5307 *
5308 * Note that:
5309 *
5310 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5311 * - Calling #rewind on the stream discards the pushed-back data.
5312 *
5313 * When argument +integer+ is given, interprets the integer as a character:
5314 *
5315 * File.write('t.tmp', '012')
5316 * f = File.open('t.tmp')
5317 * f.ungetc(0x41) # => nil
5318 * f.read # => "A012"
5319 * f.rewind
5320 * f.ungetc(0x0442) # => nil
5321 * f.getc.ord # => 1090
5322 * f.close
5323 *
5324 * When argument +string+ is given, uses all characters:
5325 *
5326 * File.write('t.tmp', '012')
5327 * f = File.open('t.tmp')
5328 * f.ungetc('A') # => nil
5329 * f.read # => "A012"
5330 * f.rewind
5331 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5332 * f.getc.ord # => 1090
5333 * f.getc.ord # => 1077
5334 * f.getc.ord # => 1089
5335 * f.getc.ord # => 1090
5336 * f.close
5337 *
5338 */
5339
5340VALUE
5342{
5343 rb_io_t *fptr;
5344 long len;
5345
5346 GetOpenFile(io, fptr);
5348 if (FIXNUM_P(c)) {
5349 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5350 }
5351 else if (RB_BIGNUM_TYPE_P(c)) {
5352 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5353 }
5354 else {
5355 StringValue(c);
5356 }
5357 if (NEED_READCONV(fptr)) {
5358 SET_BINARY_MODE(fptr);
5359 len = RSTRING_LEN(c);
5360#if SIZEOF_LONG > SIZEOF_INT
5361 if (len > INT_MAX)
5362 rb_raise(rb_eIOError, "ungetc failed");
5363#endif
5364 make_readconv(fptr, (int)len);
5365 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5366 rb_raise(rb_eIOError, "ungetc failed");
5367 if (fptr->cbuf.off < len) {
5368 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5369 fptr->cbuf.ptr+fptr->cbuf.off,
5370 char, fptr->cbuf.len);
5371 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5372 }
5373 fptr->cbuf.off -= (int)len;
5374 fptr->cbuf.len += (int)len;
5375 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5376 }
5377 else {
5378 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5379 io_ungetbyte(c, fptr);
5380 }
5381 return Qnil;
5382}
5383
5384/*
5385 * call-seq:
5386 * isatty -> true or false
5387 *
5388 * Returns +true+ if the stream is associated with a terminal device (tty),
5389 * +false+ otherwise:
5390 *
5391 * f = File.new('t.txt').isatty #=> false
5392 * f.close
5393 * f = File.new('/dev/tty').isatty #=> true
5394 * f.close
5395 *
5396 */
5397
5398static VALUE
5399rb_io_isatty(VALUE io)
5400{
5401 rb_io_t *fptr;
5402
5403 GetOpenFile(io, fptr);
5404 return RBOOL(isatty(fptr->fd) != 0);
5405}
5406
5407#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5408/*
5409 * call-seq:
5410 * close_on_exec? -> true or false
5411 *
5412 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5413 *
5414 * f = File.open('t.txt')
5415 * f.close_on_exec? # => true
5416 * f.close_on_exec = false
5417 * f.close_on_exec? # => false
5418 * f.close
5419 *
5420 */
5421
5422static VALUE
5423rb_io_close_on_exec_p(VALUE io)
5424{
5425 rb_io_t *fptr;
5426 VALUE write_io;
5427 int fd, ret;
5428
5429 write_io = GetWriteIO(io);
5430 if (io != write_io) {
5431 GetOpenFile(write_io, fptr);
5432 if (fptr && 0 <= (fd = fptr->fd)) {
5433 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5434 if (!(ret & FD_CLOEXEC)) return Qfalse;
5435 }
5436 }
5437
5438 GetOpenFile(io, fptr);
5439 if (fptr && 0 <= (fd = fptr->fd)) {
5440 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5441 if (!(ret & FD_CLOEXEC)) return Qfalse;
5442 }
5443 return Qtrue;
5444}
5445#else
5446#define rb_io_close_on_exec_p rb_f_notimplement
5447#endif
5448
5449#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5450/*
5451 * call-seq:
5452 * self.close_on_exec = bool -> true or false
5453 *
5454 * Sets a close-on-exec flag.
5455 *
5456 * f = File.open(File::NULL)
5457 * f.close_on_exec = true
5458 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5459 * f.closed? #=> false
5460 *
5461 * Ruby sets close-on-exec flags of all file descriptors by default
5462 * since Ruby 2.0.0.
5463 * So you don't need to set by yourself.
5464 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5465 * if another thread use fork() and exec() (via system() method for example).
5466 * If you really needs file descriptor inheritance to child process,
5467 * use spawn()'s argument such as fd=>fd.
5468 */
5469
5470static VALUE
5471rb_io_set_close_on_exec(VALUE io, VALUE arg)
5472{
5473 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5474 rb_io_t *fptr;
5475 VALUE write_io;
5476 int fd, ret;
5477
5478 write_io = GetWriteIO(io);
5479 if (io != write_io) {
5480 GetOpenFile(write_io, fptr);
5481 if (fptr && 0 <= (fd = fptr->fd)) {
5482 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5483 if ((ret & FD_CLOEXEC) != flag) {
5484 ret = (ret & ~FD_CLOEXEC) | flag;
5485 ret = fcntl(fd, F_SETFD, ret);
5486 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5487 }
5488 }
5489
5490 }
5491
5492 GetOpenFile(io, fptr);
5493 if (fptr && 0 <= (fd = fptr->fd)) {
5494 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5495 if ((ret & FD_CLOEXEC) != flag) {
5496 ret = (ret & ~FD_CLOEXEC) | flag;
5497 ret = fcntl(fd, F_SETFD, ret);
5498 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5499 }
5500 }
5501 return Qnil;
5502}
5503#else
5504#define rb_io_set_close_on_exec rb_f_notimplement
5505#endif
5506
5507#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5508#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5509
5510static VALUE
5511finish_writeconv(rb_io_t *fptr, int noalloc)
5512{
5513 unsigned char *ds, *dp, *de;
5515
5516 if (!fptr->wbuf.ptr) {
5517 unsigned char buf[1024];
5518
5520 while (res == econv_destination_buffer_full) {
5521 ds = dp = buf;
5522 de = buf + sizeof(buf);
5523 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5524 while (dp-ds) {
5525 size_t remaining = dp-ds;
5526 long result = rb_io_write_memory(fptr, ds, remaining);
5527
5528 if (result > 0) {
5529 ds += result;
5530 if ((size_t)result == remaining) break;
5531 }
5532 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5533 if (fptr->fd < 0)
5534 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5535 }
5536 else {
5537 return noalloc ? Qtrue : INT2NUM(errno);
5538 }
5539 }
5540 if (res == econv_invalid_byte_sequence ||
5541 res == econv_incomplete_input ||
5543 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5544 }
5545 }
5546
5547 return Qnil;
5548 }
5549
5551 while (res == econv_destination_buffer_full) {
5552 if (fptr->wbuf.len == fptr->wbuf.capa) {
5553 if (io_fflush(fptr) < 0) {
5554 return noalloc ? Qtrue : INT2NUM(errno);
5555 }
5556 }
5557
5558 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5559 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5560 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5561 fptr->wbuf.len += (int)(dp - ds);
5562 if (res == econv_invalid_byte_sequence ||
5563 res == econv_incomplete_input ||
5565 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5566 }
5567 }
5568 return Qnil;
5569}
5570
5572 rb_io_t *fptr;
5573 int noalloc;
5574};
5575
5576static VALUE
5577finish_writeconv_sync(VALUE arg)
5578{
5579 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5580 return finish_writeconv(p->fptr, p->noalloc);
5581}
5582
5583static void*
5584nogvl_close(void *ptr)
5585{
5586 int *fd = ptr;
5587
5588 return (void*)(intptr_t)close(*fd);
5589}
5590
5591static int
5592maygvl_close(int fd, int keepgvl)
5593{
5594 if (keepgvl)
5595 return close(fd);
5596
5597 /*
5598 * close() may block for certain file types (NFS, SO_LINGER sockets,
5599 * inotify), so let other threads run.
5600 */
5601 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5602}
5603
5604static void*
5605nogvl_fclose(void *ptr)
5606{
5607 FILE *file = ptr;
5608
5609 return (void*)(intptr_t)fclose(file);
5610}
5611
5612static int
5613maygvl_fclose(FILE *file, int keepgvl)
5614{
5615 if (keepgvl)
5616 return fclose(file);
5617
5618 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5619}
5620
5621static void free_io_buffer(rb_io_buffer_t *buf);
5622
5623static void
5624fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5625{
5626 VALUE error = Qnil;
5627 int fd = fptr->fd;
5628 FILE *stdio_file = fptr->stdio_file;
5629 int mode = fptr->mode;
5630
5631 if (fptr->writeconv) {
5632 if (!NIL_P(fptr->write_lock) && !noraise) {
5633 struct finish_writeconv_arg arg;
5634 arg.fptr = fptr;
5635 arg.noalloc = noraise;
5636 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5637 }
5638 else {
5639 error = finish_writeconv(fptr, noraise);
5640 }
5641 }
5642 /* Do not flush the write buffer on close when the stream is in sync
5643 * mode. In sync mode Ruby's write buffer is not authoritative (writes go
5644 * straight to the OS), so any bytes left in the buffer are the result of
5645 * writes made while sync was disabled. Setting sync = true is therefore a
5646 * way to abandon that pending output rather than replaying it on close,
5647 * which matters after an interrupted write where the amount actually
5648 * written is indeterminate. Call flush before enabling sync if the
5649 * buffered data should still be sent. */
5650 if (fptr->wbuf.len && !(fptr->mode & FMODE_SYNC)) {
5651 if (noraise) {
5652 io_flush_buffer_sync(fptr);
5653 }
5654 else {
5655 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5656 error = INT2NUM(errno);
5657 }
5658 }
5659 }
5660
5661 int done = 0;
5662
5663 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5664 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5665 done = 1;
5666 }
5667
5668 fptr->fd = -1;
5669 fptr->stdio_file = 0;
5671
5672 // Wait for blocking operations to ensure they do not hit EBADF:
5673 rb_thread_io_close_wait(fptr);
5674
5675 if (!done && stdio_file) {
5676 // stdio_file is deallocated anyway even if fclose failed.
5677 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5678 if (!noraise) {
5679 error = INT2NUM(errno);
5680 }
5681 }
5682
5683 done = 1;
5684 }
5685
5686 VALUE scheduler = rb_fiber_scheduler_current();
5687 if (!done && fd >= 0 && scheduler != Qnil) {
5688 VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
5689
5690 if (!UNDEF_P(result)) {
5691 done = RTEST(result);
5692 }
5693 }
5694
5695 if (!done && fd >= 0) {
5696 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5697 // We assumes it is closed.
5698
5699 keepgvl |= !(mode & FMODE_WRITABLE);
5700 keepgvl |= noraise;
5701 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5702 if (!noraise) {
5703 error = INT2NUM(errno);
5704 }
5705 }
5706
5707 done = 1;
5708 }
5709
5710 if (!NIL_P(error) && !noraise) {
5711 if (RB_INTEGER_TYPE_P(error))
5712 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5713 else
5714 rb_exc_raise(error);
5715 }
5716}
5717
5718static void
5719fptr_finalize(rb_io_t *fptr, int noraise)
5720{
5721 fptr_finalize_flush(fptr, noraise, FALSE);
5722 free_io_buffer(&fptr->rbuf);
5723 free_io_buffer(&fptr->wbuf);
5724 clear_codeconv(fptr);
5725}
5726
5727static void
5728rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5729{
5730 if (fptr->finalize) {
5731 (*fptr->finalize)(fptr, noraise);
5732 }
5733 else {
5734 fptr_finalize(fptr, noraise);
5735 }
5736}
5737
5738static void
5739free_io_buffer(rb_io_buffer_t *buf)
5740{
5741 if (buf->ptr) {
5742 ruby_xfree_sized(buf->ptr, (size_t)buf->capa);
5743 buf->ptr = NULL;
5744 }
5745 buf->off = buf->len = buf->capa = 0;
5746}
5747
5748static void
5749clear_readconv(rb_io_t *fptr)
5750{
5751 if (fptr->readconv) {
5752 rb_econv_close(fptr->readconv);
5753 fptr->readconv = NULL;
5754 }
5755 free_io_buffer(&fptr->cbuf);
5756}
5757
5758static void
5759clear_writeconv(rb_io_t *fptr)
5760{
5761 if (fptr->writeconv) {
5763 fptr->writeconv = NULL;
5764 }
5765 fptr->writeconv_initialized = 0;
5766}
5767
5768static void
5769clear_codeconv(rb_io_t *fptr)
5770{
5771 clear_readconv(fptr);
5772 clear_writeconv(fptr);
5773}
5774
5775static void
5776rb_io_fptr_cleanup_all(rb_io_t *fptr)
5777{
5778 fptr->pathv = Qnil;
5779 if (0 <= fptr->fd)
5780 rb_io_fptr_cleanup(fptr, TRUE);
5781 fptr->write_lock = Qnil;
5782 free_io_buffer(&fptr->rbuf);
5783 free_io_buffer(&fptr->wbuf);
5784 clear_codeconv(fptr);
5785}
5786
5787int
5789{
5790 if (!io) return 0;
5791 rb_io_fptr_cleanup_all(io);
5792 free(io);
5793
5794 return 1;
5795}
5796
5797bool
5798rb_io_fptr_finalize_closed(struct rb_io *io)
5799{
5800 if (!io) return true;
5801 if (io->fd >= 0) return false;
5803 return true;
5804}
5805
5806size_t
5807rb_io_memsize(const rb_io_t *io)
5808{
5809 size_t size = sizeof(rb_io_t);
5810 size += io->rbuf.capa;
5811 size += io->wbuf.capa;
5812 size += io->cbuf.capa;
5813 if (io->readconv) size += rb_econv_memsize(io->readconv);
5814 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5815
5816 struct rb_io_blocking_operation *blocking_operation = 0;
5817
5818 // 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.
5819 rb_serial_t fork_generation = GET_VM()->fork_gen;
5820 if (io->fork_generation == fork_generation) {
5821 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5822 size += sizeof(struct rb_io_blocking_operation);
5823 }
5824 }
5825
5826 return size;
5827}
5828
5829#ifdef _WIN32
5830/* keep GVL while closing to prevent crash on Windows */
5831# define KEEPGVL TRUE
5832#else
5833# define KEEPGVL FALSE
5834#endif
5835
5836static rb_io_t *
5837io_close_fptr(VALUE io)
5838{
5839 rb_io_t *fptr;
5840 VALUE write_io;
5841 rb_io_t *write_fptr;
5842
5843 write_io = GetWriteIO(io);
5844 if (io != write_io) {
5845 write_fptr = RFILE(write_io)->fptr;
5846 if (write_fptr && 0 <= write_fptr->fd) {
5847 rb_io_fptr_cleanup(write_fptr, TRUE);
5848 }
5849 }
5850
5851 fptr = RFILE(io)->fptr;
5852 if (!fptr) return 0;
5853 if (fptr->fd < 0) return 0;
5854
5855 // This guards against multiple threads closing the same IO object:
5856 if (rb_thread_io_close_interrupt(fptr)) {
5857 /* calls close(fptr->fd): */
5858 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5859 }
5860
5861 rb_io_fptr_cleanup(fptr, FALSE);
5862 return fptr;
5863}
5864
5865static void
5866fptr_waitpid(rb_io_t *fptr, int nohang)
5867{
5868 int status;
5869 if (fptr->pid) {
5870 rb_last_status_clear();
5871 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5872 fptr->pid = 0;
5873 }
5874}
5875
5876VALUE
5878{
5879 rb_io_t *fptr = io_close_fptr(io);
5880 if (fptr) fptr_waitpid(fptr, 0);
5881 return Qnil;
5882}
5883
5884/*
5885 * call-seq:
5886 * close -> nil
5887 *
5888 * Closes the stream for both reading and writing
5889 * if open for either or both; returns +nil+.
5890 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5891 *
5892 * If the stream is open for writing, flushes any buffered writes
5893 * to the operating system before closing.
5894 *
5895 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5896 * (child exit status).
5897 *
5898 * It is not an error to close an IO object that has already been closed.
5899 * It just returns nil.
5900 *
5901 * Example:
5902 *
5903 * IO.popen('ruby', 'r+') do |pipe|
5904 * puts pipe.closed?
5905 * pipe.close
5906 * puts $?
5907 * puts pipe.closed?
5908 * end
5909 *
5910 * Output:
5911 *
5912 * false
5913 * pid 13760 exit 0
5914 * true
5915 *
5916 * Related: IO#close_read, IO#close_write, IO#closed?.
5917 */
5918
5919static VALUE
5920rb_io_close_m(VALUE io)
5921{
5922 rb_io_t *fptr = rb_io_get_fptr(io);
5923 if (fptr->fd < 0) {
5924 return Qnil;
5925 }
5926 rb_io_close(io);
5927 return Qnil;
5928}
5929
5930static VALUE
5931io_call_close(VALUE io)
5932{
5933 rb_check_funcall(io, rb_intern("close"), 0, 0);
5934 return io;
5935}
5936
5937static VALUE
5938ignore_closed_stream(VALUE io, VALUE exc)
5939{
5940 enum {mesg_len = sizeof(closed_stream)-1};
5941 VALUE mesg = rb_attr_get(exc, idMesg);
5942 if (!RB_TYPE_P(mesg, T_STRING) ||
5943 RSTRING_LEN(mesg) != mesg_len ||
5944 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5945 rb_exc_raise(exc);
5946 }
5947 return io;
5948}
5949
5950static VALUE
5951io_close(VALUE io)
5952{
5953 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5954 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5955 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5956 rb_eIOError, (VALUE)0);
5957 return io;
5958}
5959
5960/*
5961 * call-seq:
5962 * closed? -> true or false
5963 *
5964 * Returns +true+ if the stream is closed for both reading and writing,
5965 * +false+ otherwise.
5966 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5967 *
5968 * IO.popen('ruby', 'r+') do |pipe|
5969 * puts pipe.closed?
5970 * pipe.close_read
5971 * puts pipe.closed?
5972 * pipe.close_write
5973 * puts pipe.closed?
5974 * end
5975 *
5976 * Output:
5977 *
5978 * false
5979 * false
5980 * true
5981 *
5982 * Related: IO#close_read, IO#close_write, IO#close.
5983 */
5984VALUE
5986{
5987 rb_io_t *fptr;
5988 VALUE write_io;
5989 rb_io_t *write_fptr;
5990
5991 write_io = GetWriteIO(io);
5992 if (io != write_io) {
5993 write_fptr = RFILE(write_io)->fptr;
5994 if (write_fptr && 0 <= write_fptr->fd) {
5995 return Qfalse;
5996 }
5997 }
5998
5999 fptr = rb_io_get_fptr(io);
6000 return RBOOL(0 > fptr->fd);
6001}
6002
6003/*
6004 * call-seq:
6005 * close_read -> nil
6006 *
6007 * Closes the stream for reading if open for reading;
6008 * returns +nil+.
6009 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6010 *
6011 * If the stream was opened by IO.popen and is also closed for writing,
6012 * sets global variable <tt>$?</tt> (child exit status).
6013 *
6014 * Example:
6015 *
6016 * IO.popen('ruby', 'r+') do |pipe|
6017 * puts pipe.closed?
6018 * pipe.close_write
6019 * puts pipe.closed?
6020 * pipe.close_read
6021 * puts $?
6022 * puts pipe.closed?
6023 * end
6024 *
6025 * Output:
6026 *
6027 * false
6028 * false
6029 * pid 14748 exit 0
6030 * true
6031 *
6032 * Related: IO#close, IO#close_write, IO#closed?.
6033 */
6034
6035static VALUE
6036rb_io_close_read(VALUE io)
6037{
6038 rb_io_t *fptr;
6039 VALUE write_io;
6040
6041 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6042 if (fptr->fd < 0) return Qnil;
6043 if (is_socket(fptr->fd, fptr->pathv)) {
6044#ifndef SHUT_RD
6045# define SHUT_RD 0
6046#endif
6047 if (shutdown(fptr->fd, SHUT_RD) < 0)
6048 rb_sys_fail_path(fptr->pathv);
6049 fptr->mode &= ~FMODE_READABLE;
6050 if (!(fptr->mode & FMODE_WRITABLE))
6051 return rb_io_close(io);
6052 return Qnil;
6053 }
6054
6055 write_io = GetWriteIO(io);
6056 if (io != write_io) {
6057 rb_io_t *wfptr;
6058 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6059 wfptr->pid = fptr->pid;
6060 fptr->pid = 0;
6061 RFILE(io)->fptr = wfptr;
6062 /* bind to write_io temporarily to get rid of memory/fd leak */
6063 fptr->tied_io_for_writing = 0;
6064 RFILE(write_io)->fptr = fptr;
6065 rb_io_fptr_cleanup(fptr, FALSE);
6066 /* should not finalize fptr because another thread may be reading it */
6067 return Qnil;
6068 }
6069
6070 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
6071 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
6072 }
6073 return rb_io_close(io);
6074}
6075
6076/*
6077 * call-seq:
6078 * close_write -> nil
6079 *
6080 * Closes the stream for writing if open for writing;
6081 * returns +nil+.
6082 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6083 *
6084 * Flushes any buffered writes to the operating system before closing.
6085 *
6086 * If the stream was opened by IO.popen and is also closed for reading,
6087 * sets global variable <tt>$?</tt> (child exit status).
6088 *
6089 * IO.popen('ruby', 'r+') do |pipe|
6090 * puts pipe.closed?
6091 * pipe.close_read
6092 * puts pipe.closed?
6093 * pipe.close_write
6094 * puts $?
6095 * puts pipe.closed?
6096 * end
6097 *
6098 * Output:
6099 *
6100 * false
6101 * false
6102 * pid 15044 exit 0
6103 * true
6104 *
6105 * Related: IO#close, IO#close_read, IO#closed?.
6106 */
6107
6108static VALUE
6109rb_io_close_write(VALUE io)
6110{
6111 rb_io_t *fptr;
6112 VALUE write_io;
6113
6114 write_io = GetWriteIO(io);
6115 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6116 if (fptr->fd < 0) return Qnil;
6117 if (is_socket(fptr->fd, fptr->pathv)) {
6118#ifndef SHUT_WR
6119# define SHUT_WR 1
6120#endif
6121 /* Flush any buffered data before shutting down the write side.
6122 * Otherwise the buffered bytes are silently dropped here, and a
6123 * subsequent #close would try to flush them into the now
6124 * shutdown(SHUT_WR) socket and fail with EPIPE. This matches the
6125 * behaviour of the non-socket path below, which flushes via
6126 * rb_io_close(). */
6127 if (fptr->mode & FMODE_WRITABLE) {
6128 if (io_fflush(fptr) < 0)
6129 rb_sys_fail_on_write(fptr);
6130 }
6131 if (shutdown(fptr->fd, SHUT_WR) < 0)
6132 rb_sys_fail_path(fptr->pathv);
6133 fptr->mode &= ~FMODE_WRITABLE;
6134 if (!(fptr->mode & FMODE_READABLE))
6135 return rb_io_close(write_io);
6136 return Qnil;
6137 }
6138
6139 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6140 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6141 }
6142
6143 if (io != write_io) {
6144 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6145 fptr->tied_io_for_writing = 0;
6146 }
6147 rb_io_close(write_io);
6148 return Qnil;
6149}
6150
6151/*
6152 * call-seq:
6153 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6154 *
6155 * Behaves like IO#seek, except that it:
6156 *
6157 * - Uses low-level system functions.
6158 * - Returns the new position.
6159 *
6160 */
6161
6162static VALUE
6163rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6164{
6165 VALUE offset, ptrname;
6166 int whence = SEEK_SET;
6167 rb_io_t *fptr;
6168 rb_off_t pos;
6169
6170 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6171 whence = interpret_seek_whence(ptrname);
6172 }
6173 pos = NUM2OFFT(offset);
6174 GetOpenFile(io, fptr);
6175 if ((fptr->mode & FMODE_READABLE) &&
6176 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6177 rb_raise(rb_eIOError, "sysseek for buffered IO");
6178 }
6179 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6180 rb_warn("sysseek for buffered IO");
6181 }
6182 errno = 0;
6183 pos = lseek(fptr->fd, pos, whence);
6184 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6185
6186 return OFFT2NUM(pos);
6187}
6188
6189/*
6190 * call-seq:
6191 * syswrite(object) -> integer
6192 *
6193 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6194 * returns the number bytes written.
6195 * If +object+ is not a string is converted via method to_s:
6196 *
6197 * f = File.new('t.tmp', 'w')
6198 * f.syswrite('foo') # => 3
6199 * f.syswrite(30) # => 2
6200 * f.syswrite(:foo) # => 3
6201 * f.close
6202 *
6203 * This methods should not be used with other stream-writer methods.
6204 *
6205 */
6206
6207static VALUE
6208rb_io_syswrite(VALUE io, VALUE str)
6209{
6210 VALUE tmp;
6211 rb_io_t *fptr;
6212 long n, len;
6213 const char *ptr;
6214
6215 if (!RB_TYPE_P(str, T_STRING))
6216 str = rb_obj_as_string(str);
6217
6218 io = GetWriteIO(io);
6219 GetOpenFile(io, fptr);
6221
6222 if (fptr->wbuf.len) {
6223 rb_warn("syswrite for buffered IO");
6224 }
6225
6226 tmp = rb_str_tmp_frozen_acquire(str);
6227 RSTRING_GETMEM(tmp, ptr, len);
6228 n = rb_io_write_memory(fptr, ptr, len);
6229 if (n < 0) rb_sys_fail_path(fptr->pathv);
6230 rb_str_tmp_frozen_release(str, tmp);
6231
6232 return LONG2FIX(n);
6233}
6234
6235/*
6236 * call-seq:
6237 * sysread(maxlen) -> string
6238 * sysread(maxlen, out_string) -> string
6239 *
6240 * Behaves like IO#readpartial, except that it uses low-level system functions.
6241 *
6242 * This method should not be used with other stream-reader methods.
6243 *
6244 */
6245
6246static VALUE
6247rb_io_sysread(int argc, VALUE *argv, VALUE io)
6248{
6249 VALUE len, str;
6250 rb_io_t *fptr;
6251 long n, ilen;
6252 struct io_internal_read_struct iis;
6253 int shrinkable;
6254
6255 rb_scan_args(argc, argv, "11", &len, &str);
6256 ilen = NUM2LONG(len);
6257
6258 shrinkable = io_setstrbuf(&str, ilen);
6259 if (ilen == 0) return str;
6260
6261 GetOpenFile(io, fptr);
6263
6264 if (READ_DATA_BUFFERED(fptr)) {
6265 rb_raise(rb_eIOError, "sysread for buffered IO");
6266 }
6267
6268 rb_io_check_closed(fptr);
6269
6270 io_setstrbuf(&str, ilen);
6271 iis.th = rb_thread_current();
6272 iis.fptr = fptr;
6273 iis.nonblock = 0;
6274 iis.fd = fptr->fd;
6275 iis.buf = RSTRING_PTR(str);
6276 iis.capa = ilen;
6277 iis.timeout = NULL;
6278 n = io_read_memory_locktmp(str, &iis);
6279
6280 if (n < 0) {
6281 rb_sys_fail_path(fptr->pathv);
6282 }
6283
6284 io_set_read_length(str, n, shrinkable);
6285
6286 if (n == 0 && ilen > 0) {
6287 rb_eof_error();
6288 }
6289
6290 return str;
6291}
6292
6294 struct rb_io *io;
6295 int fd;
6296 void *buf;
6297 size_t count;
6298 rb_off_t offset;
6299};
6300
6301static VALUE
6302internal_pread_func(void *_arg)
6303{
6304 struct prdwr_internal_arg *arg = _arg;
6305
6306 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6307}
6308
6309static VALUE
6310pread_internal_call(VALUE _arg)
6311{
6312 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6313
6314 VALUE scheduler = rb_fiber_scheduler_current();
6315 if (scheduler != Qnil) {
6316 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6317
6318 if (!UNDEF_P(result)) {
6320 }
6321 }
6322
6323 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6324}
6325
6326/*
6327 * call-seq:
6328 * pread(maxlen, offset) -> string
6329 * pread(maxlen, offset, out_string) -> string
6330 *
6331 * Behaves like IO#readpartial, except that it:
6332 *
6333 * - Reads at the given +offset+ (in bytes).
6334 * - Disregards, and does not modify, the stream's position
6335 * (see {Position}[rdoc-ref:IO@Position]).
6336 * - Bypasses any user space buffering in the stream.
6337 *
6338 * Because this method does not disturb the stream's state
6339 * (its position, in particular), +pread+ allows multiple threads and processes
6340 * to use the same \IO object for reading at various offsets.
6341 *
6342 * f = File.open('t.txt')
6343 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6344 * f.pos # => 52
6345 * # Read 12 bytes at offset 0.
6346 * f.pread(12, 0) # => "First line\n"
6347 * # Read 9 bytes at offset 8.
6348 * f.pread(9, 8) # => "ne\nSecon"
6349 * f.close
6350 *
6351 * Not available on some platforms.
6352 *
6353 */
6354static VALUE
6355rb_io_pread(int argc, VALUE *argv, VALUE io)
6356{
6357 VALUE len, offset, str;
6358 rb_io_t *fptr;
6359 ssize_t n;
6360 struct prdwr_internal_arg arg;
6361 int shrinkable;
6362
6363 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6364 arg.count = NUM2SIZET(len);
6365 arg.offset = NUM2OFFT(offset);
6366
6367 shrinkable = io_setstrbuf(&str, (long)arg.count);
6368 if (arg.count == 0) return str;
6369 arg.buf = RSTRING_PTR(str);
6370
6371 GetOpenFile(io, fptr);
6373
6374 arg.io = fptr;
6375 arg.fd = fptr->fd;
6376 rb_io_check_closed(fptr);
6377
6378 rb_str_locktmp(str);
6379 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6380
6381 if (n < 0) {
6382 rb_sys_fail_path(fptr->pathv);
6383 }
6384 io_set_read_length(str, n, shrinkable);
6385 if (n == 0 && arg.count > 0) {
6386 rb_eof_error();
6387 }
6388
6389 return str;
6390}
6391
6392static VALUE
6393internal_pwrite_func(void *_arg)
6394{
6395 struct prdwr_internal_arg *arg = _arg;
6396
6397 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6398}
6399
6400static VALUE
6401pwrite_internal_call(VALUE _arg)
6402{
6403 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6404
6405 VALUE scheduler = rb_fiber_scheduler_current();
6406 if (scheduler != Qnil) {
6407 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6408
6409 if (!UNDEF_P(result)) {
6411 }
6412 }
6413
6414 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
6415}
6416
6417/*
6418 * call-seq:
6419 * pwrite(object, offset) -> integer
6420 *
6421 * Behaves like IO#write, except that it:
6422 *
6423 * - Writes at the given +offset+ (in bytes).
6424 * - Disregards, and does not modify, the stream's position
6425 * (see {Position}[rdoc-ref:IO@Position]).
6426 * - Bypasses any user space buffering in the stream.
6427 *
6428 * Because this method does not disturb the stream's state
6429 * (its position, in particular), +pwrite+ allows multiple threads and processes
6430 * to use the same \IO object for writing at various offsets.
6431 *
6432 * f = File.open('t.tmp', 'w+')
6433 * # Write 6 bytes at offset 3.
6434 * f.pwrite('ABCDEF', 3) # => 6
6435 * f.rewind
6436 * f.read # => "\u0000\u0000\u0000ABCDEF"
6437 * f.close
6438 *
6439 * Not available on some platforms.
6440 *
6441 */
6442static VALUE
6443rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6444{
6445 rb_io_t *fptr;
6446 ssize_t n;
6447 struct prdwr_internal_arg arg;
6448 VALUE tmp;
6449
6450 if (!RB_TYPE_P(str, T_STRING))
6451 str = rb_obj_as_string(str);
6452
6453 arg.offset = NUM2OFFT(offset);
6454
6455 io = GetWriteIO(io);
6456 GetOpenFile(io, fptr);
6458
6459 arg.io = fptr;
6460 arg.fd = fptr->fd;
6461
6462 tmp = rb_str_tmp_frozen_acquire(str);
6463 arg.buf = RSTRING_PTR(tmp);
6464 arg.count = (size_t)RSTRING_LEN(tmp);
6465
6466 n = (ssize_t)pwrite_internal_call((VALUE)&arg);
6467 if (n < 0) rb_sys_fail_path(fptr->pathv);
6468 rb_str_tmp_frozen_release(str, tmp);
6469
6470 return SSIZET2NUM(n);
6471}
6472
6473VALUE
6475{
6476 rb_io_t *fptr;
6477
6478 GetOpenFile(io, fptr);
6479 if (fptr->readconv)
6481 if (fptr->writeconv)
6483 fptr->mode |= FMODE_BINMODE;
6484 fptr->mode &= ~FMODE_TEXTMODE;
6485 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6486#ifdef O_BINARY
6487 if (!fptr->readconv) {
6488 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6489 }
6490 else {
6491 setmode(fptr->fd, O_BINARY);
6492 }
6493#endif
6494 return io;
6495}
6496
6497static void
6498io_ascii8bit_binmode(rb_io_t *fptr)
6499{
6500 if (fptr->readconv) {
6501 rb_econv_close(fptr->readconv);
6502 fptr->readconv = NULL;
6503 }
6504 if (fptr->writeconv) {
6506 fptr->writeconv = NULL;
6507 }
6508 fptr->mode |= FMODE_BINMODE;
6509 fptr->mode &= ~FMODE_TEXTMODE;
6510 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6511
6512 fptr->encs.enc = rb_ascii8bit_encoding();
6513 fptr->encs.enc2 = NULL;
6514 fptr->encs.ecflags = 0;
6515 fptr->encs.ecopts = Qnil;
6516 clear_codeconv(fptr);
6517}
6518
6519VALUE
6521{
6522 rb_io_t *fptr;
6523
6524 GetOpenFile(io, fptr);
6525 io_ascii8bit_binmode(fptr);
6526
6527 return io;
6528}
6529
6530/*
6531 * call-seq:
6532 * binmode -> self
6533 *
6534 * Sets the stream's data mode as binary
6535 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6536 *
6537 * A stream's data mode may not be changed from binary to text.
6538 *
6539 */
6540
6541static VALUE
6542rb_io_binmode_m(VALUE io)
6543{
6544 VALUE write_io;
6545
6547
6548 write_io = GetWriteIO(io);
6549 if (write_io != io)
6550 rb_io_ascii8bit_binmode(write_io);
6551 return io;
6552}
6553
6554/*
6555 * call-seq:
6556 * binmode? -> true or false
6557 *
6558 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6559 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6560 *
6561 */
6562static VALUE
6563rb_io_binmode_p(VALUE io)
6564{
6565 rb_io_t *fptr;
6566 GetOpenFile(io, fptr);
6567 return RBOOL(fptr->mode & FMODE_BINMODE);
6568}
6569
6570static const char*
6571rb_io_fmode_modestr(enum rb_io_mode fmode)
6572{
6573 if (fmode & FMODE_APPEND) {
6574 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6575 return MODE_BTMODE("a+", "ab+", "at+");
6576 }
6577 return MODE_BTMODE("a", "ab", "at");
6578 }
6579 switch (fmode & FMODE_READWRITE) {
6580 default:
6581 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6582 case FMODE_READABLE:
6583 return MODE_BTMODE("r", "rb", "rt");
6584 case FMODE_WRITABLE:
6585 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6586 case FMODE_READWRITE:
6587 if (fmode & FMODE_CREATE) {
6588 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6589 }
6590 return MODE_BTMODE("r+", "rb+", "rt+");
6591 }
6592}
6593
6594static const char bom_prefix[] = "bom|";
6595static const char utf_prefix[] = "utf-";
6596enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6597enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6598
6599static int
6600io_encname_bom_p(const char *name, long len)
6601{
6602 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6603}
6604
6605enum rb_io_mode
6606rb_io_modestr_fmode(const char *modestr)
6607{
6608 enum rb_io_mode fmode = 0;
6609 const char *m = modestr, *p = NULL;
6610
6611 switch (*m++) {
6612 case 'r':
6613 fmode |= FMODE_READABLE;
6614 break;
6615 case 'w':
6617 break;
6618 case 'a':
6620 break;
6621 default:
6622 goto error;
6623 }
6624
6625 while (*m) {
6626 switch (*m++) {
6627 case 'b':
6628 fmode |= FMODE_BINMODE;
6629 break;
6630 case 't':
6631 fmode |= FMODE_TEXTMODE;
6632 break;
6633 case '+':
6634 fmode |= FMODE_READWRITE;
6635 break;
6636 case 'x':
6637 if (modestr[0] != 'w')
6638 goto error;
6639 fmode |= FMODE_EXCL;
6640 break;
6641 default:
6642 goto error;
6643 case ':':
6644 p = strchr(m, ':');
6645 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6646 fmode |= FMODE_SETENC_BY_BOM;
6647 goto finished;
6648 }
6649 }
6650
6651 finished:
6652 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6653 goto error;
6654
6655 return fmode;
6656
6657 error:
6658 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6660}
6661
6662int
6663rb_io_oflags_fmode(int oflags)
6664{
6665 enum rb_io_mode fmode = 0;
6666
6667 switch (oflags & O_ACCMODE) {
6668 case O_RDONLY:
6669 fmode = FMODE_READABLE;
6670 break;
6671 case O_WRONLY:
6672 fmode = FMODE_WRITABLE;
6673 break;
6674 case O_RDWR:
6675 fmode = FMODE_READWRITE;
6676 break;
6677 }
6678
6679 if (oflags & O_APPEND) {
6680 fmode |= FMODE_APPEND;
6681 }
6682 if (oflags & O_TRUNC) {
6683 fmode |= FMODE_TRUNC;
6684 }
6685 if (oflags & O_CREAT) {
6686 fmode |= FMODE_CREATE;
6687 }
6688 if (oflags & O_EXCL) {
6689 fmode |= FMODE_EXCL;
6690 }
6691#ifdef O_BINARY
6692 if (oflags & O_BINARY) {
6693 fmode |= FMODE_BINMODE;
6694 }
6695#endif
6696
6697 return fmode;
6698}
6699
6700static int
6701rb_io_fmode_oflags(enum rb_io_mode fmode)
6702{
6703 int oflags = 0;
6704
6705 switch (fmode & FMODE_READWRITE) {
6706 case FMODE_READABLE:
6707 oflags |= O_RDONLY;
6708 break;
6709 case FMODE_WRITABLE:
6710 oflags |= O_WRONLY;
6711 break;
6712 case FMODE_READWRITE:
6713 oflags |= O_RDWR;
6714 break;
6715 }
6716
6717 if (fmode & FMODE_APPEND) {
6718 oflags |= O_APPEND;
6719 }
6720 if (fmode & FMODE_TRUNC) {
6721 oflags |= O_TRUNC;
6722 }
6723 if (fmode & FMODE_CREATE) {
6724 oflags |= O_CREAT;
6725 }
6726 if (fmode & FMODE_EXCL) {
6727 oflags |= O_EXCL;
6728 }
6729#ifdef O_BINARY
6730 if (fmode & FMODE_BINMODE) {
6731 oflags |= O_BINARY;
6732 }
6733#endif
6734
6735 return oflags;
6736}
6737
6738int
6739rb_io_modestr_oflags(const char *modestr)
6740{
6741 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6742}
6743
6744static const char*
6745rb_io_oflags_modestr(int oflags)
6746{
6747#ifdef O_BINARY
6748# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6749#else
6750# define MODE_BINARY(a,b) (a)
6751#endif
6752 int accmode;
6753 if (oflags & O_EXCL) {
6754 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6755 }
6756 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6757 if (oflags & O_APPEND) {
6758 if (accmode == O_WRONLY) {
6759 return MODE_BINARY("a", "ab");
6760 }
6761 if (accmode == O_RDWR) {
6762 return MODE_BINARY("a+", "ab+");
6763 }
6764 }
6765 switch (accmode) {
6766 default:
6767 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6768 case O_RDONLY:
6769 return MODE_BINARY("r", "rb");
6770 case O_WRONLY:
6771 return MODE_BINARY("w", "wb");
6772 case O_RDWR:
6773 if (oflags & O_TRUNC) {
6774 return MODE_BINARY("w+", "wb+");
6775 }
6776 return MODE_BINARY("r+", "rb+");
6777 }
6778}
6779
6780/*
6781 * Convert external/internal encodings to enc/enc2
6782 * NULL => use default encoding
6783 * Qnil => no encoding specified (internal only)
6784 */
6785static void
6786rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6787{
6788 int default_ext = 0;
6789
6790 if (ext == NULL) {
6791 ext = rb_default_external_encoding();
6792 default_ext = 1;
6793 }
6794 if (rb_is_ascii8bit_enc(ext)) {
6795 /* If external is ASCII-8BIT, no transcoding */
6796 intern = NULL;
6797 }
6798 else if (intern == NULL) {
6799 intern = rb_default_internal_encoding();
6800 }
6801 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6802 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6803 /* No internal encoding => use external + no transcoding */
6804 *enc = (default_ext && intern != ext) ? NULL : ext;
6805 *enc2 = NULL;
6806 }
6807 else {
6808 *enc = intern;
6809 *enc2 = ext;
6810 }
6811}
6812
6813static void
6814unsupported_encoding(const char *name, rb_encoding *enc)
6815{
6816 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6817}
6818
6819static void
6820parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6821 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6822{
6823 const char *p;
6824 char encname[ENCODING_MAXNAMELEN+1];
6825 int idx, idx2;
6826 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6827 rb_encoding *ext_enc, *int_enc;
6828 long len;
6829
6830 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6831
6832 p = strrchr(estr, ':');
6833 len = p ? (p++ - estr) : (long)strlen(estr);
6834 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6835 estr += bom_prefix_len;
6836 len -= bom_prefix_len;
6837 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6838 fmode |= FMODE_SETENC_BY_BOM;
6839 }
6840 else {
6841 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6842 fmode &= ~FMODE_SETENC_BY_BOM;
6843 }
6844 }
6845 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6846 idx = -1;
6847 }
6848 else {
6849 if (p) {
6850 memcpy(encname, estr, len);
6851 encname[len] = '\0';
6852 estr = encname;
6853 }
6854 idx = rb_enc_find_index(estr);
6855 }
6856 if (fmode_p) *fmode_p = fmode;
6857
6858 if (idx >= 0)
6859 ext_enc = rb_enc_from_index(idx);
6860 else {
6861 if (idx != -2)
6862 unsupported_encoding(estr, estr_enc);
6863 ext_enc = NULL;
6864 }
6865
6866 int_enc = NULL;
6867 if (p) {
6868 if (*p == '-' && *(p+1) == '\0') {
6869 /* Special case - "-" => no transcoding */
6870 int_enc = (rb_encoding *)Qnil;
6871 }
6872 else {
6873 idx2 = rb_enc_find_index(p);
6874 if (idx2 < 0)
6875 unsupported_encoding(p, estr_enc);
6876 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6877 int_enc = (rb_encoding *)Qnil;
6878 }
6879 else
6880 int_enc = rb_enc_from_index(idx2);
6881 }
6882 }
6883
6884 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6885}
6886
6887int
6888rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6889{
6890 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6891 int extracted = 0;
6892 rb_encoding *extencoding = NULL;
6893 rb_encoding *intencoding = NULL;
6894
6895 if (!NIL_P(opt)) {
6896 VALUE v;
6897 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6898 if (v != Qnil) encoding = v;
6899 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6900 if (v != Qnil) extenc = v;
6901 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6902 if (!UNDEF_P(v)) intenc = v;
6903 }
6904 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6905 if (!NIL_P(ruby_verbose)) {
6906 int idx = rb_to_encoding_index(encoding);
6907 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6908 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6909 encoding, UNDEF_P(extenc) ? "internal" : "external");
6910 }
6911 encoding = Qnil;
6912 }
6913 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6914 extencoding = rb_to_encoding(extenc);
6915 }
6916 if (!UNDEF_P(intenc)) {
6917 if (NIL_P(intenc)) {
6918 /* internal_encoding: nil => no transcoding */
6919 intencoding = (rb_encoding *)Qnil;
6920 }
6921 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6922 char *p = StringValueCStr(tmp);
6923
6924 if (*p == '-' && *(p+1) == '\0') {
6925 /* Special case - "-" => no transcoding */
6926 intencoding = (rb_encoding *)Qnil;
6927 }
6928 else {
6929 intencoding = rb_to_encoding(intenc);
6930 }
6931 }
6932 else {
6933 intencoding = rb_to_encoding(intenc);
6934 }
6935 if (extencoding == intencoding) {
6936 intencoding = (rb_encoding *)Qnil;
6937 }
6938 }
6939 if (!NIL_P(encoding)) {
6940 extracted = 1;
6941 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6942 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6943 enc_p, enc2_p, fmode_p);
6944 }
6945 else {
6946 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6947 }
6948 }
6949 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6950 extracted = 1;
6951 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6952 }
6953 return extracted;
6954}
6955
6956static void
6957validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6958{
6959 enum rb_io_mode fmode = *fmode_p;
6960
6961 if ((fmode & FMODE_READABLE) &&
6962 !enc2 &&
6963 !(fmode & FMODE_BINMODE) &&
6964 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6965 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6966
6967 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6968 rb_raise(rb_eArgError, "newline decorator with binary mode");
6969 }
6970 if (!(fmode & FMODE_BINMODE) &&
6971 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6972 fmode |= FMODE_TEXTMODE;
6973 *fmode_p = fmode;
6974 }
6975#if !DEFAULT_TEXTMODE
6976 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6977 fmode &= ~FMODE_TEXTMODE;
6978 *fmode_p = fmode;
6979 }
6980#endif
6981}
6982
6983static void
6984extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
6985{
6986 if (!NIL_P(opthash)) {
6987 VALUE v;
6988 v = rb_hash_aref(opthash, sym_textmode);
6989 if (!NIL_P(v)) {
6990 if (*fmode & FMODE_TEXTMODE)
6991 rb_raise(rb_eArgError, "textmode specified twice");
6992 if (*fmode & FMODE_BINMODE)
6993 rb_raise(rb_eArgError, "both textmode and binmode specified");
6994 if (RTEST(v))
6995 *fmode |= FMODE_TEXTMODE;
6996 }
6997 v = rb_hash_aref(opthash, sym_binmode);
6998 if (!NIL_P(v)) {
6999 if (*fmode & FMODE_BINMODE)
7000 rb_raise(rb_eArgError, "binmode specified twice");
7001 if (*fmode & FMODE_TEXTMODE)
7002 rb_raise(rb_eArgError, "both textmode and binmode specified");
7003 if (RTEST(v))
7004 *fmode |= FMODE_BINMODE;
7005 }
7006
7007 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
7008 rb_raise(rb_eArgError, "both textmode and binmode specified");
7009 }
7010}
7011
7012void
7013rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
7014 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
7015{
7016 VALUE vmode;
7017 int oflags;
7018 enum rb_io_mode fmode;
7019 rb_encoding *enc, *enc2;
7020 int ecflags;
7021 VALUE ecopts;
7022 int has_enc = 0, has_vmode = 0;
7023 VALUE intmode;
7024
7025 vmode = *vmode_p;
7026
7027 /* Set to defaults */
7028 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
7029
7030 vmode_handle:
7031 if (NIL_P(vmode)) {
7032 fmode = FMODE_READABLE;
7033 oflags = O_RDONLY;
7034 }
7035 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
7036 vmode = intmode;
7037 oflags = NUM2INT(intmode);
7038 fmode = rb_io_oflags_fmode(oflags);
7039 }
7040 else {
7041 const char *p;
7042
7043 StringValue(vmode);
7044 p = StringValueCStr(vmode);
7045 fmode = rb_io_modestr_fmode(p);
7046 oflags = rb_io_fmode_oflags(fmode);
7047 p = strchr(p, ':');
7048 if (p) {
7049 has_enc = 1;
7050 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
7051 }
7052 else {
7053 rb_encoding *e;
7054
7055 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7056 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
7057 }
7058 }
7059
7060 if (NIL_P(opthash)) {
7061 ecflags = (fmode & FMODE_READABLE) ?
7064#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7065 ecflags |= (fmode & FMODE_WRITABLE) ?
7066 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7067 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7068#endif
7069 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7070 ecopts = Qnil;
7071 if (fmode & FMODE_BINMODE) {
7072#ifdef O_BINARY
7073 oflags |= O_BINARY;
7074#endif
7075 if (!has_enc)
7076 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7077 }
7078#if DEFAULT_TEXTMODE
7079 else if (NIL_P(vmode)) {
7080 fmode |= DEFAULT_TEXTMODE;
7081 }
7082#endif
7083 }
7084 else {
7085 VALUE v;
7086 if (!has_vmode) {
7087 v = rb_hash_aref(opthash, sym_mode);
7088 if (!NIL_P(v)) {
7089 if (!NIL_P(vmode)) {
7090 rb_raise(rb_eArgError, "mode specified twice");
7091 }
7092 has_vmode = 1;
7093 vmode = v;
7094 goto vmode_handle;
7095 }
7096 }
7097 v = rb_hash_aref(opthash, sym_flags);
7098 if (!NIL_P(v)) {
7099 v = rb_to_int(v);
7100 oflags |= NUM2INT(v);
7101 vmode = INT2NUM(oflags);
7102 fmode = rb_io_oflags_fmode(oflags);
7103 }
7104 extract_binmode(opthash, &fmode);
7105 if (fmode & FMODE_BINMODE) {
7106#ifdef O_BINARY
7107 oflags |= O_BINARY;
7108#endif
7109 if (!has_enc)
7110 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7111 }
7112#if DEFAULT_TEXTMODE
7113 else if (NIL_P(vmode)) {
7114 fmode |= DEFAULT_TEXTMODE;
7115 }
7116#endif
7117 v = rb_hash_aref(opthash, sym_perm);
7118 if (!NIL_P(v)) {
7119 if (vperm_p) {
7120 if (!NIL_P(*vperm_p)) {
7121 rb_raise(rb_eArgError, "perm specified twice");
7122 }
7123 *vperm_p = v;
7124 }
7125 else {
7126 /* perm no use, just ignore */
7127 }
7128 }
7129 ecflags = (fmode & FMODE_READABLE) ?
7132#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7133 ecflags |= (fmode & FMODE_WRITABLE) ?
7134 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7135 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7136#endif
7137
7138 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7139 if (has_enc) {
7140 rb_raise(rb_eArgError, "encoding specified twice");
7141 }
7142 }
7143 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7144 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7145 }
7146
7147 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7148
7149 *vmode_p = vmode;
7150
7151 *oflags_p = oflags;
7152 *fmode_p = fmode;
7153 convconfig_p->enc = enc;
7154 convconfig_p->enc2 = enc2;
7155 convconfig_p->ecflags = ecflags;
7156 convconfig_p->ecopts = ecopts;
7157}
7158
7160 VALUE fname;
7161 int oflags;
7162 mode_t perm;
7163};
7164
7165static void *
7166sysopen_func(void *ptr)
7167{
7168 const struct sysopen_struct *data = ptr;
7169 const char *fname = RSTRING_PTR(data->fname);
7170 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7171}
7172
7173static inline int
7174rb_sysopen_internal(struct sysopen_struct *data)
7175{
7176 int fd;
7177 do {
7178 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7179 } while (fd < 0 && errno == EINTR);
7180 if (0 <= fd)
7181 rb_update_max_fd(fd);
7182 return fd;
7183}
7184
7185static int
7186rb_sysopen(VALUE fname, int oflags, mode_t perm)
7187{
7188 int fd = -1;
7189 struct sysopen_struct data;
7190
7191 data.fname = rb_str_encode_ospath(fname);
7192 StringValueCStr(data.fname);
7193 data.oflags = oflags;
7194 data.perm = perm;
7195
7196 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7197 rb_syserr_fail_path(first_errno, fname);
7198 }
7199 return fd;
7200}
7201
7202static inline FILE *
7203fdopen_internal(int fd, const char *modestr)
7204{
7205 FILE *file;
7206
7207#if defined(__sun)
7208 errno = 0;
7209#endif
7210 file = fdopen(fd, modestr);
7211 if (!file) {
7212#ifdef _WIN32
7213 if (errno == 0) errno = EINVAL;
7214#elif defined(__sun)
7215 if (errno == 0) errno = EMFILE;
7216#endif
7217 }
7218 return file;
7219}
7220
7221FILE *
7222rb_fdopen(int fd, const char *modestr)
7223{
7224 FILE *file = 0;
7225
7226 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7227 rb_syserr_fail(first_errno, 0);
7228 }
7229
7230 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7231#ifdef USE_SETVBUF
7232 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7233 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7234#endif
7235 return file;
7236}
7237
7238static int
7239io_check_tty(rb_io_t *fptr)
7240{
7241 int t = isatty(fptr->fd);
7242 if (t)
7243 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7244 return t;
7245}
7246
7247static VALUE rb_io_internal_encoding(VALUE);
7248static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7249
7250static int
7251io_strip_bom(VALUE io)
7252{
7253 VALUE b1, b2, b3, b4;
7254 rb_io_t *fptr;
7255
7256 GetOpenFile(io, fptr);
7257 if (!(fptr->mode & FMODE_READABLE)) return 0;
7258 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7259 switch (b1) {
7260 case INT2FIX(0xEF):
7261 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7262 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7263 if (b3 == INT2FIX(0xBF)) {
7264 return rb_utf8_encindex();
7265 }
7266 rb_io_ungetbyte(io, b3);
7267 }
7268 rb_io_ungetbyte(io, b2);
7269 break;
7270
7271 case INT2FIX(0xFE):
7272 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7273 if (b2 == INT2FIX(0xFF)) {
7274 return ENCINDEX_UTF_16BE;
7275 }
7276 rb_io_ungetbyte(io, b2);
7277 break;
7278
7279 case INT2FIX(0xFF):
7280 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7281 if (b2 == INT2FIX(0xFE)) {
7282 b3 = rb_io_getbyte(io);
7283 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7284 if (b4 == INT2FIX(0)) {
7285 return ENCINDEX_UTF_32LE;
7286 }
7287 rb_io_ungetbyte(io, b4);
7288 }
7289 rb_io_ungetbyte(io, b3);
7290 return ENCINDEX_UTF_16LE;
7291 }
7292 rb_io_ungetbyte(io, b2);
7293 break;
7294
7295 case INT2FIX(0):
7296 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7297 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7298 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7299 if (b4 == INT2FIX(0xFF)) {
7300 return ENCINDEX_UTF_32BE;
7301 }
7302 rb_io_ungetbyte(io, b4);
7303 }
7304 rb_io_ungetbyte(io, b3);
7305 }
7306 rb_io_ungetbyte(io, b2);
7307 break;
7308 }
7309 rb_io_ungetbyte(io, b1);
7310 return 0;
7311}
7312
7313static rb_encoding *
7314io_set_encoding_by_bom(VALUE io)
7315{
7316 int idx = io_strip_bom(io);
7317 rb_io_t *fptr;
7318 rb_encoding *extenc = NULL;
7319
7320 GetOpenFile(io, fptr);
7321 if (idx) {
7322 extenc = rb_enc_from_index(idx);
7323 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7324 rb_io_internal_encoding(io), Qnil);
7325 }
7326 else {
7327 fptr->encs.enc2 = NULL;
7328 }
7329 return extenc;
7330}
7331
7332static VALUE
7333rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7334 const struct rb_io_encoding *convconfig, mode_t perm)
7335{
7336 VALUE pathv;
7337 rb_io_t *fptr;
7338 struct rb_io_encoding cc;
7339 if (!convconfig) {
7340 /* Set to default encodings */
7341 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7342 cc.ecflags = 0;
7343 cc.ecopts = Qnil;
7344 convconfig = &cc;
7345 }
7346 validate_enc_binmode(&fmode, convconfig->ecflags,
7347 convconfig->enc, convconfig->enc2);
7348
7349 MakeOpenFile(io, fptr);
7350 fptr->mode = fmode;
7351 fptr->encs = *convconfig;
7352 pathv = rb_str_new_frozen(filename);
7353#ifdef O_TMPFILE
7354 if (!(oflags & O_TMPFILE)) {
7355 fptr->pathv = pathv;
7356 }
7357#else
7358 fptr->pathv = pathv;
7359#endif
7360 fptr->fd = rb_sysopen(pathv, oflags, perm);
7361 io_check_tty(fptr);
7362 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7363
7364 return io;
7365}
7366
7367static VALUE
7368rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7369{
7370 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7371 const char *p = strchr(modestr, ':');
7372 struct rb_io_encoding convconfig;
7373
7374 if (p) {
7375 parse_mode_enc(p+1, rb_usascii_encoding(),
7376 &convconfig.enc, &convconfig.enc2, &fmode);
7377 }
7378 else {
7379 rb_encoding *e;
7380 /* Set to default encodings */
7381
7382 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7383 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7384 }
7385
7386 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7389#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7390 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7391 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7392 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7393#endif
7394 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7395 convconfig.ecopts = Qnil;
7396
7397 return rb_file_open_generic(io, filename,
7398 rb_io_fmode_oflags(fmode),
7399 fmode,
7400 &convconfig,
7401 0666);
7402}
7403
7404VALUE
7405rb_file_open_str(VALUE fname, const char *modestr)
7406{
7407 FilePathValue(fname);
7408 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7409}
7410
7411VALUE
7412rb_file_open(const char *fname, const char *modestr)
7413{
7414 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7415}
7416
7417#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7418static struct pipe_list {
7419 rb_io_t *fptr;
7420 struct pipe_list *next;
7421} *pipe_list;
7422
7423static void
7424pipe_add_fptr(rb_io_t *fptr)
7425{
7426 struct pipe_list *list;
7427
7428 list = ALLOC(struct pipe_list);
7429 list->fptr = fptr;
7430 list->next = pipe_list;
7431 pipe_list = list;
7432}
7433
7434static void
7435pipe_del_fptr(rb_io_t *fptr)
7436{
7437 struct pipe_list **prev = &pipe_list;
7438 struct pipe_list *tmp;
7439
7440 while ((tmp = *prev) != 0) {
7441 if (tmp->fptr == fptr) {
7442 *prev = tmp->next;
7443 free(tmp);
7444 return;
7445 }
7446 prev = &tmp->next;
7447 }
7448}
7449
7450#if defined (_WIN32) || defined(__CYGWIN__)
7451static void
7452pipe_atexit(void)
7453{
7454 struct pipe_list *list = pipe_list;
7455 struct pipe_list *tmp;
7456
7457 while (list) {
7458 tmp = list->next;
7459 rb_io_fptr_finalize(list->fptr);
7460 list = tmp;
7461 }
7462}
7463#endif
7464
7465static void
7466pipe_finalize(rb_io_t *fptr, int noraise)
7467{
7468#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7469 int status = 0;
7470 if (fptr->stdio_file) {
7471 status = pclose(fptr->stdio_file);
7472 }
7473 fptr->fd = -1;
7474 fptr->stdio_file = 0;
7475 rb_last_status_set(status, fptr->pid);
7476#else
7477 fptr_finalize(fptr, noraise);
7478#endif
7479 pipe_del_fptr(fptr);
7480}
7481#endif
7482
7483static void
7484fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7485{
7486#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7487 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7488
7489 if (old_finalize == orig->finalize) return;
7490#endif
7491
7492 fptr->finalize = orig->finalize;
7493
7494#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7495 if (old_finalize != pipe_finalize) {
7496 struct pipe_list *list;
7497 for (list = pipe_list; list; list = list->next) {
7498 if (list->fptr == fptr) break;
7499 }
7500 if (!list) pipe_add_fptr(fptr);
7501 }
7502 else {
7503 pipe_del_fptr(fptr);
7504 }
7505#endif
7506}
7507
7508void
7510{
7512 fptr->mode |= FMODE_SYNC;
7513}
7514
7515
7516int
7517rb_pipe(int *pipes)
7518{
7519 int ret;
7520 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7521 if (ret == 0) {
7522 rb_update_max_fd(pipes[0]);
7523 rb_update_max_fd(pipes[1]);
7524 }
7525 return ret;
7526}
7527
7528#ifdef _WIN32
7529#define HAVE_SPAWNV 1
7530#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7531#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7532#endif
7533
7534#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7535struct popen_arg {
7536 VALUE execarg_obj;
7537 struct rb_execarg *eargp;
7538 int modef;
7539 int pair[2];
7540 int write_pair[2];
7541};
7542#endif
7543
7544#ifdef HAVE_WORKING_FORK
7545# ifndef __EMSCRIPTEN__
7546static void
7547popen_redirect(struct popen_arg *p)
7548{
7549 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7550 close(p->write_pair[1]);
7551 if (p->write_pair[0] != 0) {
7552 dup2(p->write_pair[0], 0);
7553 close(p->write_pair[0]);
7554 }
7555 close(p->pair[0]);
7556 if (p->pair[1] != 1) {
7557 dup2(p->pair[1], 1);
7558 close(p->pair[1]);
7559 }
7560 }
7561 else if (p->modef & FMODE_READABLE) {
7562 close(p->pair[0]);
7563 if (p->pair[1] != 1) {
7564 dup2(p->pair[1], 1);
7565 close(p->pair[1]);
7566 }
7567 }
7568 else {
7569 close(p->pair[1]);
7570 if (p->pair[0] != 0) {
7571 dup2(p->pair[0], 0);
7572 close(p->pair[0]);
7573 }
7574 }
7575}
7576# endif
7577
7578#if defined(__linux__)
7579/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7580 * Since /proc may not be available, linux_get_maxfd is just a hint.
7581 * This function, linux_get_maxfd, must be async-signal-safe.
7582 * I.e. opendir() is not usable.
7583 *
7584 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7585 * However they are easy to re-implement in async-signal-safe manner.
7586 * (Also note that there is missing/memcmp.c.)
7587 */
7588static int
7589linux_get_maxfd(void)
7590{
7591 int fd;
7592 char buf[4096], *p, *np, *e;
7593 ssize_t ss;
7594 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7595 if (fd < 0) return fd;
7596 ss = read(fd, buf, sizeof(buf));
7597 if (ss < 0) goto err;
7598 p = buf;
7599 e = buf + ss;
7600 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7601 (np = memchr(p, '\n', e-p)) != NULL) {
7602 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7603 int fdsize;
7604 p += sizeof("FDSize:")-1;
7605 *np = '\0';
7606 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7607 close(fd);
7608 return fdsize;
7609 }
7610 p = np+1;
7611 }
7612 /* fall through */
7613
7614 err:
7615 close(fd);
7616 return (int)ss;
7617}
7618#endif
7619
7620/* This function should be async-signal-safe. */
7621void
7622rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7623{
7624#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7625 int fd, ret;
7626 int max = (int)max_file_descriptor;
7627# ifdef F_MAXFD
7628 /* F_MAXFD is available since NetBSD 2.0. */
7629 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7630 if (ret != -1)
7631 maxhint = max = ret;
7632# elif defined(__linux__)
7633 ret = linux_get_maxfd();
7634 if (maxhint < ret)
7635 maxhint = ret;
7636 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7637# endif
7638 if (max < maxhint)
7639 max = maxhint;
7640 for (fd = lowfd; fd <= max; fd++) {
7641 if (!NIL_P(noclose_fds) &&
7642 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7643 continue;
7644 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7645 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7646 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7647 }
7648# define CONTIGUOUS_CLOSED_FDS 20
7649 if (ret != -1) {
7650 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7651 max = fd + CONTIGUOUS_CLOSED_FDS;
7652 }
7653 }
7654#endif
7655}
7656
7657# ifndef __EMSCRIPTEN__
7658static int
7659popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7660{
7661 struct popen_arg *p = (struct popen_arg*)pp;
7662
7663 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7664}
7665# endif
7666#endif
7667
7668#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7669static VALUE
7670rb_execarg_fixup_v(VALUE execarg_obj)
7671{
7672 rb_execarg_parent_start(execarg_obj);
7673 return Qnil;
7674}
7675#else
7676char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7677#endif
7678
7679#ifndef __EMSCRIPTEN__
7680static VALUE
7681pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7682 const struct rb_io_encoding *convconfig)
7683{
7684 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7685 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7686 rb_pid_t pid = 0;
7687 rb_io_t *fptr;
7688 VALUE port;
7689 rb_io_t *write_fptr;
7690 VALUE write_port;
7691#if defined(HAVE_WORKING_FORK)
7692 int status;
7693 char errmsg[80] = { '\0' };
7694#endif
7695#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7696 int state;
7697 struct popen_arg arg;
7698#endif
7699 int e = 0;
7700#if defined(HAVE_SPAWNV)
7701# if defined(HAVE_SPAWNVE)
7702# define DO_SPAWN(cmd, args, envp) ((args) ? \
7703 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7704 spawne(P_NOWAIT, (cmd), (envp)))
7705# else
7706# define DO_SPAWN(cmd, args, envp) ((args) ? \
7707 spawnv(P_NOWAIT, (cmd), (args)) : \
7708 spawn(P_NOWAIT, (cmd)))
7709# endif
7710# if !defined(HAVE_WORKING_FORK)
7711 char **args = NULL;
7712# if defined(HAVE_SPAWNVE)
7713 char **envp = NULL;
7714# endif
7715# endif
7716#endif
7717#if !defined(HAVE_WORKING_FORK)
7718 struct rb_execarg sarg, *sargp = &sarg;
7719#endif
7720 FILE *fp = 0;
7721 int fd = -1;
7722 int write_fd = -1;
7723#if !defined(HAVE_WORKING_FORK)
7724 const char *cmd = 0;
7725
7726 if (prog)
7727 cmd = StringValueCStr(prog);
7728#endif
7729
7730#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7731 arg.execarg_obj = execarg_obj;
7732 arg.eargp = eargp;
7733 arg.modef = fmode;
7734 arg.pair[0] = arg.pair[1] = -1;
7735 arg.write_pair[0] = arg.write_pair[1] = -1;
7736# if !defined(HAVE_WORKING_FORK)
7737 if (eargp && !eargp->use_shell) {
7738 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7739 }
7740# endif
7741 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7743 if (rb_pipe(arg.write_pair) < 0)
7744 rb_sys_fail_str(prog);
7745 if (rb_pipe(arg.pair) < 0) {
7746 e = errno;
7747 close(arg.write_pair[0]);
7748 close(arg.write_pair[1]);
7749 rb_syserr_fail_str(e, prog);
7750 }
7751 if (eargp) {
7752 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7753 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7754 }
7755 break;
7756 case FMODE_READABLE:
7757 if (rb_pipe(arg.pair) < 0)
7758 rb_sys_fail_str(prog);
7759 if (eargp)
7760 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7761 break;
7762 case FMODE_WRITABLE:
7763 if (rb_pipe(arg.pair) < 0)
7764 rb_sys_fail_str(prog);
7765 if (eargp)
7766 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7767 break;
7768 default:
7769 rb_sys_fail_str(prog);
7770 }
7771 if (!NIL_P(execarg_obj)) {
7772 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7773 if (state) {
7774 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7775 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7776 if (0 <= arg.pair[0]) close(arg.pair[0]);
7777 if (0 <= arg.pair[1]) close(arg.pair[1]);
7778 rb_execarg_parent_end(execarg_obj);
7779 rb_jump_tag(state);
7780 }
7781
7782# if defined(HAVE_WORKING_FORK)
7783 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7784# else
7785 rb_execarg_run_options(eargp, sargp, NULL, 0);
7786# if defined(HAVE_SPAWNVE)
7787 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7788# endif
7789 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7790 /* exec failed */
7791 switch (e = errno) {
7792 case EAGAIN:
7793# if EWOULDBLOCK != EAGAIN
7794 case EWOULDBLOCK:
7795# endif
7796 rb_thread_sleep(1);
7797 continue;
7798 }
7799 break;
7800 }
7801 if (eargp)
7802 rb_execarg_run_options(sargp, NULL, NULL, 0);
7803# endif
7804 rb_execarg_parent_end(execarg_obj);
7805 }
7806 else {
7807# if defined(HAVE_WORKING_FORK)
7808 pid = rb_call_proc__fork();
7809 if (pid == 0) { /* child */
7810 popen_redirect(&arg);
7811 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7812 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7813 return Qnil;
7814 }
7815# else
7816 rb_notimplement();
7817# endif
7818 }
7819
7820 /* parent */
7821 if (pid < 0) {
7822# if defined(HAVE_WORKING_FORK)
7823 e = errno;
7824# endif
7825 close(arg.pair[0]);
7826 close(arg.pair[1]);
7828 close(arg.write_pair[0]);
7829 close(arg.write_pair[1]);
7830 }
7831# if defined(HAVE_WORKING_FORK)
7832 if (errmsg[0])
7833 rb_syserr_fail(e, errmsg);
7834# endif
7835 rb_syserr_fail_str(e, prog);
7836 }
7837 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7838 close(arg.pair[1]);
7839 fd = arg.pair[0];
7840 close(arg.write_pair[0]);
7841 write_fd = arg.write_pair[1];
7842 }
7843 else if (fmode & FMODE_READABLE) {
7844 close(arg.pair[1]);
7845 fd = arg.pair[0];
7846 }
7847 else {
7848 close(arg.pair[0]);
7849 fd = arg.pair[1];
7850 }
7851#else
7852 cmd = rb_execarg_commandline(eargp, &prog);
7853 if (!NIL_P(execarg_obj)) {
7854 rb_execarg_parent_start(execarg_obj);
7855 rb_execarg_run_options(eargp, sargp, NULL, 0);
7856 }
7857 fp = popen(cmd, modestr);
7858 e = errno;
7859 if (eargp) {
7860 rb_execarg_parent_end(execarg_obj);
7861 rb_execarg_run_options(sargp, NULL, NULL, 0);
7862 }
7863 if (!fp) rb_syserr_fail_path(e, prog);
7864 fd = fileno(fp);
7865#endif
7866
7867 port = io_alloc(rb_cIO);
7868 MakeOpenFile(port, fptr);
7869 fptr->fd = fd;
7870 fptr->stdio_file = fp;
7871 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7872 if (convconfig) {
7873 fptr->encs = *convconfig;
7874#if RUBY_CRLF_ENVIRONMENT
7877 }
7878#endif
7879 }
7880 else {
7881 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7883 }
7884#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7885 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7886 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7887 }
7888#endif
7889 }
7890 fptr->pid = pid;
7891
7892 if (0 <= write_fd) {
7893 write_port = io_alloc(rb_cIO);
7894 MakeOpenFile(write_port, write_fptr);
7895 write_fptr->fd = write_fd;
7896 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7897 fptr->mode &= ~FMODE_WRITABLE;
7898 fptr->tied_io_for_writing = write_port;
7899 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7900 }
7901
7902#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7903 fptr->finalize = pipe_finalize;
7904 pipe_add_fptr(fptr);
7905#endif
7906 return port;
7907}
7908#else
7909static VALUE
7910pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7911 const struct rb_io_encoding *convconfig)
7912{
7913 rb_raise(rb_eNotImpError, "popen() is not available");
7914}
7915#endif
7916
7917static int
7918is_popen_fork(VALUE prog)
7919{
7920 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7921#if !defined(HAVE_WORKING_FORK)
7922 rb_raise(rb_eNotImpError,
7923 "fork() function is unimplemented on this machine");
7924#else
7925 return TRUE;
7926#endif
7927 }
7928 return FALSE;
7929}
7930
7931static VALUE
7932pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
7933 const struct rb_io_encoding *convconfig)
7934{
7935 int argc = 1;
7936 VALUE *argv = &prog;
7937 VALUE execarg_obj = Qnil;
7938
7939 if (!is_popen_fork(prog))
7940 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7941 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7942}
7943
7944static VALUE
7945pipe_close(VALUE io)
7946{
7947 rb_io_t *fptr = io_close_fptr(io);
7948 if (fptr) {
7949 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7950 }
7951 return Qnil;
7952}
7953
7954static VALUE popen_finish(VALUE port, VALUE klass);
7955
7956/*
7957 * call-seq:
7958 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7959 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7960 *
7961 * Executes the given command +cmd+ as a subprocess
7962 * whose $stdin and $stdout are connected to a new stream +io+.
7963 *
7964 * This method has potential security vulnerabilities if called with untrusted input;
7965 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
7966 *
7967 * If no block is given, returns the new stream,
7968 * which depending on given +mode+ may be open for reading, writing, or both.
7969 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7970 *
7971 * If a block is given, the stream is passed to the block
7972 * (again, open for reading, writing, or both);
7973 * when the block exits, the stream is closed,
7974 * the block's value is returned,
7975 * and the global variable <tt>$?</tt> is set to the child's exit status.
7976 *
7977 * Optional argument +mode+ may be any valid \IO mode.
7978 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7979 *
7980 * Required argument +cmd+ determines which of the following occurs:
7981 *
7982 * - The process forks.
7983 * - A specified program runs in a shell.
7984 * - A specified program runs with specified arguments.
7985 * - A specified program runs with specified arguments and a specified +argv0+.
7986 *
7987 * Each of these is detailed below.
7988 *
7989 * The optional hash argument +env+ specifies name/value pairs that are to be added
7990 * to the environment variables for the subprocess:
7991 *
7992 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7993 * pipe.puts 'puts ENV["FOO"]'
7994 * pipe.close_write
7995 * pipe.gets
7996 * end => "bar\n"
7997 *
7998 * Optional keyword arguments +opts+ specify:
7999 *
8000 * - {Open options}[rdoc-ref:IO@Open+Options].
8001 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8002 * - Options for Kernel#spawn.
8003 *
8004 * <b>Forked Process</b>
8005 *
8006 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
8007 * IO.popen('-') do |pipe|
8008 * if pipe
8009 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
8010 * else
8011 * $stderr.puts "In child, pid is #{$$}\n"
8012 * end
8013 * end
8014 *
8015 * Output:
8016 *
8017 * In parent, child pid is 26253
8018 * In child, pid is 26253
8019 *
8020 * Note that this is not supported on all platforms.
8021 *
8022 * <b>Shell Subprocess</b>
8023 *
8024 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
8025 * the program named +cmd+ is run as a shell command:
8026 *
8027 * IO.popen('uname') do |pipe|
8028 * pipe.readlines
8029 * end
8030 *
8031 * Output:
8032 *
8033 * ["Linux\n"]
8034 *
8035 * Another example:
8036 *
8037 * IO.popen('/bin/sh', 'r+') do |pipe|
8038 * pipe.puts('ls')
8039 * pipe.close_write
8040 * $stderr.puts pipe.readlines.size
8041 * end
8042 *
8043 * Output:
8044 *
8045 * 213
8046 *
8047 * <b>Program Subprocess</b>
8048 *
8049 * When argument +cmd+ is an array of strings,
8050 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
8051 *
8052 * IO.popen(['du', '..', '.']) do |pipe|
8053 * $stderr.puts pipe.readlines.size
8054 * end
8055 *
8056 * Output:
8057 *
8058 * 1111
8059 *
8060 * <b>Program Subprocess with <tt>argv0</tt></b>
8061 *
8062 * When argument +cmd+ is an array whose first element is a 2-element string array
8063 * and whose remaining elements (if any) are strings:
8064 *
8065 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
8066 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
8067 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
8068 *
8069 * Example (sets <tt>$0</tt> to 'foo'):
8070 *
8071 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
8072 *
8073 * <b>Some Special Examples</b>
8074 *
8075 * # Set IO encoding.
8076 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
8077 * euc_jp_string = nkf_io.read
8078 * }
8079 *
8080 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
8081 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
8082 * ls_result_with_error = io.read
8083 * end
8084 *
8085 * # Use mixture of spawn options and IO options.
8086 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
8087 * ls_result_with_error = io.read
8088 * end
8089 *
8090 * f = IO.popen("uname")
8091 * p f.readlines
8092 * f.close
8093 * puts "Parent is #{Process.pid}"
8094 * IO.popen("date") {|f| puts f.gets }
8095 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
8096 * p $?
8097 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
8098 * f.puts "bar"; f.close_write; puts f.gets
8099 * }
8100 *
8101 * Output (from last section):
8102 *
8103 * ["Linux\n"]
8104 * Parent is 21346
8105 * Thu Jan 15 22:41:19 JST 2009
8106 * 21346 is here, f is #<IO:fd 3>
8107 * 21352 is here, f is nil
8108 * #<Process::Status: pid 21352 exit 0>
8109 * <foo>bar;zot;
8110 *
8111 * Raises exceptions that IO.pipe and Kernel.spawn raise.
8112 *
8113 */
8114
8115static VALUE
8116rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
8117{
8118 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
8119
8120 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8121 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8122 switch (argc) {
8123 case 2:
8124 pmode = argv[1];
8125 case 1:
8126 pname = argv[0];
8127 break;
8128 default:
8129 {
8130 int ex = !NIL_P(opt);
8131 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8132 }
8133 }
8134 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8135}
8136
8137VALUE
8138rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8139{
8140 const char *modestr;
8141 VALUE tmp, execarg_obj = Qnil;
8142 int oflags;
8143 enum rb_io_mode fmode;
8144 struct rb_io_encoding convconfig;
8145
8146 tmp = rb_check_array_type(pname);
8147 if (!NIL_P(tmp)) {
8148 long len = RARRAY_LEN(tmp);
8149#if SIZEOF_LONG > SIZEOF_INT
8150 if (len > INT_MAX) {
8151 rb_raise(rb_eArgError, "too many arguments");
8152 }
8153#endif
8154 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8155 RB_GC_GUARD(tmp);
8156 }
8157 else {
8158 StringValue(pname);
8159 execarg_obj = Qnil;
8160 if (!is_popen_fork(pname))
8161 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8162 }
8163 if (!NIL_P(execarg_obj)) {
8164 if (!NIL_P(opt))
8165 opt = rb_execarg_extract_options(execarg_obj, opt);
8166 if (!NIL_P(env))
8167 rb_execarg_setenv(execarg_obj, env);
8168 }
8169 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8170 modestr = rb_io_oflags_modestr(oflags);
8171
8172 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8173}
8174
8175static VALUE
8176popen_finish(VALUE port, VALUE klass)
8177{
8178 if (NIL_P(port)) {
8179 /* child */
8180 if (rb_block_given_p()) {
8181 rb_protect(rb_yield, Qnil, NULL);
8182 rb_io_flush(rb_ractor_stdout());
8183 rb_io_flush(rb_ractor_stderr());
8184 _exit(EXIT_SUCCESS);
8185 }
8186 return Qnil;
8187 }
8188 RBASIC_SET_CLASS(port, klass);
8189 if (rb_block_given_p()) {
8190 return rb_ensure(rb_yield, port, pipe_close, port);
8191 }
8192 return port;
8193}
8194
8195#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8196struct popen_writer_arg {
8197 char *const *argv;
8198 struct popen_arg popen;
8199};
8200
8201static int
8202exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8203{
8204 struct popen_writer_arg *pw = arg;
8205 pw->popen.modef = FMODE_WRITABLE;
8206 popen_redirect(&pw->popen);
8207 execv(pw->argv[0], pw->argv);
8208 strlcpy(errmsg, strerror(errno), buflen);
8209 return -1;
8210}
8211#endif
8212
8213FILE *
8214ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8215{
8216#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8217# ifdef HAVE_WORKING_FORK
8218 struct popen_writer_arg pw;
8219 int *const write_pair = pw.popen.pair;
8220# else
8221 int write_pair[2];
8222# endif
8223
8224 *pid = -1;
8225 if (cloexec_pipe(write_pair, 0, false) == 0) {
8226# ifdef HAVE_WORKING_FORK
8227 pw.argv = argv;
8228 int status;
8229 char errmsg[80] = {'\0'};
8230 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8231# else
8232 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8233 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8234# endif
8235 close(write_pair[0]);
8236 if (*pid < 0) {
8237 close(write_pair[1]);
8238 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8239 }
8240 else {
8241 return fdopen(write_pair[1], "w");
8242 }
8243 }
8244#endif
8245 return NULL;
8246}
8247
8248static VALUE
8249rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8250{
8251 int oflags;
8252 enum rb_io_mode fmode;
8253 struct rb_io_encoding convconfig;
8254 mode_t perm;
8255
8256 FilePathValue(fname);
8257
8258 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8259 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8260
8261 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8262
8263 return io;
8264}
8265
8266/*
8267 * Document-method: File::open
8268 *
8269 * :markup: markdown
8270 *
8271 * call-seq:
8272 * File.open(path, mode = 'r', permissions = 0666, **options) -> file
8273 * File.open(path, mode = 'r', permissions = 0666, **options) {|file| ... } -> object
8274 *
8275 * Creates a new \File object via File.new with the given arguments.
8276 *
8277 * With no block given, returns the \File object.
8278 *
8279 * With a block given, calls the block with the \File object,
8280 * closes the \File object, and returns the block's value:
8281 *
8282 * ```ruby
8283 * File.open('doc/maintainers.md') {|file| file.size } # => 14900
8284 * ```
8285 *
8286 * Note that the \File object is automatically closed
8287 * even if the block raises an exception.
8288 */
8289
8290/*
8291 * Document-method: IO::open
8292 *
8293 * :markup: markdown
8294 *
8295 * call-seq:
8296 * IO.open(fd, mode = 'r', **options) -> io
8297 * IO.open(fd, mode = 'r', **options) {|io| ... } -> object
8298 *
8299 * Creates a new \IO object via IO.new with the given arguments.
8300 *
8301 * With no block given, returns the \IO object.
8302 *
8303 * With a block given, calls the block with the \IO object,
8304 * closes the \IO object, and returns the block’s value:
8305 *
8306 * ```ruby
8307 * fd = File.sysopen('doc/maintainers.md') # => 6
8308 * IO.open(fd) {|io| io.read.size } # => 14897
8309 * ```
8310 */
8311
8312static VALUE
8313rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8314{
8316
8317 if (rb_block_given_p()) {
8318 return rb_ensure(rb_yield, io, io_close, io);
8319 }
8320
8321 return io;
8322}
8323
8324/*
8325 * call-seq:
8326 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8327 *
8328 * Opens the file at the given path with the given mode and permissions;
8329 * returns the integer file descriptor.
8330 *
8331 * If the file is to be readable, it must exist;
8332 * if the file is to be writable and does not exist,
8333 * it is created with the given permissions:
8334 *
8335 * File.write('t.tmp', '') # => 0
8336 * IO.sysopen('t.tmp') # => 8
8337 * IO.sysopen('t.tmp', 'w') # => 9
8338 *
8339 *
8340 */
8341
8342static VALUE
8343rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8344{
8345 VALUE fname, vmode, vperm;
8346 VALUE intmode;
8347 int oflags, fd;
8348 mode_t perm;
8349
8350 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8351 FilePathValue(fname);
8352
8353 if (NIL_P(vmode))
8354 oflags = O_RDONLY;
8355 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8356 oflags = NUM2INT(intmode);
8357 else {
8358 StringValue(vmode);
8359 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8360 }
8361 if (NIL_P(vperm)) perm = 0666;
8362 else perm = NUM2MODET(vperm);
8363
8364 RB_GC_GUARD(fname) = rb_str_new4(fname);
8365 fd = rb_sysopen(fname, oflags, perm);
8366 return INT2NUM(fd);
8367}
8368
8369/*
8370 * call-seq:
8371 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8372 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8373 *
8374 * Creates an IO object connected to the given file.
8375 *
8376 * With no block given, file stream is returned:
8377 *
8378 * open('t.txt') # => #<File:t.txt>
8379 *
8380 * With a block given, calls the block with the open file stream,
8381 * then closes the stream:
8382 *
8383 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8384 *
8385 * Output:
8386 *
8387 * #<File:t.txt>
8388 *
8389 * See File.open for details.
8390 *
8391 */
8392
8393static VALUE
8394rb_f_open(int argc, VALUE *argv, VALUE _)
8395{
8396 ID to_open = 0;
8397 int redirect = FALSE;
8398
8399 if (argc >= 1) {
8400 CONST_ID(to_open, "to_open");
8401 if (rb_respond_to(argv[0], to_open)) {
8402 redirect = TRUE;
8403 }
8404 else {
8405 VALUE tmp = argv[0];
8406 FilePathValue(tmp);
8407 if (NIL_P(tmp)) {
8408 redirect = TRUE;
8409 }
8410 else {
8411 argv[0] = tmp;
8412 }
8413 }
8414 }
8415 if (redirect) {
8416 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8417
8418 if (rb_block_given_p()) {
8419 return rb_ensure(rb_yield, io, io_close, io);
8420 }
8421 return io;
8422 }
8423 return rb_io_s_open(argc, argv, rb_cFile);
8424}
8425
8426static VALUE
8427rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8428 const struct rb_io_encoding *convconfig, mode_t perm)
8429{
8430 return rb_file_open_generic(io_alloc(klass), filename,
8431 oflags, fmode, convconfig, perm);
8432}
8433
8434static VALUE
8435rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8436{
8437 int oflags;
8438 enum rb_io_mode fmode;
8439 struct rb_io_encoding convconfig;
8440 mode_t perm;
8441
8442 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8443 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8444 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8445}
8446
8447static VALUE
8448io_reopen(VALUE io, VALUE nfile)
8449{
8450 rb_io_t *fptr, *orig;
8451 int fd, fd2;
8452 rb_off_t pos = 0;
8453
8454 nfile = rb_io_get_io(nfile);
8455 GetOpenFile(io, fptr);
8456 GetOpenFile(nfile, orig);
8457
8458 if (fptr == orig) return io;
8459 if (RUBY_IO_EXTERNAL_P(fptr)) {
8460 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8461 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8462 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8463 rb_raise(rb_eArgError,
8464 "%s can't change access mode from \"%s\" to \"%s\"",
8465 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8466 rb_io_fmode_modestr(orig->mode));
8467 }
8468 }
8469 flush_before_seek(fptr, true);
8470 /* in flush_before_seek, clear_codeconv called only if rbuf is filled */
8471 clear_codeconv(fptr);
8472 if (orig->mode & FMODE_READABLE) {
8473 pos = io_tell(orig);
8474 }
8475 if (orig->mode & FMODE_WRITABLE) {
8476 if (io_fflush(orig) < 0)
8477 rb_sys_fail_on_write(fptr);
8478 }
8479
8480 /* copy rb_io_t structure */
8481 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8482 fptr->encs = orig->encs;
8483 fptr->pid = orig->pid;
8484 fptr->lineno = orig->lineno;
8485 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8486 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8487 fptr_copy_finalizer(fptr, orig);
8488
8489 fd = fptr->fd;
8490 fd2 = orig->fd;
8491 if (fd != fd2) {
8492 // Interrupt all usage of the old file descriptor:
8493 rb_thread_io_close_interrupt(fptr);
8494 rb_thread_io_close_wait(fptr);
8495
8496 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8497 /* need to keep FILE objects of stdin, stdout and stderr */
8498 if (rb_cloexec_dup2(fd2, fd) < 0)
8499 rb_sys_fail_path(orig->pathv);
8500 rb_update_max_fd(fd);
8501 }
8502 else {
8503 fclose(fptr->stdio_file);
8504 fptr->stdio_file = 0;
8505 fptr->fd = -1;
8506 if (rb_cloexec_dup2(fd2, fd) < 0)
8507 rb_sys_fail_path(orig->pathv);
8508 rb_update_max_fd(fd);
8509 fptr->fd = fd;
8510 }
8511
8512 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8513 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8514 rb_sys_fail_path(fptr->pathv);
8515 }
8516 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8517 rb_sys_fail_path(orig->pathv);
8518 }
8519 }
8520 }
8521
8522 if (fptr->mode & FMODE_BINMODE) {
8523 rb_io_binmode(io);
8524 }
8525
8526 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8527 return io;
8528}
8529
8530#ifdef _WIN32
8531int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8532#else
8533static int
8534rb_freopen(VALUE fname, const char *mode, FILE *fp)
8535{
8536 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8537 RB_GC_GUARD(fname);
8538 return errno;
8539 }
8540 return 0;
8541}
8542#endif
8543
8544/*
8545 * call-seq:
8546 * reopen(other_io) -> self
8547 * reopen(path, mode = 'r', **opts) -> self
8548 *
8549 * Reassociates the stream with another stream,
8550 * which may be of a different class.
8551 * This method may be used to redirect an existing stream
8552 * to a new destination.
8553 *
8554 * With argument +other_io+ given, reassociates with that stream:
8555 *
8556 * # Redirect $stdin from a file.
8557 * f = File.open('t.txt')
8558 * $stdin.reopen(f)
8559 * f.close
8560 *
8561 * # Redirect $stdout to a file.
8562 * f = File.open('t.tmp', 'w')
8563 * $stdout.reopen(f)
8564 * f.close
8565 *
8566 * With argument +path+ given, reassociates with a new stream to that file path:
8567 *
8568 * $stdin.reopen('t.txt')
8569 * $stdout.reopen('t.tmp', 'w')
8570 *
8571 * Optional keyword arguments +opts+ specify:
8572 *
8573 * - {Open Options}[rdoc-ref:IO@Open+Options].
8574 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8575 *
8576 */
8577
8578static VALUE
8579rb_io_reopen(int argc, VALUE *argv, VALUE file)
8580{
8581 VALUE fname, nmode, opt;
8582 int oflags;
8583 rb_io_t *fptr;
8584
8585 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8586 VALUE tmp = rb_io_check_io(fname);
8587 if (!NIL_P(tmp)) {
8588 return io_reopen(file, tmp);
8589 }
8590 }
8591
8592 FilePathValue(fname);
8593 rb_io_taint_check(file);
8594 fptr = RFILE(file)->fptr;
8595 if (!fptr) {
8596 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8597 }
8598
8599 if (!NIL_P(nmode) || !NIL_P(opt)) {
8600 enum rb_io_mode fmode;
8601 struct rb_io_encoding convconfig;
8602
8603 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8604 if (RUBY_IO_EXTERNAL_P(fptr) &&
8605 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8606 (fptr->mode & FMODE_READWRITE)) {
8607 rb_raise(rb_eArgError,
8608 "%s can't change access mode from \"%s\" to \"%s\"",
8609 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8610 rb_io_fmode_modestr(fmode));
8611 }
8612 fptr->mode = fmode;
8613 fptr->encs = convconfig;
8614 }
8615 else {
8616 oflags = rb_io_fmode_oflags(fptr->mode);
8617 }
8618
8619 fptr->pathv = fname;
8620 if (fptr->fd < 0) {
8621 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8622 fptr->stdio_file = 0;
8623 return file;
8624 }
8625
8626 if (fptr->mode & FMODE_WRITABLE) {
8627 if (io_fflush(fptr) < 0)
8628 rb_sys_fail_on_write(fptr);
8629 }
8630 fptr->rbuf.off = fptr->rbuf.len = 0;
8631 clear_codeconv(fptr);
8632
8633 if (fptr->stdio_file) {
8634 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8635 rb_io_oflags_modestr(oflags),
8636 fptr->stdio_file);
8637 if (e) rb_syserr_fail_path(e, fptr->pathv);
8638 fptr->fd = fileno(fptr->stdio_file);
8639 rb_fd_fix_cloexec(fptr->fd);
8640#ifdef USE_SETVBUF
8641 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8642 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8643#endif
8644 if (fptr->stdio_file == stderr) {
8645 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8646 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8647 }
8648 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8649 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8650 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8651 }
8652 }
8653 else {
8654 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8655 int err = 0;
8656 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8657 err = errno;
8658 (void)close(tmpfd);
8659 if (err) {
8660 rb_syserr_fail_path(err, fptr->pathv);
8661 }
8662 }
8663
8664 return file;
8665}
8666
8667/* :nodoc: */
8668static VALUE
8669rb_io_init_copy(VALUE dest, VALUE io)
8670{
8671 rb_io_t *fptr, *orig;
8672 int fd;
8673 VALUE write_io;
8674 rb_off_t pos;
8675
8676 io = rb_io_get_io(io);
8677 if (!OBJ_INIT_COPY(dest, io)) return dest;
8678 GetOpenFile(io, orig);
8679 MakeOpenFile(dest, fptr);
8680
8681 rb_io_flush(io);
8682
8683 /* copy rb_io_t structure */
8684 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8685 fptr->encs = orig->encs;
8686 fptr->pid = orig->pid;
8687 fptr->lineno = orig->lineno;
8688 fptr->timeout = orig->timeout;
8689
8690 ccan_list_head_init(&fptr->blocking_operations);
8691 fptr->closing_ec = NULL;
8692 fptr->wakeup_mutex = Qnil;
8693 fptr->fork_generation = GET_VM()->fork_gen;
8694
8695 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8696 fptr_copy_finalizer(fptr, orig);
8697
8698 fd = ruby_dup(orig->fd);
8699 fptr->fd = fd;
8700 pos = io_tell(orig);
8701 if (0 <= pos)
8702 io_seek(fptr, pos, SEEK_SET);
8703 if (fptr->mode & FMODE_BINMODE) {
8704 rb_io_binmode(dest);
8705 }
8706
8707 write_io = GetWriteIO(io);
8708 if (io != write_io) {
8709 write_io = rb_obj_dup(write_io);
8710 fptr->tied_io_for_writing = write_io;
8711 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8712 }
8713
8714 return dest;
8715}
8716
8717/*
8718 * call-seq:
8719 * printf(format_string, *objects) -> nil
8720 *
8721 * Formats and writes +objects+ to the stream.
8722 *
8723 * For details on +format_string+, see
8724 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8725 *
8726 */
8727
8728VALUE
8729rb_io_printf(int argc, const VALUE *argv, VALUE out)
8730{
8731 rb_io_write(out, rb_f_sprintf(argc, argv));
8732 return Qnil;
8733}
8734
8735/*
8736 * call-seq:
8737 * printf(format_string, *objects) -> nil
8738 * printf(io, format_string, *objects) -> nil
8739 *
8740 * Equivalent to:
8741 *
8742 * io.write(sprintf(format_string, *objects))
8743 *
8744 * For details on +format_string+, see
8745 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8746 *
8747 * With the single argument +format_string+, formats +objects+ into the string,
8748 * then writes the formatted string to $stdout:
8749 *
8750 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8751 *
8752 * Output (on $stdout):
8753 *
8754 * 0024 24 24.00#
8755 *
8756 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8757 * then writes the formatted string to +io+:
8758 *
8759 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8760 *
8761 * Output (on $stderr):
8762 *
8763 * 0024 24 24.00# => nil
8764 *
8765 * With no arguments, does nothing.
8766 *
8767 */
8768
8769static VALUE
8770rb_f_printf(int argc, VALUE *argv, VALUE _)
8771{
8772 VALUE out;
8773
8774 if (argc == 0) return Qnil;
8775 if (RB_TYPE_P(argv[0], T_STRING)) {
8776 out = rb_ractor_stdout();
8777 }
8778 else {
8779 out = argv[0];
8780 argv++;
8781 argc--;
8782 }
8783 rb_io_write(out, rb_f_sprintf(argc, argv));
8784
8785 return Qnil;
8786}
8787
8788extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
8789
8790static void
8791deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8792{
8793 rb_deprecated_str_setter(val, id, &val);
8794 if (!NIL_P(val)) {
8795 if (rb_str_equal(val, rb_default_rs)) {
8796 val = rb_default_rs;
8797 }
8798 else {
8799 val = rb_str_frozen_bare_string(val);
8800 }
8801 }
8802 *var = val;
8803}
8804
8805/*
8806 * call-seq:
8807 * print(*objects) -> nil
8808 *
8809 * Writes the given objects to the stream; returns +nil+.
8810 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8811 * (<tt>$\</tt>), if it is not +nil+.
8812 * See {Line IO}[rdoc-ref:IO@Line+IO].
8813 *
8814 * With argument +objects+ given, for each object:
8815 *
8816 * - Converts via its method +to_s+ if not a string.
8817 * - Writes to the stream.
8818 * - If not the last object, writes the output field separator
8819 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8820 *
8821 * With default separators:
8822 *
8823 * f = File.open('t.tmp', 'w+')
8824 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8825 * p $OUTPUT_RECORD_SEPARATOR
8826 * p $OUTPUT_FIELD_SEPARATOR
8827 * f.print(*objects)
8828 * f.rewind
8829 * p f.read
8830 * f.close
8831 *
8832 * Output:
8833 *
8834 * nil
8835 * nil
8836 * "00.00/10+0izerozero"
8837 *
8838 * With specified separators:
8839 *
8840 * $\ = "\n"
8841 * $, = ','
8842 * f.rewind
8843 * f.print(*objects)
8844 * f.rewind
8845 * p f.read
8846 *
8847 * Output:
8848 *
8849 * "0,0.0,0/1,0+0i,zero,zero\n"
8850 *
8851 * With no argument given, writes the content of <tt>$_</tt>
8852 * (which is usually the most recent user input):
8853 *
8854 * f = File.open('t.tmp', 'w+')
8855 * gets # Sets $_ to the most recent user input.
8856 * f.print
8857 * f.close
8858 *
8859 */
8860
8861VALUE
8862rb_io_print(int argc, const VALUE *argv, VALUE out)
8863{
8864 int i;
8865 VALUE line;
8866
8867 /* if no argument given, print `$_' */
8868 if (argc == 0) {
8869 argc = 1;
8870 line = rb_lastline_get();
8871 argv = &line;
8872 }
8873 if (argc > 1 && !NIL_P(rb_output_fs)) {
8874 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8875 }
8876 for (i=0; i<argc; i++) {
8877 if (!NIL_P(rb_output_fs) && i>0) {
8878 rb_io_write(out, rb_output_fs);
8879 }
8880 rb_io_write(out, argv[i]);
8881 }
8882 if (argc > 0 && !NIL_P(rb_output_rs)) {
8883 rb_io_write(out, rb_output_rs);
8884 }
8885
8886 return Qnil;
8887}
8888
8889/*
8890 * call-seq:
8891 * print(*objects) -> nil
8892 *
8893 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8894 * this method is the straightforward way to write to <tt>$stdout</tt>.
8895 *
8896 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8897 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8898 * (<tt>$\</tt>), if it is not +nil+.
8899 *
8900 * With argument +objects+ given, for each object:
8901 *
8902 * - Converts via its method +to_s+ if not a string.
8903 * - Writes to <tt>stdout</tt>.
8904 * - If not the last object, writes the output field separator
8905 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8906 *
8907 * With default separators:
8908 *
8909 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8910 * $OUTPUT_RECORD_SEPARATOR
8911 * $OUTPUT_FIELD_SEPARATOR
8912 * print(*objects)
8913 *
8914 * Output:
8915 *
8916 * nil
8917 * nil
8918 * 00.00/10+0izerozero
8919 *
8920 * With specified separators:
8921 *
8922 * $OUTPUT_RECORD_SEPARATOR = "\n"
8923 * $OUTPUT_FIELD_SEPARATOR = ','
8924 * print(*objects)
8925 *
8926 * Output:
8927 *
8928 * 0,0.0,0/1,0+0i,zero,zero
8929 *
8930 * With no argument given, writes the content of <tt>$_</tt>
8931 * (which is usually the most recent user input):
8932 *
8933 * gets # Sets $_ to the most recent user input.
8934 * print # Prints $_.
8935 *
8936 */
8937
8938static VALUE
8939rb_f_print(int argc, const VALUE *argv, VALUE _)
8940{
8941 rb_io_print(argc, argv, rb_ractor_stdout());
8942 return Qnil;
8943}
8944
8945/*
8946 * call-seq:
8947 * putc(object) -> object
8948 *
8949 * Writes a character to the stream.
8950 * See {Character IO}[rdoc-ref:IO@Character+IO].
8951 *
8952 * If +object+ is numeric, converts to integer if necessary,
8953 * then writes the character whose code is the
8954 * least significant byte;
8955 * if +object+ is a string, writes the first character:
8956 *
8957 * $stdout.putc "A"
8958 * $stdout.putc 65
8959 *
8960 * Output:
8961 *
8962 * AA
8963 *
8964 */
8965
8966static VALUE
8967rb_io_putc(VALUE io, VALUE ch)
8968{
8969 VALUE str;
8970 if (RB_TYPE_P(ch, T_STRING)) {
8971 str = rb_str_substr(ch, 0, 1);
8972 }
8973 else {
8974 char c = NUM2CHR(ch);
8975 str = rb_str_new(&c, 1);
8976 }
8977 rb_io_write(io, str);
8978 return ch;
8979}
8980
8981#define forward(obj, id, argc, argv) \
8982 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8983#define forward_public(obj, id, argc, argv) \
8984 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8985#define forward_current(id, argc, argv) \
8986 forward_public(ARGF.current_file, id, argc, argv)
8987
8988/*
8989 * call-seq:
8990 * putc(int) -> int
8991 *
8992 * Equivalent to:
8993 *
8994 * $stdout.putc(int)
8995 *
8996 * See IO#putc for important information regarding multi-byte characters.
8997 *
8998 */
8999
9000static VALUE
9001rb_f_putc(VALUE recv, VALUE ch)
9002{
9003 VALUE r_stdout = rb_ractor_stdout();
9004 if (recv == r_stdout) {
9005 return rb_io_putc(recv, ch);
9006 }
9007 return forward(r_stdout, rb_intern("putc"), 1, &ch);
9008}
9009
9010
9011int
9012rb_str_end_with_asciichar(VALUE str, int c)
9013{
9014 long len = RSTRING_LEN(str);
9015 const char *ptr = RSTRING_PTR(str);
9016 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
9017 int n;
9018
9019 if (len == 0) return 0;
9020 if ((n = rb_enc_mbminlen(enc)) == 1) {
9021 return ptr[len - 1] == c;
9022 }
9023 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
9024}
9025
9026static VALUE
9027io_puts_ary(VALUE ary, VALUE out, int recur)
9028{
9029 VALUE tmp;
9030 long i;
9031
9032 if (recur) {
9033 tmp = rb_str_new2("[...]");
9034 rb_io_puts(1, &tmp, out);
9035 return Qtrue;
9036 }
9037 ary = rb_check_array_type(ary);
9038 if (NIL_P(ary)) return Qfalse;
9039 for (i=0; i<RARRAY_LEN(ary); i++) {
9040 tmp = RARRAY_AREF(ary, i);
9041 rb_io_puts(1, &tmp, out);
9042 }
9043 return Qtrue;
9044}
9045
9046/*
9047 * call-seq:
9048 * puts(*objects) -> nil
9049 *
9050 * Writes the given +objects+ to the stream, which must be open for writing;
9051 * returns +nil+.\
9052 * Writes a newline after each that does not already end with a newline sequence.
9053 * If called without arguments, writes a newline.
9054 * See {Line IO}[rdoc-ref:IO@Line+IO].
9055 *
9056 * Note that each added newline is the character <tt>"\n"</tt>,
9057 * not the output record separator (<tt>$\</tt>).
9058 *
9059 * Treatment for each object:
9060 *
9061 * - String: writes the string.
9062 * - Neither string nor array: writes <tt>object.to_s</tt>.
9063 * - Array: writes each element of the array; arrays may be nested.
9064 *
9065 * To keep these examples brief, we define this helper method:
9066 *
9067 * def show(*objects)
9068 * # Puts objects to file.
9069 * f = File.new('t.tmp', 'w+')
9070 * f.puts(objects)
9071 * # Return file content.
9072 * f.rewind
9073 * p f.read
9074 * f.close
9075 * end
9076 *
9077 * # Strings without newlines.
9078 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
9079 * # Strings, some with newlines.
9080 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
9081 *
9082 * # Neither strings nor arrays:
9083 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
9084 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
9085 *
9086 * # Array of strings.
9087 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
9088 * # Nested arrays.
9089 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
9090 *
9091 */
9092
9093VALUE
9094rb_io_puts(int argc, const VALUE *argv, VALUE out)
9095{
9096 VALUE line, args[2];
9097
9098 /* if no argument given, print newline. */
9099 if (argc == 0) {
9100 rb_io_write(out, rb_default_rs);
9101 return Qnil;
9102 }
9103 for (int i = 0; i < argc; i++) {
9104 // Convert the argument to a string:
9105 if (RB_TYPE_P(argv[i], T_STRING)) {
9106 line = argv[i];
9107 }
9108 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9109 continue;
9110 }
9111 else {
9112 line = rb_obj_as_string(argv[i]);
9113 }
9114
9115 // Write the line:
9116 int n = 0;
9117 if (RSTRING_LEN(line) == 0) {
9118 args[n++] = rb_default_rs;
9119 }
9120 else {
9121 args[n++] = line;
9122 if (!rb_str_end_with_asciichar(line, '\n')) {
9123 args[n++] = rb_default_rs;
9124 }
9125 }
9126
9127 rb_io_writev(out, n, args);
9128 }
9129
9130 return Qnil;
9131}
9132
9133/*
9134 * call-seq:
9135 * puts(*objects) -> nil
9136 *
9137 * Equivalent to
9138 *
9139 * $stdout.puts(objects)
9140 */
9141
9142static VALUE
9143rb_f_puts(int argc, VALUE *argv, VALUE recv)
9144{
9145 VALUE r_stdout = rb_ractor_stdout();
9146 if (recv == r_stdout) {
9147 return rb_io_puts(argc, argv, recv);
9148 }
9149 return forward(r_stdout, rb_intern("puts"), argc, argv);
9150}
9151
9152static VALUE
9153rb_p_write(VALUE str)
9154{
9155 VALUE args[2];
9156 args[0] = str;
9157 args[1] = rb_default_rs;
9158 VALUE r_stdout = rb_ractor_stdout();
9159 if (RB_TYPE_P(r_stdout, T_FILE) &&
9160 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9161 io_writev(2, args, r_stdout);
9162 }
9163 else {
9164 rb_io_writev(r_stdout, 2, args);
9165 }
9166 return Qnil;
9167}
9168
9169void
9170rb_p(VALUE obj) /* for debug print within C code */
9171{
9172 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9173}
9174
9175static VALUE
9176rb_p_result(int argc, const VALUE *argv)
9177{
9178 VALUE ret = Qnil;
9179
9180 if (argc == 1) {
9181 ret = argv[0];
9182 }
9183 else if (argc > 1) {
9184 ret = rb_ary_new4(argc, argv);
9185 }
9186 VALUE r_stdout = rb_ractor_stdout();
9187 if (RB_TYPE_P(r_stdout, T_FILE)) {
9188 rb_uninterruptible(rb_io_flush, r_stdout);
9189 }
9190 return ret;
9191}
9192
9193/*
9194 * call-seq:
9195 * p(object) -> obj
9196 * p(*objects) -> array of objects
9197 * p -> nil
9198 *
9199 * For each object +obj+, executes:
9200 *
9201 * $stdout.write(obj.inspect, "\n")
9202 *
9203 * With one object given, returns the object;
9204 * with multiple objects given, returns an array containing the objects;
9205 * with no object given, returns +nil+.
9206 *
9207 * Examples:
9208 *
9209 * r = Range.new(0, 4)
9210 * p r # => 0..4
9211 * p [r, r, r] # => [0..4, 0..4, 0..4]
9212 * p # => nil
9213 *
9214 * Output:
9215 *
9216 * 0..4
9217 * [0..4, 0..4, 0..4]
9218 *
9219 * Kernel#p is designed for debugging purposes.
9220 * Ruby implementations may define Kernel#p to be uninterruptible
9221 * in whole or in part.
9222 * On CRuby, Kernel#p's writing of data is uninterruptible.
9223 */
9224
9225static VALUE
9226rb_f_p(int argc, VALUE *argv, VALUE self)
9227{
9228 int i;
9229 for (i=0; i<argc; i++) {
9230 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9231 rb_uninterruptible(rb_p_write, inspected);
9232 }
9233 return rb_p_result(argc, argv);
9234}
9235
9236/*
9237 * call-seq:
9238 * display(port = $>) -> nil
9239 *
9240 * Writes +self+ on the given port:
9241 *
9242 * 1.display
9243 * "cat".display
9244 * [ 4, 5, 6 ].display
9245 * puts
9246 *
9247 * Output:
9248 *
9249 * 1cat[4, 5, 6]
9250 *
9251 */
9252
9253static VALUE
9254rb_obj_display(int argc, VALUE *argv, VALUE self)
9255{
9256 VALUE out;
9257
9258 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9259 rb_io_write(out, self);
9260
9261 return Qnil;
9262}
9263
9264static int
9265rb_stderr_to_original_p(VALUE err)
9266{
9267 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9268}
9269
9270void
9271rb_write_error2(const char *mesg, long len)
9272{
9273 VALUE out = rb_ractor_stderr();
9274 if (rb_stderr_to_original_p(out)) {
9275#ifdef _WIN32
9276 if (isatty(fileno(stderr))) {
9277 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9278 }
9279#endif
9280 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9281 /* failed to write to stderr, what can we do? */
9282 return;
9283 }
9284 }
9285 else {
9286 rb_io_write(out, rb_str_new(mesg, len));
9287 }
9288}
9289
9290void
9291rb_write_error(const char *mesg)
9292{
9293 rb_write_error2(mesg, strlen(mesg));
9294}
9295
9296void
9297rb_write_error_str(VALUE mesg)
9298{
9299 VALUE out = rb_ractor_stderr();
9300 /* a stopgap measure for the time being */
9301 if (rb_stderr_to_original_p(out)) {
9302 size_t len = (size_t)RSTRING_LEN(mesg);
9303#ifdef _WIN32
9304 if (isatty(fileno(stderr))) {
9305 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9306 }
9307#endif
9308 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9309 RB_GC_GUARD(mesg);
9310 return;
9311 }
9312 }
9313 else {
9314 /* may unlock GVL, and */
9315 rb_io_write(out, mesg);
9316 }
9317}
9318
9319int
9320rb_stderr_tty_p(void)
9321{
9322 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9323 return isatty(fileno(stderr));
9324 return 0;
9325}
9326
9327static void
9328must_respond_to(ID mid, VALUE val, ID id)
9329{
9330 if (!rb_respond_to(val, mid)) {
9331 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9332 rb_id2str(id), rb_id2str(mid),
9333 rb_obj_class(val));
9334 }
9335}
9336
9337static void
9338stdin_setter(VALUE val, ID id, VALUE *ptr)
9339{
9341}
9342
9343static VALUE
9344stdin_getter(ID id, VALUE *ptr)
9345{
9346 return rb_ractor_stdin();
9347}
9348
9349static void
9350stdout_setter(VALUE val, ID id, VALUE *ptr)
9351{
9352 must_respond_to(id_write, val, id);
9354}
9355
9356static VALUE
9357stdout_getter(ID id, VALUE *ptr)
9358{
9359 return rb_ractor_stdout();
9360}
9361
9362static void
9363stderr_setter(VALUE val, ID id, VALUE *ptr)
9364{
9365 must_respond_to(id_write, val, id);
9367}
9368
9369static VALUE
9370stderr_getter(ID id, VALUE *ptr)
9371{
9372 return rb_ractor_stderr();
9373}
9374
9375static VALUE
9376allocate_and_open_new_file(VALUE klass)
9377{
9378 VALUE self = io_alloc(klass);
9379 rb_io_make_open_file(self);
9380 return self;
9381}
9382
9383VALUE
9384rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9385{
9386 int state;
9387 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9388 if (state) {
9389 /* if we raised an exception allocating an IO object, but the caller
9390 intended to transfer ownership of this FD to us, close the fd before
9391 raising the exception. Otherwise, we would leak a FD - the caller
9392 expects GC to close the file, but we never got around to assigning
9393 it to a rb_io. */
9394 if (!(mode & FMODE_EXTERNAL)) {
9395 maygvl_close(descriptor, 0);
9396 }
9397 rb_jump_tag(state);
9398 }
9399
9400
9401 rb_io_t *io = RFILE(self)->fptr;
9402 io->self = self;
9403 io->fd = descriptor;
9404 io->mode = mode;
9405
9406 /* At this point, Ruby fully owns the descriptor, and will close it when
9407 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9408 in the rest of this method. */
9409
9410 if (NIL_P(path)) {
9411 io->pathv = Qnil;
9412 }
9413 else {
9414 StringValue(path);
9415 io->pathv = rb_str_new_frozen(path);
9416 }
9417
9418 io->timeout = timeout;
9419
9420 ccan_list_head_init(&io->blocking_operations);
9421 io->closing_ec = NULL;
9422 io->wakeup_mutex = Qnil;
9423 io->fork_generation = GET_VM()->fork_gen;
9424
9425 if (encoding) {
9426 io->encs = *encoding;
9427 }
9428
9429 rb_update_max_fd(descriptor);
9430
9431 return self;
9432}
9433
9434static VALUE
9435prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9436{
9437 VALUE path_value = Qnil;
9438 rb_encoding *e;
9439 struct rb_io_encoding convconfig;
9440
9441 if (path) {
9442 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9443 }
9444
9445 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9446 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9447 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9450#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9451 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9452 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9453 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9454#endif
9455 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9456 convconfig.ecopts = Qnil;
9457
9458 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9459 rb_io_t*io = RFILE(self)->fptr;
9460
9461 if (!io_check_tty(io)) {
9462#ifdef __CYGWIN__
9463 io->mode |= FMODE_BINMODE;
9464 setmode(fd, O_BINARY);
9465#endif
9466 }
9467
9468 return self;
9469}
9470
9471VALUE
9472rb_io_fdopen(int fd, int oflags, const char *path)
9473{
9474 VALUE klass = rb_cIO;
9475
9476 if (path && strcmp(path, "-")) klass = rb_cFile;
9477 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9478}
9479
9480static VALUE
9481prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9482{
9483 rb_io_t *fptr;
9484 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9485
9486 GetOpenFile(io, fptr);
9488#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9489 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9490 if (fmode & FMODE_READABLE) {
9492 }
9493#endif
9494 fptr->stdio_file = f;
9495
9496 return io;
9497}
9498
9499VALUE
9500rb_io_prep_stdin(void)
9501{
9502 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9503}
9504
9505VALUE
9506rb_io_prep_stdout(void)
9507{
9508 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9509}
9510
9511VALUE
9512rb_io_prep_stderr(void)
9513{
9514 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9515}
9516
9517FILE *
9519{
9520 if (!fptr->stdio_file) {
9521 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9522 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9523 }
9524 return fptr->stdio_file;
9525}
9526
9527static inline void
9528rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9529{
9530 buf->ptr = NULL;
9531 buf->off = 0;
9532 buf->len = 0;
9533 buf->capa = 0;
9534}
9535
9536static inline rb_io_t *
9537rb_io_fptr_new(void)
9538{
9539 rb_io_t *fp = ALLOC(rb_io_t);
9540 fp->self = Qnil;
9541 fp->fd = -1;
9542 fp->stdio_file = NULL;
9543 fp->mode = 0;
9544 fp->pid = 0;
9545 fp->lineno = 0;
9546 fp->pathv = Qnil;
9547 fp->finalize = 0;
9548 rb_io_buffer_init(&fp->wbuf);
9549 rb_io_buffer_init(&fp->rbuf);
9550 rb_io_buffer_init(&fp->cbuf);
9551 fp->readconv = NULL;
9552 fp->writeconv = NULL;
9554 fp->writeconv_pre_ecflags = 0;
9556 fp->writeconv_initialized = 0;
9557 fp->tied_io_for_writing = 0;
9558 fp->encs.enc = NULL;
9559 fp->encs.enc2 = NULL;
9560 fp->encs.ecflags = 0;
9561 fp->encs.ecopts = Qnil;
9562 fp->write_lock = Qnil;
9563 fp->timeout = Qnil;
9564 ccan_list_head_init(&fp->blocking_operations);
9565 fp->closing_ec = NULL;
9566 fp->wakeup_mutex = Qnil;
9567 fp->fork_generation = GET_VM()->fork_gen;
9568 return fp;
9569}
9570
9571rb_io_t *
9572rb_io_make_open_file(VALUE obj)
9573{
9574 rb_io_t *fp = 0;
9575
9576 Check_Type(obj, T_FILE);
9577 if (RFILE(obj)->fptr) {
9578 rb_io_close(obj);
9579 rb_io_fptr_finalize(RFILE(obj)->fptr);
9580 RFILE(obj)->fptr = 0;
9581 }
9582 fp = rb_io_fptr_new();
9583 fp->self = obj;
9584 RFILE(obj)->fptr = fp;
9585 return fp;
9586}
9587
9588static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9589
9590/*
9591 * call-seq:
9592 * IO.new(fd, mode = 'r', **opts) -> io
9593 *
9594 * Creates and returns a new \IO object (file stream) from a file descriptor.
9595 *
9596 * \IO.new may be useful for interaction with low-level libraries.
9597 * For higher-level interactions, it may be simpler to create
9598 * the file stream using File.open.
9599 *
9600 * Argument +fd+ must be a valid file descriptor (integer):
9601 *
9602 * path = 't.tmp'
9603 * fd = IO.sysopen(path) # => 3
9604 * IO.new(fd) # => #<IO:fd 3>
9605 *
9606 * The new \IO object does not inherit encoding
9607 * (because the integer file descriptor does not have an encoding):
9608 *
9609 * File.read('t.ja') # => "こんにちは"
9610 * fd = IO.sysopen('t.ja', 'rb')
9611 * io = IO.new(fd)
9612 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9613 *
9614 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9615 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9616 *
9617 * IO.new(fd, 'w') # => #<IO:fd 3>
9618 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9619 *
9620 * Optional keyword arguments +opts+ specify:
9621 *
9622 * - {Open Options}[rdoc-ref:IO@Open+Options].
9623 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9624 *
9625 * Examples:
9626 *
9627 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9628 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9629 *
9630 */
9631
9632static VALUE
9633rb_io_initialize(int argc, VALUE *argv, VALUE io)
9634{
9635 VALUE fnum, vmode;
9636 VALUE opt;
9637
9638 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9639 return io_initialize(io, fnum, vmode, opt);
9640}
9641
9642static VALUE
9643io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9644{
9645 rb_io_t *fp;
9646 int fd, oflags = O_RDONLY;
9647 enum rb_io_mode fmode;
9648 struct rb_io_encoding convconfig;
9649#if defined(HAVE_FCNTL) && defined(F_GETFL)
9650 int ofmode;
9651#else
9652 struct stat st;
9653#endif
9654
9655 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9656
9657 fd = NUM2INT(fnum);
9658 if (rb_reserved_fd_p(fd)) {
9659 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9660 }
9661#if defined(HAVE_FCNTL) && defined(F_GETFL)
9662 oflags = fcntl(fd, F_GETFL);
9663 if (oflags == -1) rb_sys_fail(0);
9664#else
9665 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9666#endif
9667 rb_update_max_fd(fd);
9668#if defined(HAVE_FCNTL) && defined(F_GETFL)
9669 ofmode = rb_io_oflags_fmode(oflags);
9670 if (NIL_P(vmode)) {
9671 fmode = ofmode;
9672 }
9673 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9674 VALUE error = INT2FIX(EINVAL);
9676 }
9677#endif
9678 VALUE path = Qnil;
9679
9680 if (!NIL_P(opt)) {
9681 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9682 fmode |= FMODE_EXTERNAL;
9683 }
9684
9685 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9686 if (!NIL_P(path)) {
9687 StringValue(path);
9688 path = rb_str_new_frozen(path);
9689 }
9690 }
9691
9692 MakeOpenFile(io, fp);
9693 fp->self = io;
9694 fp->fd = fd;
9695 fp->mode = fmode;
9696 fp->encs = convconfig;
9697 fp->pathv = path;
9698 fp->timeout = Qnil;
9699 ccan_list_head_init(&fp->blocking_operations);
9700 fp->closing_ec = NULL;
9701 fp->wakeup_mutex = Qnil;
9702 fp->fork_generation = GET_VM()->fork_gen;
9703 clear_codeconv(fp);
9704 io_check_tty(fp);
9705 if (fileno(stdin) == fd)
9706 fp->stdio_file = stdin;
9707 else if (fileno(stdout) == fd)
9708 fp->stdio_file = stdout;
9709 else if (fileno(stderr) == fd)
9710 fp->stdio_file = stderr;
9711
9712 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9713 return io;
9714}
9715
9716/*
9717 * call-seq:
9718 * set_encoding_by_bom -> encoding or nil
9719 *
9720 * If the stream begins with a BOM
9721 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9722 * consumes the BOM and sets the external encoding accordingly;
9723 * returns the result encoding if found, or +nil+ otherwise:
9724 *
9725 * File.write('t.tmp', "\u{FEFF}abc")
9726 * io = File.open('t.tmp', 'rb')
9727 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9728 * io.close
9729 *
9730 * File.write('t.tmp', 'abc')
9731 * io = File.open('t.tmp', 'rb')
9732 * io.set_encoding_by_bom # => nil
9733 * io.close
9734 *
9735 * Raises an exception if the stream is not binmode
9736 * or its encoding has already been set.
9737 *
9738 */
9739
9740static VALUE
9741rb_io_set_encoding_by_bom(VALUE io)
9742{
9743 rb_io_t *fptr;
9744
9745 GetOpenFile(io, fptr);
9746 if (!(fptr->mode & FMODE_BINMODE)) {
9747 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9748 }
9749 if (fptr->encs.enc2) {
9750 rb_raise(rb_eArgError, "encoding conversion is set");
9751 }
9752 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9753 rb_raise(rb_eArgError, "encoding is set to %s already",
9754 rb_enc_name(fptr->encs.enc));
9755 }
9756 if (!io_set_encoding_by_bom(io)) return Qnil;
9757 return rb_enc_from_encoding(fptr->encs.enc);
9758}
9759
9760/*
9761 * :markup: markdown
9762 *
9763 * call-seq:
9764 * File.new(path, mode = 'r', permissions = 0666, **options) -> file
9765 *
9766 * Opens the file as specified by the given arguments.
9767 * Creates and returns a new open \File object for that file;
9768 * the opened file is in non-synchronous mode.
9769 *
9770 * Argument `path` must the string path to an existing filesystem entry:
9771 *
9772 * ```ruby
9773 * file = File.new('doc/maintainers.md') # => #<File:doc/maintainers.md>
9774 * file.close # Clean up.
9775 * tty = File.new('/dev/tty') # => #<File:/dev/tty>
9776 * tty.close # Clean up.
9777 * ```
9778 *
9779 * Note that the caller is responsible for closing the file;
9780 * see File.open for automatic closing.
9781 *
9782 * Optional argument `mode` (defaults to `'r'`) must specify a valid mode;
9783 * see [Access Modes](rdoc-ref:File@Access+Modes):
9784 *
9785 * ```ruby
9786 * file = File.new('t.tmp', 'w') # => #<File:t.tmp>
9787 * file.close # Clean up.
9788 * file = File.new('t.tmp', File::RDONLY) # => #<File:t.tmp>
9789 * file.close # Clean up.
9790 * ```
9791 *
9792 * Optional argument `permissions` (defaults to `0666`) must specify valid permissions;
9793 * see [File Permissions](rdoc-ref:File@File+Permissions):
9794 *
9795 * ```ruby
9796 * file = File.new('t.tmp', 'w', 0644) # => #<File:t.tmp>
9797 * file.close # Clean up.
9798 * file = File.new('t.tmp', 'w', 0444) # => #<File:t.tmp>
9799 * file.close # Clean up.
9800 * ```
9801 *
9802 * Optional keyword arguments `options` specify:
9803 *
9804 * - [Open Options](rdoc-ref:IO@Open+Options).
9805 * - [Encoding options](rdoc-ref:encodings.rdoc@Encoding+Options).
9806 *
9807 */
9808
9809static VALUE
9810rb_file_initialize(int argc, VALUE *argv, VALUE io)
9811{
9812 if (RFILE(io)->fptr) {
9813 rb_raise(rb_eRuntimeError, "reinitializing File");
9814 }
9815 VALUE fname, vmode, vperm, opt;
9816 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9817 if (posargc < 3) { /* perm is File only */
9818 VALUE fd = rb_check_to_int(fname);
9819
9820 if (!NIL_P(fd)) {
9821 return io_initialize(io, fd, vmode, opt);
9822 }
9823 }
9824 return rb_open_file(io, fname, vmode, vperm, opt);
9825}
9826
9827/* :nodoc: */
9828static VALUE
9829rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9830{
9831 if (rb_block_given_p()) {
9832 VALUE cname = rb_obj_as_string(klass);
9833
9834 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9835 cname, cname);
9836 }
9837 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9838}
9839
9840
9841/*
9842 * call-seq:
9843 * IO.for_fd(fd, mode = 'r', **opts) -> io
9844 *
9845 * Synonym for IO.new.
9846 *
9847 */
9848
9849static VALUE
9850rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9851{
9852 VALUE io = rb_obj_alloc(klass);
9853 rb_io_initialize(argc, argv, io);
9854 return io;
9855}
9856
9857/*
9858 * call-seq:
9859 * ios.autoclose? -> true or false
9860 *
9861 * Returns +true+ if the underlying file descriptor of _ios_ will be
9862 * closed at its finalization or at calling #close, otherwise +false+.
9863 */
9864
9865static VALUE
9866rb_io_autoclose_p(VALUE io)
9867{
9868 rb_io_t *fptr = RFILE(io)->fptr;
9869 rb_io_check_closed(fptr);
9870 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9871}
9872
9873/*
9874 * call-seq:
9875 * io.autoclose = bool -> true or false
9876 *
9877 * Sets auto-close flag.
9878 *
9879 * f = File.open(File::NULL)
9880 * IO.for_fd(f.fileno).close
9881 * f.gets # raises Errno::EBADF
9882 *
9883 * f = File.open(File::NULL)
9884 * g = IO.for_fd(f.fileno)
9885 * g.autoclose = false
9886 * g.close
9887 * f.gets # won't cause Errno::EBADF
9888 */
9889
9890static VALUE
9891rb_io_set_autoclose(VALUE io, VALUE autoclose)
9892{
9893 rb_io_t *fptr;
9894 GetOpenFile(io, fptr);
9895 if (!RTEST(autoclose))
9896 fptr->mode |= FMODE_EXTERNAL;
9897 else
9898 fptr->mode &= ~FMODE_EXTERNAL;
9899 return autoclose;
9900}
9901
9902static VALUE
9903io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9904{
9905 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9906
9907 if (!RB_TEST(result)) {
9908 return Qnil;
9909 }
9910
9911 int mask = RB_NUM2INT(result);
9912
9913 if (mask & event) {
9914 if (return_io)
9915 return io;
9916 else
9917 return result;
9918 }
9919 else {
9920 return Qfalse;
9921 }
9922}
9923
9924/*
9925 * call-seq:
9926 * io.wait_readable -> truthy or falsy
9927 * io.wait_readable(timeout) -> truthy or falsy
9928 *
9929 * Waits until IO is readable and returns a truthy value, or a falsy
9930 * value when times out. Returns a truthy value immediately when
9931 * buffered data is available.
9932 */
9933
9934static VALUE
9935io_wait_readable(int argc, VALUE *argv, VALUE io)
9936{
9937 rb_io_t *fptr;
9938
9939 RB_IO_POINTER(io, fptr);
9941
9942 if (rb_io_read_pending(fptr)) return Qtrue;
9943
9944 rb_check_arity(argc, 0, 1);
9945 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9946
9947 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9948}
9949
9950/*
9951 * call-seq:
9952 * io.wait_writable -> truthy or falsy
9953 * io.wait_writable(timeout) -> truthy or falsy
9954 *
9955 * Waits until IO is writable and returns a truthy value or a falsy
9956 * value when times out.
9957 */
9958static VALUE
9959io_wait_writable(int argc, VALUE *argv, VALUE io)
9960{
9961 rb_io_t *fptr;
9962
9963 RB_IO_POINTER(io, fptr);
9965
9966 rb_check_arity(argc, 0, 1);
9967 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9968
9969 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9970}
9971
9972/*
9973 * call-seq:
9974 * io.wait_priority -> truthy or falsy
9975 * io.wait_priority(timeout) -> truthy or falsy
9976 *
9977 * Waits until IO is priority and returns a truthy value or a falsy
9978 * value when times out. Priority data is sent and received using
9979 * the Socket::MSG_OOB flag and is typically limited to streams.
9980 */
9981static VALUE
9982io_wait_priority(int argc, VALUE *argv, VALUE io)
9983{
9984 rb_io_t *fptr = NULL;
9985
9986 RB_IO_POINTER(io, fptr);
9988
9989 if (rb_io_read_pending(fptr)) return Qtrue;
9990
9991 rb_check_arity(argc, 0, 1);
9992 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9993
9994 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9995}
9996
9997static int
9998wait_mode_sym(VALUE mode)
9999{
10000 if (mode == ID2SYM(rb_intern("r"))) {
10001 return RB_WAITFD_IN;
10002 }
10003 if (mode == ID2SYM(rb_intern("read"))) {
10004 return RB_WAITFD_IN;
10005 }
10006 if (mode == ID2SYM(rb_intern("readable"))) {
10007 return RB_WAITFD_IN;
10008 }
10009 if (mode == ID2SYM(rb_intern("w"))) {
10010 return RB_WAITFD_OUT;
10011 }
10012 if (mode == ID2SYM(rb_intern("write"))) {
10013 return RB_WAITFD_OUT;
10014 }
10015 if (mode == ID2SYM(rb_intern("writable"))) {
10016 return RB_WAITFD_OUT;
10017 }
10018 if (mode == ID2SYM(rb_intern("rw"))) {
10019 return RB_WAITFD_IN|RB_WAITFD_OUT;
10020 }
10021 if (mode == ID2SYM(rb_intern("read_write"))) {
10022 return RB_WAITFD_IN|RB_WAITFD_OUT;
10023 }
10024 if (mode == ID2SYM(rb_intern("readable_writable"))) {
10025 return RB_WAITFD_IN|RB_WAITFD_OUT;
10026 }
10027
10028 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
10029}
10030
10031static inline enum rb_io_event
10032io_event_from_value(VALUE value)
10033{
10034 int events = RB_NUM2INT(value);
10035
10036 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
10037
10038 return events;
10039}
10040
10041/*
10042 * call-seq:
10043 * io.wait(events, timeout) -> event mask, false or nil
10044 * io.wait(*event_symbols[, timeout]) -> self, true, or false
10045 *
10046 * Waits until the IO becomes ready for the specified events and returns the
10047 * subset of events that become ready, or a falsy value when times out.
10048 *
10049 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
10050 * +IO::PRIORITY+.
10051 *
10052 * Returns an event mask (truthy value) immediately when buffered data is
10053 * available.
10054 *
10055 * The second form: if one or more event symbols (+:read+, +:write+, or
10056 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
10057 * corresponding to those symbols. In this form, +timeout+ is optional, the
10058 * order of the arguments is arbitrary, and returns +io+ if any of the
10059 * events is ready.
10060 */
10061
10062static VALUE
10063io_wait(int argc, VALUE *argv, VALUE io)
10064{
10065 VALUE timeout = Qundef;
10066 enum rb_io_event events = 0;
10067 int return_io = 0;
10068
10069 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
10070 // We'd prefer to return the actual mask, but this form would return the io itself:
10071 return_io = 1;
10072
10073 // Slow/messy path:
10074 for (int i = 0; i < argc; i += 1) {
10075 if (RB_SYMBOL_P(argv[i])) {
10076 events |= wait_mode_sym(argv[i]);
10077 }
10078 else if (UNDEF_P(timeout)) {
10079 rb_time_interval(timeout = argv[i]);
10080 }
10081 else {
10082 rb_raise(rb_eArgError, "timeout given more than once");
10083 }
10084 }
10085
10086 if (UNDEF_P(timeout)) timeout = Qnil;
10087
10088 if (events == 0) {
10089 events = RUBY_IO_READABLE;
10090 }
10091 }
10092 else /* argc == 2 and neither are symbols */ {
10093 // This is the fast path:
10094 events = io_event_from_value(argv[0]);
10095 timeout = argv[1];
10096 }
10097
10098 if (events & RUBY_IO_READABLE) {
10099 rb_io_t *fptr = NULL;
10100 RB_IO_POINTER(io, fptr);
10101
10102 if (rb_io_read_pending(fptr)) {
10103 // This was the original behaviour:
10104 if (return_io) return Qtrue;
10105 // New behaviour always returns an event mask:
10106 else return RB_INT2NUM(RUBY_IO_READABLE);
10107 }
10108 }
10109
10110 return io_wait_event(io, events, timeout, return_io);
10111}
10112
10113static void
10114argf_mark_and_move(void *ptr)
10115{
10116 struct argf *p = ptr;
10117 rb_gc_mark_and_move(&p->filename);
10118 rb_gc_mark_and_move(&p->current_file);
10119 rb_gc_mark_and_move(&p->argv);
10120 rb_gc_mark_and_move(&p->inplace);
10121 rb_gc_mark_and_move(&p->encs.ecopts);
10122}
10123
10124static size_t
10125argf_memsize(const void *ptr)
10126{
10127 const struct argf *p = ptr;
10128 size_t size = sizeof(*p);
10129 return size;
10130}
10131
10132static const rb_data_type_t argf_type = {
10133 "ARGF",
10134 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10135 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10136};
10137
10138static inline void
10139argf_init(VALUE argf, struct argf *p, VALUE v)
10140{
10141 p->filename = Qnil;
10142 p->current_file = Qnil;
10143 p->lineno = 0;
10144 RB_OBJ_WRITE(argf, &p->argv, v);
10145}
10146
10147static VALUE
10148argf_alloc(VALUE klass)
10149{
10150 struct argf *p;
10151 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10152
10153 argf_init(argf, p, Qnil);
10154 return argf;
10155}
10156
10157#undef rb_argv
10158
10159/* :nodoc: */
10160static VALUE
10161argf_initialize(VALUE argf, VALUE argv)
10162{
10163 memset(&ARGF, 0, sizeof(ARGF));
10164 argf_init(argf, &ARGF, argv);
10165
10166 return argf;
10167}
10168
10169/* :nodoc: */
10170static VALUE
10171argf_initialize_copy(VALUE argf, VALUE orig)
10172{
10173 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10174 ARGF = argf_of(orig);
10175 rb_gc_writebarrier_remember(argf);
10176 ARGF_SET(argv, rb_obj_dup(ARGF.argv));
10177 return argf;
10178}
10179
10180/*
10181 * call-seq:
10182 * ARGF.lineno = integer -> integer
10183 *
10184 * Sets the line number of ARGF as a whole to the given Integer.
10185 *
10186 * ARGF sets the line number automatically as you read data, so normally
10187 * you will not need to set it explicitly. To access the current line number
10188 * use ARGF.lineno.
10189 *
10190 * For example:
10191 *
10192 * ARGF.lineno #=> 0
10193 * ARGF.readline #=> "This is line 1\n"
10194 * ARGF.lineno #=> 1
10195 * ARGF.lineno = 0 #=> 0
10196 * ARGF.lineno #=> 0
10197 */
10198static VALUE
10199argf_set_lineno(VALUE argf, VALUE val)
10200{
10201 ARGF.lineno = NUM2INT(val);
10202 ARGF.last_lineno = ARGF.lineno;
10203 return val;
10204}
10205
10206/*
10207 * call-seq:
10208 * ARGF.lineno -> integer
10209 *
10210 * Returns the current line number of ARGF as a whole. This value
10211 * can be set manually with ARGF.lineno=.
10212 *
10213 * For example:
10214 *
10215 * ARGF.lineno #=> 0
10216 * ARGF.readline #=> "This is line 1\n"
10217 * ARGF.lineno #=> 1
10218 */
10219static VALUE
10220argf_lineno(VALUE argf)
10221{
10222 return INT2FIX(ARGF.lineno);
10223}
10224
10225static VALUE
10226argf_forward(int argc, VALUE *argv, VALUE argf)
10227{
10228 return forward_current(rb_frame_this_func(), argc, argv);
10229}
10230
10231#define next_argv() argf_next_argv(argf)
10232#define ARGF_GENERIC_INPUT_P() \
10233 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10234#define ARGF_FORWARD(argc, argv) do {\
10235 if (ARGF_GENERIC_INPUT_P())\
10236 return argf_forward((argc), (argv), argf);\
10237} while (0)
10238#define NEXT_ARGF_FORWARD(argc, argv) do {\
10239 if (!next_argv()) return Qnil;\
10240 ARGF_FORWARD((argc), (argv));\
10241} while (0)
10242
10243static void
10244argf_close(VALUE argf)
10245{
10246 VALUE file = ARGF.current_file;
10247 if (file == rb_stdin) return;
10248 if (RB_TYPE_P(file, T_FILE)) {
10249 rb_io_set_write_io(file, Qnil);
10250 }
10251 io_close(file);
10252 ARGF.init_p = -1;
10253}
10254
10255static int
10256argf_next_argv(VALUE argf)
10257{
10258 char *fn;
10259 rb_io_t *fptr;
10260 int stdout_binmode = 0;
10261 enum rb_io_mode fmode;
10262
10263 VALUE r_stdout = rb_ractor_stdout();
10264
10265 if (RB_TYPE_P(r_stdout, T_FILE)) {
10266 GetOpenFile(r_stdout, fptr);
10267 if (fptr->mode & FMODE_BINMODE)
10268 stdout_binmode = 1;
10269 }
10270
10271 if (ARGF.init_p == 0) {
10272 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10273 ARGF.next_p = 1;
10274 }
10275 else {
10276 ARGF.next_p = -1;
10277 }
10278 ARGF.init_p = 1;
10279 }
10280 else {
10281 if (NIL_P(ARGF.argv)) {
10282 ARGF.next_p = -1;
10283 }
10284 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10285 ARGF.next_p = 1;
10286 }
10287 }
10288
10289 if (ARGF.next_p == 1) {
10290 if (ARGF.init_p == 1) argf_close(argf);
10291 retry:
10292 if (RARRAY_LEN(ARGF.argv) > 0) {
10293 VALUE filename = rb_ary_shift(ARGF.argv);
10294 FilePathValue(filename);
10295 ARGF_SET(filename, filename);
10296 filename = rb_str_encode_ospath(filename);
10297 fn = StringValueCStr(filename);
10298 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10299 ARGF_SET(current_file, rb_stdin);
10300 if (ARGF.inplace) {
10301 rb_warn("Can't do inplace edit for stdio; skipping");
10302 goto retry;
10303 }
10304 }
10305 else {
10306 VALUE write_io = Qnil;
10307 int fr = rb_sysopen(filename, O_RDONLY, 0);
10308
10309 if (ARGF.inplace) {
10310 struct stat st;
10311#ifndef NO_SAFE_RENAME
10312 struct stat st2;
10313#endif
10314 VALUE str;
10315 int fw;
10316
10317 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10318 rb_io_close(r_stdout);
10319 }
10320 fstat(fr, &st);
10321 str = filename;
10322 if (!NIL_P(ARGF.inplace)) {
10323 VALUE suffix = ARGF.inplace;
10324 str = rb_str_dup(str);
10325 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10326 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10327 rb_enc_get(suffix), 0, Qnil))) {
10328 rb_str_append(str, suffix);
10329 }
10330#ifdef NO_SAFE_RENAME
10331 (void)close(fr);
10332 (void)unlink(RSTRING_PTR(str));
10333 if (rename(fn, RSTRING_PTR(str)) < 0) {
10334 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10335 filename, str, strerror(errno));
10336 goto retry;
10337 }
10338 fr = rb_sysopen(str, O_RDONLY, 0);
10339#else
10340 if (rename(fn, RSTRING_PTR(str)) < 0) {
10341 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10342 filename, str, strerror(errno));
10343 close(fr);
10344 goto retry;
10345 }
10346#endif
10347 }
10348 else {
10349#ifdef NO_SAFE_RENAME
10350 rb_fatal("Can't do inplace edit without backup");
10351#else
10352 if (unlink(fn) < 0) {
10353 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10354 filename, strerror(errno));
10355 close(fr);
10356 goto retry;
10357 }
10358#endif
10359 }
10360 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10361#ifndef NO_SAFE_RENAME
10362 fstat(fw, &st2);
10363#ifdef HAVE_FCHMOD
10364 fchmod(fw, st.st_mode);
10365#else
10366 chmod(fn, st.st_mode);
10367#endif
10368 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10369 int err;
10370#ifdef HAVE_FCHOWN
10371 err = fchown(fw, st.st_uid, st.st_gid);
10372#else
10373 err = chown(fn, st.st_uid, st.st_gid);
10374#endif
10375 if (err && getuid() == 0 && st2.st_uid == 0) {
10376 const char *wkfn = RSTRING_PTR(filename);
10377 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10378 filename, str, strerror(errno));
10379 (void)close(fr);
10380 (void)close(fw);
10381 (void)unlink(wkfn);
10382 goto retry;
10383 }
10384 }
10385#endif
10386 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10387 rb_ractor_stdout_set(write_io);
10388 if (stdout_binmode) rb_io_binmode(rb_stdout);
10389 }
10390 fmode = FMODE_READABLE;
10391 if (!ARGF.binmode) {
10392 fmode |= DEFAULT_TEXTMODE;
10393 }
10394 ARGF_SET(current_file, prep_io(fr, fmode, rb_cFile, fn));
10395 if (!NIL_P(write_io)) {
10396 rb_io_set_write_io(ARGF.current_file, write_io);
10397 }
10398 RB_GC_GUARD(filename);
10399 }
10400 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10401 GetOpenFile(ARGF.current_file, fptr);
10402 if (ARGF.encs.enc) {
10403 fptr->encs = ARGF.encs;
10404 clear_codeconv(fptr);
10405 }
10406 else {
10407 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10408 if (!ARGF.binmode) {
10410#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10411 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10412#endif
10413 }
10414 }
10415 ARGF.next_p = 0;
10416 }
10417 else {
10418 ARGF.next_p = 1;
10419 return FALSE;
10420 }
10421 }
10422 else if (ARGF.next_p == -1) {
10423 ARGF_SET(current_file, rb_stdin);
10424 ARGF_SET(filename, rb_str_new2("-"));
10425 if (ARGF.inplace) {
10426 rb_warn("Can't do inplace edit for stdio");
10427 rb_ractor_stdout_set(orig_stdout);
10428 }
10429 }
10430 if (ARGF.init_p == -1) ARGF.init_p = 1;
10431 return TRUE;
10432}
10433
10434static VALUE
10435argf_getline(int argc, VALUE *argv, VALUE argf)
10436{
10437 VALUE line;
10438 long lineno = ARGF.lineno;
10439
10440 retry:
10441 if (!next_argv()) return Qnil;
10442 if (ARGF_GENERIC_INPUT_P()) {
10443 line = forward_current(idGets, argc, argv);
10444 }
10445 else {
10446 if (argc == 0 && rb_rs == rb_default_rs) {
10447 line = rb_io_gets(ARGF.current_file);
10448 }
10449 else {
10450 line = rb_io_getline(argc, argv, ARGF.current_file);
10451 }
10452 if (NIL_P(line) && ARGF.next_p != -1) {
10453 argf_close(argf);
10454 ARGF.next_p = 1;
10455 goto retry;
10456 }
10457 }
10458 if (!NIL_P(line)) {
10459 ARGF.lineno = ++lineno;
10460 ARGF.last_lineno = ARGF.lineno;
10461 }
10462 return line;
10463}
10464
10465static VALUE
10466argf_lineno_getter(ID id, VALUE *var)
10467{
10468 VALUE argf = *var;
10469 return INT2FIX(ARGF.last_lineno);
10470}
10471
10472static void
10473argf_lineno_setter(VALUE val, ID id, VALUE *var)
10474{
10475 VALUE argf = *var;
10476 int n = NUM2INT(val);
10477 ARGF.last_lineno = ARGF.lineno = n;
10478}
10479
10480void
10481rb_reset_argf_lineno(long n)
10482{
10483 ARGF.last_lineno = ARGF.lineno = n;
10484}
10485
10486static VALUE argf_gets(int, VALUE *, VALUE);
10487
10488/*
10489 * call-seq:
10490 * gets(sep=$/ [, getline_args]) -> string or nil
10491 * gets(limit [, getline_args]) -> string or nil
10492 * gets(sep, limit [, getline_args]) -> string or nil
10493 *
10494 * Returns (and assigns to <code>$_</code>) the next line from the list
10495 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10496 * no files are present on the command line. Returns +nil+ at end of
10497 * file. The optional argument specifies the record separator. The
10498 * separator is included with the contents of each record. A separator
10499 * of +nil+ reads the entire contents, and a zero-length separator
10500 * reads the input one paragraph at a time, where paragraphs are
10501 * divided by two consecutive newlines. If the first argument is an
10502 * integer, or optional second argument is given, the returning string
10503 * would not be longer than the given value in bytes. If multiple
10504 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10505 * the contents one file at a time.
10506 *
10507 * ARGV << "testfile"
10508 * print while gets
10509 *
10510 * <em>produces:</em>
10511 *
10512 * This is line one
10513 * This is line two
10514 * This is line three
10515 * And so on...
10516 *
10517 * The style of programming using <code>$_</code> as an implicit
10518 * parameter is gradually losing favor in the Ruby community.
10519 */
10520
10521static VALUE
10522rb_f_gets(int argc, VALUE *argv, VALUE recv)
10523{
10524 if (recv == argf) {
10525 return argf_gets(argc, argv, argf);
10526 }
10527 return forward(argf, idGets, argc, argv);
10528}
10529
10530/*
10531 * call-seq:
10532 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10533 * ARGF.gets(limit [, getline_args]) -> string or nil
10534 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10535 *
10536 * Returns the next line from the current file in ARGF.
10537 *
10538 * By default lines are assumed to be separated by <code>$/</code>;
10539 * to use a different character as a separator, supply it as a String
10540 * for the _sep_ argument.
10541 *
10542 * The optional _limit_ argument specifies how many characters of each line
10543 * to return. By default all characters are returned.
10544 *
10545 * See IO.readlines for details about getline_args.
10546 *
10547 */
10548static VALUE
10549argf_gets(int argc, VALUE *argv, VALUE argf)
10550{
10551 VALUE line;
10552
10553 line = argf_getline(argc, argv, argf);
10554 rb_lastline_set(line);
10555
10556 return line;
10557}
10558
10559VALUE
10561{
10562 VALUE line;
10563
10564 if (rb_rs != rb_default_rs) {
10565 return rb_f_gets(0, 0, argf);
10566 }
10567
10568 retry:
10569 if (!next_argv()) return Qnil;
10570 line = rb_io_gets(ARGF.current_file);
10571 if (NIL_P(line) && ARGF.next_p != -1) {
10572 rb_io_close(ARGF.current_file);
10573 ARGF.next_p = 1;
10574 goto retry;
10575 }
10576 rb_lastline_set(line);
10577 if (!NIL_P(line)) {
10578 ARGF.lineno++;
10579 ARGF.last_lineno = ARGF.lineno;
10580 }
10581
10582 return line;
10583}
10584
10585static VALUE argf_readline(int, VALUE *, VALUE);
10586
10587/*
10588 * call-seq:
10589 * readline(sep = $/, chomp: false) -> string
10590 * readline(limit, chomp: false) -> string
10591 * readline(sep, limit, chomp: false) -> string
10592 *
10593 * Equivalent to method Kernel#gets, except that it raises an exception
10594 * if called at end-of-stream:
10595 *
10596 * $ cat t.txt | ruby -e "p readlines; readline"
10597 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10598 * in `readline': end of file reached (EOFError)
10599 *
10600 * Optional keyword argument +chomp+ specifies whether line separators
10601 * are to be omitted.
10602 */
10603
10604static VALUE
10605rb_f_readline(int argc, VALUE *argv, VALUE recv)
10606{
10607 if (recv == argf) {
10608 return argf_readline(argc, argv, argf);
10609 }
10610 return forward(argf, rb_intern("readline"), argc, argv);
10611}
10612
10613
10614/*
10615 * call-seq:
10616 * ARGF.readline(sep=$/) -> string
10617 * ARGF.readline(limit) -> string
10618 * ARGF.readline(sep, limit) -> string
10619 *
10620 * Returns the next line from the current file in ARGF.
10621 *
10622 * By default lines are assumed to be separated by <code>$/</code>;
10623 * to use a different character as a separator, supply it as a String
10624 * for the _sep_ argument.
10625 *
10626 * The optional _limit_ argument specifies how many characters of each line
10627 * to return. By default all characters are returned.
10628 *
10629 * An EOFError is raised at the end of the file.
10630 */
10631static VALUE
10632argf_readline(int argc, VALUE *argv, VALUE argf)
10633{
10634 VALUE line;
10635
10636 if (!next_argv()) rb_eof_error();
10637 ARGF_FORWARD(argc, argv);
10638 line = argf_gets(argc, argv, argf);
10639 if (NIL_P(line)) {
10640 rb_eof_error();
10641 }
10642
10643 return line;
10644}
10645
10646static VALUE argf_readlines(int, VALUE *, VALUE);
10647
10648/*
10649 * call-seq:
10650 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10651 * readlines(limit, chomp: false, **enc_opts) -> array
10652 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10653 *
10654 * Returns an array containing the lines returned by calling
10655 * Kernel#gets until the end-of-stream is reached;
10656 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10657 *
10658 * With only string argument +sep+ given,
10659 * returns the remaining lines as determined by line separator +sep+,
10660 * or +nil+ if none;
10661 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10662 *
10663 * # Default separator.
10664 * $ cat t.txt | ruby -e "p readlines"
10665 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10666 *
10667 * # Specified separator.
10668 * $ cat t.txt | ruby -e "p readlines 'li'"
10669 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10670 *
10671 * # Get-all separator.
10672 * $ cat t.txt | ruby -e "p readlines nil"
10673 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10674 *
10675 * # Get-paragraph separator.
10676 * $ cat t.txt | ruby -e "p readlines ''"
10677 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10678 *
10679 * With only integer argument +limit+ given,
10680 * limits the number of bytes in the line;
10681 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10682 *
10683 * $cat t.txt | ruby -e "p readlines 10"
10684 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10685 *
10686 * $cat t.txt | ruby -e "p readlines 11"
10687 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10688 *
10689 * $cat t.txt | ruby -e "p readlines 12"
10690 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10691 *
10692 * With arguments +sep+ and +limit+ given,
10693 * combines the two behaviors
10694 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10695 *
10696 * Optional keyword argument +chomp+ specifies whether line separators
10697 * are to be omitted:
10698 *
10699 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10700 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10701 *
10702 * Optional keyword arguments +enc_opts+ specify encoding options;
10703 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10704 *
10705 */
10706
10707static VALUE
10708rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10709{
10710 if (recv == argf) {
10711 return argf_readlines(argc, argv, argf);
10712 }
10713 return forward(argf, rb_intern("readlines"), argc, argv);
10714}
10715
10716/*
10717 * call-seq:
10718 * ARGF.readlines(sep = $/, chomp: false) -> array
10719 * ARGF.readlines(limit, chomp: false) -> array
10720 * ARGF.readlines(sep, limit, chomp: false) -> array
10721 *
10722 * ARGF.to_a(sep = $/, chomp: false) -> array
10723 * ARGF.to_a(limit, chomp: false) -> array
10724 * ARGF.to_a(sep, limit, chomp: false) -> array
10725 *
10726 * Reads each file in ARGF in its entirety, returning an Array containing
10727 * lines from the files. Lines are assumed to be separated by _sep_.
10728 *
10729 * lines = ARGF.readlines
10730 * lines[0] #=> "This is line one\n"
10731 *
10732 * See +IO.readlines+ for a full description of all options.
10733 */
10734static VALUE
10735argf_readlines(int argc, VALUE *argv, VALUE argf)
10736{
10737 long lineno = ARGF.lineno;
10738 VALUE lines, ary;
10739
10740 ary = rb_ary_new();
10741 while (next_argv()) {
10742 if (ARGF_GENERIC_INPUT_P()) {
10743 lines = forward_current(rb_intern("readlines"), argc, argv);
10744 }
10745 else {
10746 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10747 argf_close(argf);
10748 }
10749 ARGF.next_p = 1;
10750 rb_ary_concat(ary, lines);
10751 ARGF.lineno = lineno + RARRAY_LEN(ary);
10752 ARGF.last_lineno = ARGF.lineno;
10753 }
10754 ARGF.init_p = 0;
10755 return ary;
10756}
10757
10758/*
10759 * call-seq:
10760 * `command` -> string
10761 *
10762 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10763 * sets global variable <tt>$?</tt> to the process status.
10764 *
10765 * This method has potential security vulnerabilities if called with untrusted input;
10766 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
10767 *
10768 * Examples:
10769 *
10770 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10771 * $ `echo oops && exit 99` # => "oops\n"
10772 * $ $? # => #<Process::Status: pid 17088 exit 99>
10773 * $ $?.exitstatus # => 99
10774 *
10775 * The built-in syntax <tt>%x{...}</tt> uses this method.
10776 *
10777 */
10778
10779static VALUE
10780rb_f_backquote(VALUE obj, VALUE str)
10781{
10782 VALUE port;
10783 VALUE result;
10784 rb_io_t *fptr;
10785
10786 StringValue(str);
10787 rb_last_status_clear();
10788 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10789 if (NIL_P(port)) return rb_str_new(0,0);
10790
10791 GetOpenFile(port, fptr);
10792 result = read_all(fptr, remain_size(fptr), Qnil);
10793 rb_io_close(port);
10794 rb_io_fptr_cleanup_all(fptr);
10795 RB_GC_GUARD(port);
10796
10797 return result;
10798}
10799
10800#ifdef HAVE_SYS_SELECT_H
10801#include <sys/select.h>
10802#endif
10803
10804static VALUE
10805select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10806{
10807 VALUE res, list;
10808 rb_fdset_t *rp, *wp, *ep;
10809 rb_io_t *fptr;
10810 long i;
10811 int max = 0, n;
10812 int pending = 0;
10813 struct timeval timerec;
10814
10815 if (!NIL_P(read)) {
10816 Check_Type(read, T_ARRAY);
10817 for (i=0; i<RARRAY_LEN(read); i++) {
10818 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10819 rb_fd_set(fptr->fd, &fds[0]);
10820 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10821 pending++;
10822 rb_fd_set(fptr->fd, &fds[3]);
10823 }
10824 if (max < fptr->fd) max = fptr->fd;
10825 }
10826 if (pending) { /* no blocking if there's buffered data */
10827 timerec.tv_sec = timerec.tv_usec = 0;
10828 tp = &timerec;
10829 }
10830 rp = &fds[0];
10831 }
10832 else
10833 rp = 0;
10834
10835 if (!NIL_P(write)) {
10836 Check_Type(write, T_ARRAY);
10837 for (i=0; i<RARRAY_LEN(write); i++) {
10838 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10839 GetOpenFile(write_io, fptr);
10840 rb_fd_set(fptr->fd, &fds[1]);
10841 if (max < fptr->fd) max = fptr->fd;
10842 }
10843 wp = &fds[1];
10844 }
10845 else
10846 wp = 0;
10847
10848 if (!NIL_P(except)) {
10849 Check_Type(except, T_ARRAY);
10850 for (i=0; i<RARRAY_LEN(except); i++) {
10851 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10852 VALUE write_io = GetWriteIO(io);
10853 GetOpenFile(io, fptr);
10854 rb_fd_set(fptr->fd, &fds[2]);
10855 if (max < fptr->fd) max = fptr->fd;
10856 if (io != write_io) {
10857 GetOpenFile(write_io, fptr);
10858 rb_fd_set(fptr->fd, &fds[2]);
10859 if (max < fptr->fd) max = fptr->fd;
10860 }
10861 }
10862 ep = &fds[2];
10863 }
10864 else {
10865 ep = 0;
10866 }
10867
10868 max++;
10869
10870 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10871 if (n < 0) {
10872 rb_sys_fail(0);
10873 }
10874 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10875
10876 res = rb_ary_new2(3);
10877 rb_ary_push(res, rp ? rb_ary_new_capa(RARRAY_LEN(read)) : rb_ary_new());
10878 rb_ary_push(res, wp ? rb_ary_new_capa(RARRAY_LEN(write)) : rb_ary_new());
10879 rb_ary_push(res, ep ? rb_ary_new_capa(RARRAY_LEN(except)) : rb_ary_new());
10880
10881 if (rp) {
10882 list = RARRAY_AREF(res, 0);
10883 for (i=0; i< RARRAY_LEN(read); i++) {
10884 VALUE obj = rb_ary_entry(read, i);
10885 VALUE io = rb_io_get_io(obj);
10886 GetOpenFile(io, fptr);
10887 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10888 rb_fd_isset(fptr->fd, &fds[3])) {
10889 rb_ary_push(list, obj);
10890 }
10891 }
10892 }
10893
10894 if (wp) {
10895 list = RARRAY_AREF(res, 1);
10896 for (i=0; i< RARRAY_LEN(write); i++) {
10897 VALUE obj = rb_ary_entry(write, i);
10898 VALUE io = rb_io_get_io(obj);
10899 VALUE write_io = GetWriteIO(io);
10900 GetOpenFile(write_io, fptr);
10901 if (rb_fd_isset(fptr->fd, &fds[1])) {
10902 rb_ary_push(list, obj);
10903 }
10904 }
10905 }
10906
10907 if (ep) {
10908 list = RARRAY_AREF(res, 2);
10909 for (i=0; i< RARRAY_LEN(except); i++) {
10910 VALUE obj = rb_ary_entry(except, i);
10911 VALUE io = rb_io_get_io(obj);
10912 VALUE write_io = GetWriteIO(io);
10913 GetOpenFile(io, fptr);
10914 if (rb_fd_isset(fptr->fd, &fds[2])) {
10915 rb_ary_push(list, obj);
10916 }
10917 else if (io != write_io) {
10918 GetOpenFile(write_io, fptr);
10919 if (rb_fd_isset(fptr->fd, &fds[2])) {
10920 rb_ary_push(list, obj);
10921 }
10922 }
10923 }
10924 }
10925
10926 return res; /* returns an empty array on interrupt */
10927}
10928
10930 VALUE read, write, except;
10931 struct timeval *timeout;
10932 rb_fdset_t fdsets[4];
10933};
10934
10935static VALUE
10936select_call(VALUE arg)
10937{
10938 struct select_args *p = (struct select_args *)arg;
10939
10940 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10941}
10942
10943static VALUE
10944select_end(VALUE arg)
10945{
10946 struct select_args *p = (struct select_args *)arg;
10947 int i;
10948
10949 for (i = 0; i < numberof(p->fdsets); ++i)
10950 rb_fd_term(&p->fdsets[i]);
10951 return Qnil;
10952}
10953
10954static VALUE sym_normal, sym_sequential, sym_random,
10955 sym_willneed, sym_dontneed, sym_noreuse;
10956
10957#ifdef HAVE_POSIX_FADVISE
10958struct io_advise_struct {
10959 int fd;
10960 int advice;
10961 rb_off_t offset;
10962 rb_off_t len;
10963};
10964
10965static VALUE
10966io_advise_internal(void *arg)
10967{
10968 struct io_advise_struct *ptr = arg;
10969 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10970}
10971
10972static VALUE
10973io_advise_sym_to_const(VALUE sym)
10974{
10975#ifdef POSIX_FADV_NORMAL
10976 if (sym == sym_normal)
10977 return INT2NUM(POSIX_FADV_NORMAL);
10978#endif
10979
10980#ifdef POSIX_FADV_RANDOM
10981 if (sym == sym_random)
10982 return INT2NUM(POSIX_FADV_RANDOM);
10983#endif
10984
10985#ifdef POSIX_FADV_SEQUENTIAL
10986 if (sym == sym_sequential)
10987 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10988#endif
10989
10990#ifdef POSIX_FADV_WILLNEED
10991 if (sym == sym_willneed)
10992 return INT2NUM(POSIX_FADV_WILLNEED);
10993#endif
10994
10995#ifdef POSIX_FADV_DONTNEED
10996 if (sym == sym_dontneed)
10997 return INT2NUM(POSIX_FADV_DONTNEED);
10998#endif
10999
11000#ifdef POSIX_FADV_NOREUSE
11001 if (sym == sym_noreuse)
11002 return INT2NUM(POSIX_FADV_NOREUSE);
11003#endif
11004
11005 return Qnil;
11006}
11007
11008static VALUE
11009do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
11010{
11011 int rv;
11012 struct io_advise_struct ias;
11013 VALUE num_adv;
11014
11015 num_adv = io_advise_sym_to_const(advice);
11016
11017 /*
11018 * The platform doesn't support this hint. We don't raise exception, instead
11019 * silently ignore it. Because IO::advise is only hint.
11020 */
11021 if (NIL_P(num_adv))
11022 return Qnil;
11023
11024 ias.fd = fptr->fd;
11025 ias.advice = NUM2INT(num_adv);
11026 ias.offset = offset;
11027 ias.len = len;
11028
11029 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
11030 if (rv && rv != ENOSYS) {
11031 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
11032 it returns the error code. */
11033 VALUE message = rb_sprintf("%"PRIsVALUE" "
11034 "(%"PRI_OFFT_PREFIX"d, "
11035 "%"PRI_OFFT_PREFIX"d, "
11036 "%"PRIsVALUE")",
11037 fptr->pathv, offset, len, advice);
11038 rb_syserr_fail_str(rv, message);
11039 }
11040
11041 return Qnil;
11042}
11043
11044#endif /* HAVE_POSIX_FADVISE */
11045
11046static void
11047advice_arg_check(VALUE advice)
11048{
11049 if (!SYMBOL_P(advice))
11050 rb_raise(rb_eTypeError, "advice must be a Symbol");
11051
11052 if (advice != sym_normal &&
11053 advice != sym_sequential &&
11054 advice != sym_random &&
11055 advice != sym_willneed &&
11056 advice != sym_dontneed &&
11057 advice != sym_noreuse) {
11058 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
11059 }
11060}
11061
11062/*
11063 * call-seq:
11064 * advise(advice, offset = 0, len = 0) -> nil
11065 *
11066 * Invokes Posix system call
11067 * {posix_fadvise(2)}[https://man7.org/linux/man-pages/man2/posix_fadvise.2.html],
11068 * which announces an intention to access data from the current file
11069 * in a particular manner.
11070 *
11071 * The arguments and results are platform-dependent.
11072 *
11073 * The relevant data is specified by:
11074 *
11075 * - +offset+: The offset of the first byte of data.
11076 * - +len+: The number of bytes to be accessed;
11077 * if +len+ is zero, or is larger than the number of bytes remaining,
11078 * all remaining bytes will be accessed.
11079 *
11080 * Argument +advice+ is one of the following symbols:
11081 *
11082 * - +:normal+: The application has no advice to give
11083 * about its access pattern for the specified data.
11084 * If no advice is given for an open file, this is the default assumption.
11085 * - +:sequential+: The application expects to access the specified data sequentially
11086 * (with lower offsets read before higher ones).
11087 * - +:random+: The specified data will be accessed in random order.
11088 * - +:noreuse+: The specified data will be accessed only once.
11089 * - +:willneed+: The specified data will be accessed in the near future.
11090 * - +:dontneed+: The specified data will not be accessed in the near future.
11091 *
11092 * Not implemented on all platforms.
11093 *
11094 */
11095static VALUE
11096rb_io_advise(int argc, VALUE *argv, VALUE io)
11097{
11098 VALUE advice, offset, len;
11099 rb_off_t off, l;
11100 rb_io_t *fptr;
11101
11102 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
11103 advice_arg_check(advice);
11104
11105 io = GetWriteIO(io);
11106 GetOpenFile(io, fptr);
11107
11108 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
11109 l = NIL_P(len) ? 0 : NUM2OFFT(len);
11110
11111#ifdef HAVE_POSIX_FADVISE
11112 return do_io_advise(fptr, advice, off, l);
11113#else
11114 ((void)off, (void)l); /* Ignore all hint */
11115 return Qnil;
11116#endif
11117}
11118
11119static int
11120is_pos_inf(VALUE x)
11121{
11122 double f;
11123 if (!RB_FLOAT_TYPE_P(x))
11124 return 0;
11125 f = RFLOAT_VALUE(x);
11126 return isinf(f) && 0 < f;
11127}
11128
11129/*
11130 * call-seq:
11131 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11132 *
11133 * Invokes system call {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html],
11134 * which monitors multiple file descriptors,
11135 * waiting until one or more of the file descriptors
11136 * becomes ready for some class of I/O operation.
11137 *
11138 * Not implemented on all platforms.
11139 *
11140 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11141 * is an array of IO objects.
11142 *
11143 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11144 * interval in seconds.
11145 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11146 * +nil+ and +Float::INFINITY+ means no timeout.
11147 *
11148 * The method monitors the \IO objects given in all three arrays,
11149 * waiting for some to be ready;
11150 * returns a 3-element array whose elements are:
11151 *
11152 * - An array of the objects in +read_ios+ that are ready for reading.
11153 * - An array of the objects in +write_ios+ that are ready for writing.
11154 * - An array of the objects in +error_ios+ have pending exceptions.
11155 *
11156 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11157 *
11158 * \IO.select peeks the buffer of \IO objects for testing readability.
11159 * If the \IO buffer is not empty, \IO.select immediately notifies
11160 * readability. This "peek" only happens for \IO objects. It does not
11161 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11162 *
11163 * The best way to use \IO.select is invoking it after non-blocking
11164 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11165 * raise an exception which is extended by IO::WaitReadable or
11166 * IO::WaitWritable. The modules notify how the caller should wait
11167 * with \IO.select. If IO::WaitReadable is raised, the caller should
11168 * wait for reading. If IO::WaitWritable is raised, the caller should
11169 * wait for writing.
11170 *
11171 * So, blocking read (#readpartial) can be emulated using
11172 * #read_nonblock and \IO.select as follows:
11173 *
11174 * begin
11175 * result = io_like.read_nonblock(maxlen)
11176 * rescue IO::WaitReadable
11177 * IO.select([io_like])
11178 * retry
11179 * rescue IO::WaitWritable
11180 * IO.select(nil, [io_like])
11181 * retry
11182 * end
11183 *
11184 * Especially, the combination of non-blocking methods and \IO.select is
11185 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11186 * has #to_io method to return underlying IO object. IO.select calls
11187 * #to_io to obtain the file descriptor to wait.
11188 *
11189 * This means that readability notified by \IO.select doesn't mean
11190 * readability from OpenSSL::SSL::SSLSocket object.
11191 *
11192 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11193 * some data. \IO.select doesn't see the buffer. So \IO.select can
11194 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11195 *
11196 * However, several more complicated situations exist.
11197 *
11198 * SSL is a protocol which is sequence of records.
11199 * The record consists of multiple bytes.
11200 * So, the remote side of SSL sends a partial record, IO.select
11201 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11202 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11203 *
11204 * Also, the remote side can request SSL renegotiation which forces
11205 * the local SSL engine to write some data.
11206 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11207 * system call and it can block.
11208 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11209 * IO::WaitWritable instead of blocking.
11210 * So, the caller should wait for ready for writability as above
11211 * example.
11212 *
11213 * The combination of non-blocking methods and \IO.select is also useful
11214 * for streams such as tty, pipe socket socket when multiple processes
11215 * read from a stream.
11216 *
11217 * Finally, Linux kernel developers don't guarantee that
11218 * readability of select(2) means readability of following read(2) even
11219 * for a single process;
11220 * see {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html]
11221 *
11222 * Invoking \IO.select before IO#readpartial works well as usual.
11223 * However it is not the best way to use \IO.select.
11224 *
11225 * The writability notified by select(2) doesn't show
11226 * how many bytes are writable.
11227 * IO#write method blocks until given whole string is written.
11228 * So, <tt>IO#write(two or more bytes)</tt> can block after
11229 * writability is notified by \IO.select. IO#write_nonblock is required
11230 * to avoid the blocking.
11231 *
11232 * Blocking write (#write) can be emulated using #write_nonblock and
11233 * IO.select as follows: IO::WaitReadable should also be rescued for
11234 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11235 *
11236 * while 0 < string.bytesize
11237 * begin
11238 * written = io_like.write_nonblock(string)
11239 * rescue IO::WaitReadable
11240 * IO.select([io_like])
11241 * retry
11242 * rescue IO::WaitWritable
11243 * IO.select(nil, [io_like])
11244 * retry
11245 * end
11246 * string = string.byteslice(written..-1)
11247 * end
11248 *
11249 * Example:
11250 *
11251 * rp, wp = IO.pipe
11252 * mesg = "ping "
11253 * 100.times {
11254 * # IO.select follows IO#read. Not the best way to use IO.select.
11255 * rs, ws, = IO.select([rp], [wp])
11256 * if r = rs[0]
11257 * ret = r.read(5)
11258 * print ret
11259 * case ret
11260 * when /ping/
11261 * mesg = "pong\n"
11262 * when /pong/
11263 * mesg = "ping "
11264 * end
11265 * end
11266 * if w = ws[0]
11267 * w.write(mesg)
11268 * end
11269 * }
11270 *
11271 * Output:
11272 *
11273 * ping pong
11274 * ping pong
11275 * ping pong
11276 * (snipped)
11277 * ping
11278 *
11279 */
11280
11281static VALUE
11282rb_f_select(int argc, VALUE *argv, VALUE obj)
11283{
11284 VALUE scheduler = rb_fiber_scheduler_current();
11285 if (scheduler != Qnil) {
11286 // It's optionally supported.
11287 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11288 if (!UNDEF_P(result)) return result;
11289 }
11290
11291 VALUE timeout;
11292 struct select_args args;
11293 struct timeval timerec;
11294 int i;
11295
11296 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11297 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11298 args.timeout = 0;
11299 }
11300 else {
11301 timerec = rb_time_interval(timeout);
11302 args.timeout = &timerec;
11303 }
11304
11305 for (i = 0; i < numberof(args.fdsets); ++i)
11306 rb_fd_init(&args.fdsets[i]);
11307
11308 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11309}
11310
11311#ifdef IOCTL_REQ_TYPE
11312 typedef IOCTL_REQ_TYPE ioctl_req_t;
11313#else
11314 typedef int ioctl_req_t;
11315# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11316#endif
11317
11318#ifdef HAVE_IOCTL
11319struct ioctl_arg {
11320 int fd;
11321 ioctl_req_t cmd;
11322 long narg;
11323};
11324
11325static VALUE
11326nogvl_ioctl(void *ptr)
11327{
11328 struct ioctl_arg *arg = ptr;
11329
11330 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11331}
11332
11333static int
11334do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11335{
11336 int retval;
11337 struct ioctl_arg arg;
11338
11339 arg.fd = io->fd;
11340 arg.cmd = cmd;
11341 arg.narg = narg;
11342
11343 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11344
11345 return retval;
11346}
11347#endif
11348
11349#define DEFAULT_IOCTL_NARG_LEN (256)
11350
11351#if defined(__linux__) && defined(_IOC_SIZE)
11352static long
11353linux_iocparm_len(ioctl_req_t cmd)
11354{
11355 long len;
11356
11357 if ((cmd & 0xFFFF0000) == 0) {
11358 /* legacy and unstructured ioctl number. */
11359 return DEFAULT_IOCTL_NARG_LEN;
11360 }
11361
11362 len = _IOC_SIZE(cmd);
11363
11364 /* paranoia check for silly drivers which don't keep ioctl convention */
11365 if (len < DEFAULT_IOCTL_NARG_LEN)
11366 len = DEFAULT_IOCTL_NARG_LEN;
11367
11368 return len;
11369}
11370#endif
11371
11372#ifdef HAVE_IOCTL
11373static long
11374ioctl_narg_len(ioctl_req_t cmd)
11375{
11376 long len;
11377
11378#ifdef IOCPARM_MASK
11379#ifndef IOCPARM_LEN
11380#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11381#endif
11382#endif
11383#ifdef IOCPARM_LEN
11384 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11385#elif defined(__linux__) && defined(_IOC_SIZE)
11386 len = linux_iocparm_len(cmd);
11387#else
11388 /* otherwise guess at what's safe */
11389 len = DEFAULT_IOCTL_NARG_LEN;
11390#endif
11391
11392 return len;
11393}
11394#endif
11395
11396#ifdef HAVE_FCNTL
11397#ifdef __linux__
11398typedef long fcntl_arg_t;
11399#else
11400/* posix */
11401typedef int fcntl_arg_t;
11402#endif
11403
11404static long
11405fcntl_narg_len(ioctl_req_t cmd)
11406{
11407 long len;
11408
11409 switch (cmd) {
11410#ifdef F_DUPFD
11411 case F_DUPFD:
11412 len = sizeof(fcntl_arg_t);
11413 break;
11414#endif
11415#ifdef F_DUP2FD /* bsd specific */
11416 case F_DUP2FD:
11417 len = sizeof(int);
11418 break;
11419#endif
11420#ifdef F_DUPFD_CLOEXEC /* linux specific */
11421 case F_DUPFD_CLOEXEC:
11422 len = sizeof(fcntl_arg_t);
11423 break;
11424#endif
11425#ifdef F_GETFD
11426 case F_GETFD:
11427 len = 1;
11428 break;
11429#endif
11430#ifdef F_SETFD
11431 case F_SETFD:
11432 len = sizeof(fcntl_arg_t);
11433 break;
11434#endif
11435#ifdef F_GETFL
11436 case F_GETFL:
11437 len = 1;
11438 break;
11439#endif
11440#ifdef F_SETFL
11441 case F_SETFL:
11442 len = sizeof(fcntl_arg_t);
11443 break;
11444#endif
11445#ifdef F_GETOWN
11446 case F_GETOWN:
11447 len = 1;
11448 break;
11449#endif
11450#ifdef F_SETOWN
11451 case F_SETOWN:
11452 len = sizeof(fcntl_arg_t);
11453 break;
11454#endif
11455#ifdef F_GETOWN_EX /* linux specific */
11456 case F_GETOWN_EX:
11457 len = sizeof(struct f_owner_ex);
11458 break;
11459#endif
11460#ifdef F_SETOWN_EX /* linux specific */
11461 case F_SETOWN_EX:
11462 len = sizeof(struct f_owner_ex);
11463 break;
11464#endif
11465#ifdef F_GETLK
11466 case F_GETLK:
11467 len = sizeof(struct flock);
11468 break;
11469#endif
11470#ifdef F_SETLK
11471 case F_SETLK:
11472 len = sizeof(struct flock);
11473 break;
11474#endif
11475#ifdef F_SETLKW
11476 case F_SETLKW:
11477 len = sizeof(struct flock);
11478 break;
11479#endif
11480#ifdef F_READAHEAD /* bsd specific */
11481 case F_READAHEAD:
11482 len = sizeof(int);
11483 break;
11484#endif
11485#ifdef F_RDAHEAD /* Darwin specific */
11486 case F_RDAHEAD:
11487 len = sizeof(int);
11488 break;
11489#endif
11490#ifdef F_GETSIG /* linux specific */
11491 case F_GETSIG:
11492 len = 1;
11493 break;
11494#endif
11495#ifdef F_SETSIG /* linux specific */
11496 case F_SETSIG:
11497 len = sizeof(fcntl_arg_t);
11498 break;
11499#endif
11500#ifdef F_GETLEASE /* linux specific */
11501 case F_GETLEASE:
11502 len = 1;
11503 break;
11504#endif
11505#ifdef F_SETLEASE /* linux specific */
11506 case F_SETLEASE:
11507 len = sizeof(fcntl_arg_t);
11508 break;
11509#endif
11510#ifdef F_NOTIFY /* linux specific */
11511 case F_NOTIFY:
11512 len = sizeof(fcntl_arg_t);
11513 break;
11514#endif
11515
11516 default:
11517 len = 256;
11518 break;
11519 }
11520
11521 return len;
11522}
11523#else /* HAVE_FCNTL */
11524static long
11525fcntl_narg_len(ioctl_req_t cmd)
11526{
11527 return 0;
11528}
11529#endif /* HAVE_FCNTL */
11530
11531#define NARG_SENTINEL 17
11532
11533static long
11534setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11535{
11536 long narg = 0;
11537 VALUE arg = *argp;
11538
11539 if (!RTEST(arg)) {
11540 narg = 0;
11541 }
11542 else if (FIXNUM_P(arg)) {
11543 narg = FIX2LONG(arg);
11544 }
11545 else if (arg == Qtrue) {
11546 narg = 1;
11547 }
11548 else {
11549 VALUE tmp = rb_check_string_type(arg);
11550
11551 if (NIL_P(tmp)) {
11552 narg = NUM2LONG(arg);
11553 }
11554 else {
11555 char *ptr;
11556 long len, slen;
11557
11558 *argp = arg = tmp;
11559 len = narg_len(cmd);
11560 rb_str_modify(arg);
11561
11562 slen = RSTRING_LEN(arg);
11563 /* expand for data + sentinel. */
11564 if (slen < len+1) {
11565 rb_str_resize(arg, len+1);
11566 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11567 slen = len+1;
11568 }
11569 /* a little sanity check here */
11570 ptr = RSTRING_PTR(arg);
11571 ptr[slen - 1] = NARG_SENTINEL;
11572 narg = (long)(SIGNED_VALUE)ptr;
11573 }
11574 }
11575
11576 return narg;
11577}
11578
11579static VALUE
11580finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11581{
11582 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11583 if (RB_TYPE_P(arg, T_STRING)) {
11584 char *ptr;
11585 long slen;
11586 RSTRING_GETMEM(arg, ptr, slen);
11587 if (ptr[slen-1] != NARG_SENTINEL)
11588 rb_raise(rb_eArgError, "return value overflowed string");
11589 ptr[slen-1] = '\0';
11590 }
11591
11592 return INT2NUM(retval);
11593}
11594
11595#ifdef HAVE_IOCTL
11596static VALUE
11597rb_ioctl(VALUE io, VALUE req, VALUE arg)
11598{
11599 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11600 rb_io_t *fptr;
11601 long narg;
11602 int retval;
11603
11604 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11605 GetOpenFile(io, fptr);
11606 retval = do_ioctl(fptr, cmd, narg);
11607 return finish_narg(retval, arg, fptr);
11608}
11609
11610/*
11611 * call-seq:
11612 * ioctl(integer_cmd, argument) -> integer
11613 *
11614 * Invokes Posix system call {ioctl(2)}[https://man7.org/linux/man-pages/man2/ioctl.2.html],
11615 * which issues a low-level command to an I/O device.
11616 *
11617 * Issues a low-level command to an I/O device.
11618 * The arguments and returned value are platform-dependent.
11619 * The effect of the call is platform-dependent.
11620 *
11621 * If argument +argument+ is an integer, it is passed directly;
11622 * if it is a string, it is interpreted as a binary sequence of bytes.
11623 *
11624 * Not implemented on all platforms.
11625 *
11626 */
11627
11628static VALUE
11629rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11630{
11631 VALUE req, arg;
11632
11633 rb_scan_args(argc, argv, "11", &req, &arg);
11634 return rb_ioctl(io, req, arg);
11635}
11636#else
11637#define rb_io_ioctl rb_f_notimplement
11638#endif
11639
11640#ifdef HAVE_FCNTL
11641struct fcntl_arg {
11642 int fd;
11643 int cmd;
11644 long narg;
11645};
11646
11647static VALUE
11648nogvl_fcntl(void *ptr)
11649{
11650 struct fcntl_arg *arg = ptr;
11651
11652#if defined(F_DUPFD)
11653 if (arg->cmd == F_DUPFD)
11654 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11655#endif
11656 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11657}
11658
11659static int
11660do_fcntl(struct rb_io *io, int cmd, long narg)
11661{
11662 int retval;
11663 struct fcntl_arg arg;
11664
11665 arg.fd = io->fd;
11666 arg.cmd = cmd;
11667 arg.narg = narg;
11668
11669 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11670 if (retval != -1) {
11671 switch (cmd) {
11672#if defined(F_DUPFD)
11673 case F_DUPFD:
11674#endif
11675#if defined(F_DUPFD_CLOEXEC)
11676 case F_DUPFD_CLOEXEC:
11677#endif
11678 rb_update_max_fd(retval);
11679 }
11680 }
11681
11682 return retval;
11683}
11684
11685static VALUE
11686rb_fcntl(VALUE io, VALUE req, VALUE arg)
11687{
11688 int cmd = NUM2INT(req);
11689 rb_io_t *fptr;
11690 long narg;
11691 int retval;
11692
11693 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11694 GetOpenFile(io, fptr);
11695 retval = do_fcntl(fptr, cmd, narg);
11696 return finish_narg(retval, arg, fptr);
11697}
11698
11699/*
11700 * call-seq:
11701 * fcntl(integer_cmd, argument) -> integer
11702 *
11703 * Invokes Posix system call {fcntl(2)}[https://man7.org/linux/man-pages/man2/fcntl.2.html],
11704 * which provides a mechanism for issuing low-level commands to control or query
11705 * a file-oriented I/O stream. Arguments and results are platform
11706 * dependent.
11707 *
11708 * If +argument+ is a number, its value is passed directly;
11709 * if it is a string, it is interpreted as a binary sequence of bytes.
11710 * (Array#pack might be a useful way to build this string.)
11711 *
11712 * Not implemented on all platforms.
11713 *
11714 */
11715
11716static VALUE
11717rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11718{
11719 VALUE req, arg;
11720
11721 rb_scan_args(argc, argv, "11", &req, &arg);
11722 return rb_fcntl(io, req, arg);
11723}
11724#else
11725#define rb_io_fcntl rb_f_notimplement
11726#endif
11727
11728#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11729/*
11730 * call-seq:
11731 * syscall(integer_callno, *arguments) -> integer
11732 *
11733 * Invokes Posix system call {syscall(2)}[https://man7.org/linux/man-pages/man2/syscall.2.html],
11734 * which calls a specified function.
11735 *
11736 * Calls the operating system function identified by +integer_callno+;
11737 * returns the result of the function or raises SystemCallError if it failed.
11738 * The effect of the call is platform-dependent.
11739 * The arguments and returned value are platform-dependent.
11740 *
11741 * For each of +arguments+: if it is an integer, it is passed directly;
11742 * if it is a string, it is interpreted as a binary sequence of bytes.
11743 * There may be as many as nine such arguments.
11744 *
11745 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11746 * are platform-dependent.
11747 *
11748 * Note: Method +syscall+ is essentially unsafe and unportable.
11749 * The DL (Fiddle) library is preferred for safer and a bit
11750 * more portable programming.
11751 *
11752 * Not implemented on all platforms.
11753 *
11754 */
11755
11756static VALUE
11757rb_f_syscall(int argc, VALUE *argv, VALUE _)
11758{
11759 VALUE arg[8];
11760#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11761# define SYSCALL __syscall
11762# define NUM2SYSCALLID(x) NUM2LONG(x)
11763# define RETVAL2NUM(x) LONG2NUM(x)
11764# if SIZEOF_LONG == 8
11765 long num, retval = -1;
11766# elif SIZEOF_LONG_LONG == 8
11767 long long num, retval = -1;
11768# else
11769# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11770# endif
11771#elif defined(__linux__)
11772# define SYSCALL syscall
11773# define NUM2SYSCALLID(x) NUM2LONG(x)
11774# define RETVAL2NUM(x) LONG2NUM(x)
11775 /*
11776 * Linux man page says, syscall(2) function prototype is below.
11777 *
11778 * int syscall(int number, ...);
11779 *
11780 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11781 */
11782 long num, retval = -1;
11783#else
11784# define SYSCALL syscall
11785# define NUM2SYSCALLID(x) NUM2INT(x)
11786# define RETVAL2NUM(x) INT2NUM(x)
11787 int num, retval = -1;
11788#endif
11789 int i;
11790
11791 if (RTEST(ruby_verbose)) {
11793 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11794 }
11795
11796 if (argc == 0)
11797 rb_raise(rb_eArgError, "too few arguments for syscall");
11798 if (argc > numberof(arg))
11799 rb_raise(rb_eArgError, "too many arguments for syscall");
11800 num = NUM2SYSCALLID(argv[0]); ++argv;
11801 for (i = argc - 1; i--; ) {
11802 VALUE v = rb_check_string_type(argv[i]);
11803
11804 if (!NIL_P(v)) {
11805 StringValue(v);
11806 rb_str_modify(v);
11807 arg[i] = (VALUE)StringValueCStr(v);
11808 }
11809 else {
11810 arg[i] = (VALUE)NUM2LONG(argv[i]);
11811 }
11812 }
11813
11814 switch (argc) {
11815 case 1:
11816 retval = SYSCALL(num);
11817 break;
11818 case 2:
11819 retval = SYSCALL(num, arg[0]);
11820 break;
11821 case 3:
11822 retval = SYSCALL(num, arg[0],arg[1]);
11823 break;
11824 case 4:
11825 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11826 break;
11827 case 5:
11828 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11829 break;
11830 case 6:
11831 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11832 break;
11833 case 7:
11834 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11835 break;
11836 case 8:
11837 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11838 break;
11839 }
11840
11841 if (retval == -1)
11842 rb_sys_fail(0);
11843 return RETVAL2NUM(retval);
11844#undef SYSCALL
11845#undef NUM2SYSCALLID
11846#undef RETVAL2NUM
11847}
11848#else
11849#define rb_f_syscall rb_f_notimplement
11850#endif
11851
11852static VALUE
11853io_new_instance(VALUE args)
11854{
11855 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11856}
11857
11858static rb_encoding *
11859find_encoding(VALUE v)
11860{
11861 rb_encoding *enc = rb_find_encoding(v);
11862 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11863 return enc;
11864}
11865
11866static void
11867io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11868{
11869 rb_encoding *enc, *enc2;
11870 int ecflags = fptr->encs.ecflags;
11871 VALUE ecopts, tmp;
11872
11873 if (!NIL_P(v2)) {
11874 enc2 = find_encoding(v1);
11875 tmp = rb_check_string_type(v2);
11876 if (!NIL_P(tmp)) {
11877 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11878 /* Special case - "-" => no transcoding */
11879 enc = enc2;
11880 enc2 = NULL;
11881 }
11882 else
11883 enc = find_encoding(v2);
11884 if (enc == enc2) {
11885 /* Special case - "-" => no transcoding */
11886 enc2 = NULL;
11887 }
11888 }
11889 else {
11890 enc = find_encoding(v2);
11891 if (enc == enc2) {
11892 /* Special case - "-" => no transcoding */
11893 enc2 = NULL;
11894 }
11895 }
11896 if (enc2 == rb_ascii8bit_encoding()) {
11897 /* If external is ASCII-8BIT, no transcoding */
11898 enc = enc2;
11899 enc2 = NULL;
11900 }
11901 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11902 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11903 }
11904 else {
11905 if (NIL_P(v1)) {
11906 /* Set to default encodings */
11907 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11908 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11909 ecopts = Qnil;
11910 }
11911 else {
11912 tmp = rb_check_string_type(v1);
11913 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11914 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11915 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11916 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11917 }
11918 else {
11919 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11920 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11921 ecopts = Qnil;
11922 }
11923 }
11924 }
11925 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11926 fptr->encs.enc = enc;
11927 fptr->encs.enc2 = enc2;
11928 fptr->encs.ecflags = ecflags;
11929 fptr->encs.ecopts = ecopts;
11930 clear_codeconv(fptr);
11931
11932}
11933
11935 rb_io_t *fptr;
11936 VALUE v1;
11937 VALUE v2;
11938 VALUE opt;
11939};
11940
11941static VALUE
11942io_encoding_set_v(VALUE v)
11943{
11944 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11945 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11946 return Qnil;
11947}
11948
11949static VALUE
11950pipe_pair_close(VALUE rw)
11951{
11952 VALUE *rwp = (VALUE *)rw;
11953 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11954}
11955
11956/*
11957 * call-seq:
11958 * IO.pipe(**opts) -> [read_io, write_io]
11959 * IO.pipe(enc, **opts) -> [read_io, write_io]
11960 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11961 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11962 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11963 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11964 *
11965 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11966 * connected to each other.
11967 *
11968 * If argument +enc_string+ is given, it must be a string containing one of:
11969 *
11970 * - The name of the encoding to be used as the external encoding.
11971 * - The colon-separated names of two encodings to be used as the external
11972 * and internal encodings.
11973 *
11974 * If argument +int_enc+ is given, it must be an Encoding object
11975 * or encoding name string that specifies the internal encoding to be used;
11976 * if argument +ext_enc+ is also given, it must be an Encoding object
11977 * or encoding name string that specifies the external encoding to be used.
11978 *
11979 * The string read from +read_io+ is tagged with the external encoding;
11980 * if an internal encoding is also specified, the string is converted
11981 * to, and tagged with, that encoding.
11982 *
11983 * If any encoding is specified,
11984 * optional hash arguments specify the conversion option.
11985 *
11986 * Optional keyword arguments +opts+ specify:
11987 *
11988 * - {Open Options}[rdoc-ref:IO@Open+Options].
11989 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11990 *
11991 * With no block given, returns the two endpoints in an array:
11992 *
11993 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11994 *
11995 * With a block given, calls the block with the two endpoints;
11996 * closes both endpoints and returns the value of the block:
11997 *
11998 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11999 *
12000 * Output:
12001 *
12002 * #<IO:fd 6>
12003 * #<IO:fd 7>
12004 *
12005 * Not available on all platforms.
12006 *
12007 * In the example below, the two processes close the ends of the pipe
12008 * that they are not using. This is not just a cosmetic nicety. The
12009 * read end of a pipe will not generate an end of file condition if
12010 * there are any writers with the pipe still open. In the case of the
12011 * parent process, the <tt>rd.read</tt> will never return if it
12012 * does not first issue a <tt>wr.close</tt>:
12013 *
12014 * rd, wr = IO.pipe
12015 *
12016 * if fork
12017 * wr.close
12018 * puts "Parent got: <#{rd.read}>"
12019 * rd.close
12020 * Process.wait
12021 * else
12022 * rd.close
12023 * puts 'Sending message to parent'
12024 * wr.write "Hi Dad"
12025 * wr.close
12026 * end
12027 *
12028 * <em>produces:</em>
12029 *
12030 * Sending message to parent
12031 * Parent got: <Hi Dad>
12032 *
12033 */
12034
12035static VALUE
12036rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
12037{
12038 int pipes[2], state;
12039 VALUE r, w, args[3], v1, v2;
12040 VALUE opt;
12041 rb_io_t *fptr, *fptr2;
12042 struct io_encoding_set_args ies_args;
12043 enum rb_io_mode fmode = 0;
12044 VALUE ret;
12045
12046 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
12047 if (rb_pipe(pipes) < 0)
12048 rb_sys_fail(0);
12049
12050 args[0] = klass;
12051 args[1] = INT2NUM(pipes[0]);
12052 args[2] = INT2FIX(O_RDONLY);
12053 r = rb_protect(io_new_instance, (VALUE)args, &state);
12054 if (state) {
12055 close(pipes[0]);
12056 close(pipes[1]);
12057 rb_jump_tag(state);
12058 }
12059 GetOpenFile(r, fptr);
12060
12061 ies_args.fptr = fptr;
12062 ies_args.v1 = v1;
12063 ies_args.v2 = v2;
12064 ies_args.opt = opt;
12065 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
12066 if (state) {
12067 close(pipes[1]);
12068 io_close(r);
12069 rb_jump_tag(state);
12070 }
12071
12072 args[1] = INT2NUM(pipes[1]);
12073 args[2] = INT2FIX(O_WRONLY);
12074 w = rb_protect(io_new_instance, (VALUE)args, &state);
12075 if (state) {
12076 close(pipes[1]);
12077 if (!NIL_P(r)) rb_io_close(r);
12078 rb_jump_tag(state);
12079 }
12080 GetOpenFile(w, fptr2);
12081 rb_io_synchronized(fptr2);
12082
12083 extract_binmode(opt, &fmode);
12084
12085 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
12088 }
12089
12090#if DEFAULT_TEXTMODE
12091 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12092 fptr->mode &= ~FMODE_TEXTMODE;
12093 setmode(fptr->fd, O_BINARY);
12094 }
12095#if RUBY_CRLF_ENVIRONMENT
12098 }
12099#endif
12100#endif
12101 fptr->mode |= fmode;
12102#if DEFAULT_TEXTMODE
12103 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12104 fptr2->mode &= ~FMODE_TEXTMODE;
12105 setmode(fptr2->fd, O_BINARY);
12106 }
12107#endif
12108 fptr2->mode |= fmode;
12109
12110 ret = rb_assoc_new(r, w);
12111 if (rb_block_given_p()) {
12112 VALUE rw[2];
12113 rw[0] = r;
12114 rw[1] = w;
12115 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12116 }
12117 return ret;
12118}
12119
12121 int argc;
12122 VALUE *argv;
12123 VALUE io;
12124};
12125
12126static void
12127open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12128{
12129 VALUE path, v;
12130 VALUE vmode = Qnil, vperm = Qnil;
12131
12132 path = *argv++;
12133 argc--;
12134 FilePathValue(path);
12135 arg->io = 0;
12136 arg->argc = argc;
12137 arg->argv = argv;
12138 if (NIL_P(opt)) {
12139 vmode = INT2NUM(O_RDONLY);
12140 vperm = INT2FIX(0666);
12141 }
12142 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12143 int n;
12144
12145 v = rb_to_array_type(v);
12146 n = RARRAY_LENINT(v);
12147 rb_check_arity(n, 0, 3); /* rb_io_open */
12148 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12149 }
12150 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12151}
12152
12153static VALUE
12154io_s_foreach(VALUE v)
12155{
12156 struct getline_arg *arg = (void *)v;
12157 VALUE str;
12158
12159 if (arg->limit == 0)
12160 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12161 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12162 rb_lastline_set(str);
12163 rb_yield(str);
12164 }
12166 return Qnil;
12167}
12168
12169/*
12170 * call-seq:
12171 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12172 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12173 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12174 * IO.foreach(...) -> an_enumerator
12175 *
12176 * Calls the block with each successive line read from the stream.
12177 *
12178 * The first argument must be a string that is the path to a file.
12179 *
12180 * With only argument +path+ given, parses lines from the file at the given +path+,
12181 * as determined by the default line separator,
12182 * and calls the block with each successive line:
12183 *
12184 * File.foreach('t.txt') {|line| p line }
12185 *
12186 * Output: the same as above.
12187 *
12188 * For both forms, command and path, the remaining arguments are the same.
12189 *
12190 * With argument +sep+ given, parses lines as determined by that line separator
12191 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12192 *
12193 * File.foreach('t.txt', 'li') {|line| p line }
12194 *
12195 * Output:
12196 *
12197 * "First li"
12198 * "ne\nSecond li"
12199 * "ne\n\nThird li"
12200 * "ne\nFourth li"
12201 * "ne\n"
12202 *
12203 * Each paragraph:
12204 *
12205 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12206 *
12207 * Output:
12208 *
12209 * "First line\nSecond line\n\n"
12210 * "Third line\nFourth line\n"
12211 *
12212 * With argument +limit+ given, parses lines as determined by the default
12213 * line separator and the given line-length limit
12214 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12215 *
12216 * File.foreach('t.txt', 7) {|line| p line }
12217 *
12218 * Output:
12219 *
12220 * "First l"
12221 * "ine\n"
12222 * "Second "
12223 * "line\n"
12224 * "\n"
12225 * "Third l"
12226 * "ine\n"
12227 * "Fourth l"
12228 * "line\n"
12229 *
12230 * With arguments +sep+ and +limit+ given,
12231 * combines the two behaviors
12232 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12233 *
12234 * Optional keyword arguments +opts+ specify:
12235 *
12236 * - {Open Options}[rdoc-ref:IO@Open+Options].
12237 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12238 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12239 *
12240 * Returns an Enumerator if no block is given.
12241 *
12242 */
12243
12244static VALUE
12245rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12246{
12247 VALUE opt;
12248 int orig_argc = argc;
12249 struct foreach_arg arg;
12250 struct getline_arg garg;
12251
12252 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12253 RETURN_ENUMERATOR(self, orig_argc, argv);
12254 extract_getline_args(argc-1, argv+1, &garg);
12255 open_key_args(self, argc, argv, opt, &arg);
12256 if (NIL_P(arg.io)) return Qnil;
12257 extract_getline_opts(opt, &garg);
12258 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12259 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12260}
12261
12262static VALUE
12263io_s_readlines(VALUE v)
12264{
12265 struct getline_arg *arg = (void *)v;
12266 return io_readlines(arg, arg->io);
12267}
12268
12269/*
12270 * call-seq:
12271 * IO.readlines(path, sep = $/, **opts) -> array
12272 * IO.readlines(path, limit, **opts) -> array
12273 * IO.readlines(path, sep, limit, **opts) -> array
12274 *
12275 * Returns an array of all lines read from the stream.
12276 *
12277 * The first argument must be a string that is the path to a file.
12278 *
12279 * With only argument +path+ given, parses lines from the file at the given +path+,
12280 * as determined by the default line separator,
12281 * and returns those lines in an array:
12282 *
12283 * IO.readlines('t.txt')
12284 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12285 *
12286 * With argument +sep+ given, parses lines as determined by that line separator
12287 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12288 *
12289 * # Ordinary separator.
12290 * IO.readlines('t.txt', 'li')
12291 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12292 * # Get-paragraphs separator.
12293 * IO.readlines('t.txt', '')
12294 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12295 * # Get-all separator.
12296 * IO.readlines('t.txt', nil)
12297 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12298 *
12299 * With argument +limit+ given, parses lines as determined by the default
12300 * line separator and the given line-length limit
12301 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12302 *
12303 * IO.readlines('t.txt', 7)
12304 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12305 *
12306 * With arguments +sep+ and +limit+ given,
12307 * combines the two behaviors
12308 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12309 *
12310 * Optional keyword arguments +opts+ specify:
12311 *
12312 * - {Open Options}[rdoc-ref:IO@Open+Options].
12313 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12314 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12315 *
12316 */
12317
12318static VALUE
12319rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12320{
12321 VALUE opt;
12322 struct foreach_arg arg;
12323 struct getline_arg garg;
12324
12325 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12326 extract_getline_args(argc-1, argv+1, &garg);
12327 open_key_args(io, argc, argv, opt, &arg);
12328 if (NIL_P(arg.io)) return Qnil;
12329 extract_getline_opts(opt, &garg);
12330 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12331 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12332}
12333
12334static VALUE
12335io_s_read(VALUE v)
12336{
12337 struct foreach_arg *arg = (void *)v;
12338 return io_read(arg->argc, arg->argv, arg->io);
12339}
12340
12341struct seek_arg {
12342 VALUE io;
12343 VALUE offset;
12344 int mode;
12345};
12346
12347static VALUE
12348seek_before_access(VALUE argp)
12349{
12350 struct seek_arg *arg = (struct seek_arg *)argp;
12351 rb_io_binmode(arg->io);
12352 return rb_io_seek(arg->io, arg->offset, arg->mode);
12353}
12354
12355/*
12356 * call-seq:
12357 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12358 *
12359 * Opens the stream, reads and returns some or all of its content,
12360 * and closes the stream; returns +nil+ if no bytes were read.
12361 *
12362 * The first argument must be a string that is the path to a file.
12363 *
12364 * With only argument +path+ given, reads in text mode and returns the entire content
12365 * of the file at the given path:
12366 *
12367 * File.read('t.txt')
12368 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
12369 * File.read('t.ja')
12370 * # => "こんにちは"
12371 * File.read('t.dat')
12372 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12373 *
12374 * On Windows, text mode can terminate reading and leave bytes in the file
12375 * unread when encountering certain special bytes. Consider using
12376 * IO.binread if all bytes in the file should be read.
12377 *
12378 * With argument +length+, returns +length+ bytes if available:
12379 *
12380 * File.read('t.txt', 7)
12381 * # => "First l"
12382 * File.read('t.ja', 7)
12383 * # => "\xE3\x81\x93\xE3\x82\x93\xE3"
12384 * File.read('t.dat', 7)
12385 * # => "\xFE\xFF\x99\x90\x99\x91\x99"
12386 *
12387 * Returns all bytes if +length+ is larger than the files size:
12388 *
12389 * File.read('t.txt', 700)
12390 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12391 * File.read('t.ja', 700)
12392 * # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
12393 * File.read('t.dat', 700)
12394 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12395 *
12396 * With arguments +length+ and +offset+, returns +length+ bytes
12397 * if available, beginning at the given +offset+:
12398 *
12399 * File.read('t.txt', 10, 2)
12400 * # => "rst line\r\n"
12401 * File.read('t.ja', 10, 2)
12402 * # => "\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1"
12403 * File.read('t.dat', 10, 2)
12404 * # => "\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12405 *
12406 * Returns +nil+ if +offset+ is past the end of the stream:
12407 *
12408 * File.read('t.txt', 10, 200)
12409 * # => nil
12410 *
12411 * Optional keyword arguments +opts+ specify:
12412 *
12413 * - {Open Options}[rdoc-ref:IO@Open+Options].
12414 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12415 *
12416 */
12417
12418static VALUE
12419rb_io_s_read(int argc, VALUE *argv, VALUE io)
12420{
12421 VALUE opt, offset;
12422 long off;
12423 struct foreach_arg arg;
12424
12425 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12426 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12427 rb_raise(rb_eArgError, "negative offset %ld given", off);
12428 }
12429 open_key_args(io, argc, argv, opt, &arg);
12430 if (NIL_P(arg.io)) return Qnil;
12431 if (!NIL_P(offset)) {
12432 struct seek_arg sarg;
12433 int state = 0;
12434 sarg.io = arg.io;
12435 sarg.offset = offset;
12436 sarg.mode = SEEK_SET;
12437 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12438 if (state) {
12439 rb_io_close(arg.io);
12440 rb_jump_tag(state);
12441 }
12442 if (arg.argc == 2) arg.argc = 1;
12443 }
12444 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12445}
12446
12447/*
12448 * call-seq:
12449 * IO.binread(path, length = nil, offset = 0) -> string or nil
12450 *
12451 * Behaves like IO.read, except that the stream is opened in binary mode
12452 * with ASCII-8BIT encoding.
12453 *
12454 */
12455
12456static VALUE
12457rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12458{
12459 VALUE offset;
12460 struct foreach_arg arg;
12461 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12462 enum {
12463 oflags = O_RDONLY
12464#ifdef O_BINARY
12465 |O_BINARY
12466#endif
12467 };
12468 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12469
12470 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12471 FilePathValue(argv[0]);
12472 convconfig.enc = rb_ascii8bit_encoding();
12473 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12474 if (NIL_P(arg.io)) return Qnil;
12475 arg.argv = argv+1;
12476 arg.argc = (argc > 1) ? 1 : 0;
12477 if (!NIL_P(offset)) {
12478 struct seek_arg sarg;
12479 int state = 0;
12480 sarg.io = arg.io;
12481 sarg.offset = offset;
12482 sarg.mode = SEEK_SET;
12483 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12484 if (state) {
12485 rb_io_close(arg.io);
12486 rb_jump_tag(state);
12487 }
12488 }
12489 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12490}
12491
12492static VALUE
12493io_s_write0(VALUE v)
12494{
12495 struct write_arg *arg = (void *)v;
12496 return io_write(arg->io,arg->str,arg->nosync);
12497}
12498
12499static VALUE
12500io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12501{
12502 VALUE string, offset, opt;
12503 struct foreach_arg arg;
12504 struct write_arg warg;
12505
12506 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12507
12508 if (NIL_P(opt)) opt = rb_hash_new();
12509 else opt = rb_hash_dup(opt);
12510
12511
12512 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12513 int mode = O_WRONLY|O_CREAT;
12514#ifdef O_BINARY
12515 if (binary) mode |= O_BINARY;
12516#endif
12517 if (NIL_P(offset)) mode |= O_TRUNC;
12518 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12519 }
12520 open_key_args(klass, argc, argv, opt, &arg);
12521
12522#ifndef O_BINARY
12523 if (binary) rb_io_binmode_m(arg.io);
12524#endif
12525
12526 if (NIL_P(arg.io)) return Qnil;
12527 if (!NIL_P(offset)) {
12528 struct seek_arg sarg;
12529 int state = 0;
12530 sarg.io = arg.io;
12531 sarg.offset = offset;
12532 sarg.mode = SEEK_SET;
12533 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12534 if (state) {
12535 rb_io_close(arg.io);
12536 rb_jump_tag(state);
12537 }
12538 }
12539
12540 warg.io = arg.io;
12541 warg.str = string;
12542 warg.nosync = 0;
12543
12544 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12545}
12546
12547/*
12548 * call-seq:
12549 * IO.write(path, data, offset = 0, **opts) -> nonnegative_integer
12550 *
12551 * Opens the stream, writes the given +data+ to it,
12552 * and closes the stream; returns the number of bytes written.
12553 *
12554 * The first argument must be a string that is the path to a file.
12555 *
12556 * With only arguments +path+ and +data+ given,
12557 * writes the given data to the file at that path:
12558 *
12559 * path = 't.tmp'
12560 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n") # => 47
12561 * File.write(path, 'こんにちは') # => 15
12562 * File.write(path, "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94") # => 12
12563 *
12564 * When +offset+ is zero (the default), the entire file content is overwritten:
12565 *
12566 * File.read(path) # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12567 * File.write(path, 'foo')
12568 * File.read(path) # => "foo"
12569 *
12570 * When +offset+ in within the file content, the file content is partly overwritten,
12571 * beginning at byte +offset+:
12572 *
12573 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12574 * File.write(path, 'LINE', 6)
12575 * File.read(path) # => "First LINE\nSecond line\n\nFourth line\nFifth line\n"
12576 *
12577 * When the file contains multi-byte characters,
12578 * the effect of writing may disturb some characters:
12579 *
12580 * File.write(path, "こんにちは")
12581 * File.write(path, 'FOO', 3) # Replace one 3-byte character.
12582 * File.read(path) # => "こFOOにちは"
12583 * File.write(path, 'BAR', 7) # Replace bytes in two different 3-byte characters.
12584 * File.read(path) # => "こFOO\xE3BAR\x81\xA1は"
12585 *
12586 * If +offset+ is outside the file content,
12587 * the file is padded with null characters <tt>"\u0000"</tt>:
12588 *
12589 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12590 * File.write(path, 'FOO', 55)
12591 * File.read(path)
12592 * # => "First line\nSecond line\n\nFourth line\nFifth line\n\u0000\u0000\u0000FOO"
12593 *
12594 * Optional keyword arguments +opts+ specify:
12595 *
12596 * - {Open Options}[rdoc-ref:IO@Open+Options].
12597 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12598 *
12599 */
12600
12601static VALUE
12602rb_io_s_write(int argc, VALUE *argv, VALUE io)
12603{
12604 return io_s_write(argc, argv, io, 0);
12605}
12606
12607/*
12608 * call-seq:
12609 * IO.binwrite(path, string, offset = 0, **opts) -> integer
12610 *
12611 * Behaves like IO.write, except that the stream is opened in binary mode
12612 * with ASCII-8BIT encoding.
12613 *
12614 */
12615
12616static VALUE
12617rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12618{
12619 return io_s_write(argc, argv, io, 1);
12620}
12621
12623 VALUE src;
12624 VALUE dst;
12625 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12626 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12627
12628 rb_io_t *src_fptr;
12629 rb_io_t *dst_fptr;
12630 unsigned close_src : 1;
12631 unsigned close_dst : 1;
12632 int error_no;
12633 rb_off_t total;
12634 const char *syserr;
12635 const char *notimp;
12636 VALUE th;
12637 struct stat src_stat;
12638 struct stat dst_stat;
12639#ifdef HAVE_FCOPYFILE
12640 copyfile_state_t copyfile_state;
12641#endif
12642};
12643
12644static void *
12645exec_interrupts(void *arg)
12646{
12647 VALUE th = (VALUE)arg;
12648 rb_thread_execute_interrupts(th);
12649 return NULL;
12650}
12651
12652/*
12653 * returns TRUE if the preceding system call was interrupted
12654 * so we can continue. If the thread was interrupted, we
12655 * reacquire the GVL to execute interrupts before continuing.
12656 */
12657static int
12658maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12659{
12660 switch (errno) {
12661 case EINTR:
12662#if defined(ERESTART)
12663 case ERESTART:
12664#endif
12665 if (rb_thread_interrupted(stp->th)) {
12666 if (has_gvl)
12667 rb_thread_execute_interrupts(stp->th);
12668 else
12669 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12670 }
12671 return TRUE;
12672 }
12673 return FALSE;
12674}
12675
12677 VALUE scheduler;
12678
12679 rb_io_t *fptr;
12680 short events;
12681
12682 VALUE result;
12683};
12684
12685static void *
12686fiber_scheduler_wait_for(void * _arguments)
12687{
12688 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12689
12690 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12691
12692 return NULL;
12693}
12694
12695#if USE_POLL
12696# define IOWAIT_SYSCALL "poll"
12697STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12698STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12699static int
12700nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12701{
12703 if (scheduler != Qnil) {
12704 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12705 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12706 return RTEST(args.result);
12707 }
12708
12709 int fd = fptr->fd;
12710 if (fd == -1) return 0;
12711
12712 struct pollfd fds;
12713
12714 fds.fd = fd;
12715 fds.events = events;
12716
12717 int timeout_milliseconds = -1;
12718
12719 if (timeout) {
12720 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12721 }
12722
12723 return poll(&fds, 1, timeout_milliseconds);
12724}
12725#else /* !USE_POLL */
12726# define IOWAIT_SYSCALL "select"
12727static int
12728nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12729{
12731 if (scheduler != Qnil) {
12732 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12733 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12734 return RTEST(args.result);
12735 }
12736
12737 int fd = fptr->fd;
12738
12739 if (fd == -1) {
12740 errno = EBADF;
12741 return -1;
12742 }
12743
12744 rb_fdset_t fds;
12745 int ret;
12746
12747 rb_fd_init(&fds);
12748 rb_fd_set(fd, &fds);
12749
12750 switch (events) {
12751 case RB_WAITFD_IN:
12752 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12753 break;
12754 case RB_WAITFD_OUT:
12755 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12756 break;
12757 default:
12758 VM_UNREACHABLE(nogvl_wait_for);
12759 }
12760
12761 rb_fd_term(&fds);
12762
12763 // On timeout, this returns 0.
12764 return ret;
12765}
12766#endif /* !USE_POLL */
12767
12768static int
12769maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12770{
12771 int ret;
12772
12773 do {
12774 if (has_gvl) {
12776 }
12777 else {
12778 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12779 }
12780 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12781
12782 if (ret < 0) {
12783 stp->syserr = IOWAIT_SYSCALL;
12784 stp->error_no = errno;
12785 return ret;
12786 }
12787 return 0;
12788}
12789
12790static int
12791nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12792{
12793 int ret;
12794
12795 do {
12796 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12797 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12798
12799 if (ret < 0) {
12800 stp->syserr = IOWAIT_SYSCALL;
12801 stp->error_no = errno;
12802 return ret;
12803 }
12804 return 0;
12805}
12806
12807#ifdef USE_COPY_FILE_RANGE
12808
12809static ssize_t
12810simple_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)
12811{
12812#ifdef HAVE_COPY_FILE_RANGE
12813 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12814#else
12815 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12816#endif
12817}
12818
12819static int
12820nogvl_copy_file_range(struct copy_stream_struct *stp)
12821{
12822 ssize_t ss;
12823 rb_off_t src_size;
12824 rb_off_t copy_length, src_offset, *src_offset_ptr;
12825
12826 if (!S_ISREG(stp->src_stat.st_mode))
12827 return 0;
12828
12829 src_size = stp->src_stat.st_size;
12830 src_offset = stp->src_offset;
12831 if (src_offset >= (rb_off_t)0) {
12832 src_offset_ptr = &src_offset;
12833 }
12834 else {
12835 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12836 }
12837
12838 copy_length = stp->copy_length;
12839 if (copy_length < (rb_off_t)0) {
12840 if (src_offset < (rb_off_t)0) {
12841 rb_off_t current_offset;
12842 errno = 0;
12843 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12844 if (current_offset < (rb_off_t)0 && errno) {
12845 stp->syserr = "lseek";
12846 stp->error_no = errno;
12847 return (int)current_offset;
12848 }
12849 copy_length = src_size - current_offset;
12850 }
12851 else {
12852 copy_length = src_size - src_offset;
12853 }
12854 }
12855
12856 retry_copy_file_range:
12857# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12858 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12859 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12860# else
12861 ss = (ssize_t)copy_length;
12862# endif
12863 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12864 if (0 < ss) {
12865 stp->total += ss;
12866 copy_length -= ss;
12867 if (0 < copy_length) {
12868 goto retry_copy_file_range;
12869 }
12870 }
12871 if (ss < 0) {
12872 if (maygvl_copy_stream_continue_p(0, stp)) {
12873 goto retry_copy_file_range;
12874 }
12875 switch (errno) {
12876 case EINVAL:
12877 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12878 docker container) */
12879#ifdef ENOSYS
12880 case ENOSYS:
12881#endif
12882#ifdef EXDEV
12883 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12884#endif
12885 return 0;
12886 case EAGAIN:
12887#if EWOULDBLOCK != EAGAIN
12888 case EWOULDBLOCK:
12889#endif
12890 {
12891 int ret = nogvl_copy_stream_wait_write(stp);
12892 if (ret < 0) return ret;
12893 }
12894 goto retry_copy_file_range;
12895 case EBADF:
12896 {
12897 int e = errno;
12898 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12899
12900 if (flags != -1 && flags & O_APPEND) {
12901 return 0;
12902 }
12903 errno = e;
12904 }
12905 }
12906 stp->syserr = "copy_file_range";
12907 stp->error_no = errno;
12908 return (int)ss;
12909 }
12910 return 1;
12911}
12912#endif
12913
12914#ifdef HAVE_FCOPYFILE
12915static int
12916nogvl_fcopyfile(struct copy_stream_struct *stp)
12917{
12918 rb_off_t cur, ss = 0;
12919 const rb_off_t src_offset = stp->src_offset;
12920 int ret;
12921
12922 if (stp->copy_length >= (rb_off_t)0) {
12923 /* copy_length can't be specified in fcopyfile(3) */
12924 return 0;
12925 }
12926
12927 if (!S_ISREG(stp->src_stat.st_mode))
12928 return 0;
12929
12930 if (!S_ISREG(stp->dst_stat.st_mode))
12931 return 0;
12932 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12933 return 0;
12934 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12935 /* fcopyfile(3) appends src IO to dst IO and then truncates
12936 * dst IO to src IO's original size. */
12937 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12938 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12939 if (end > (rb_off_t)0) return 0;
12940 }
12941
12942 if (src_offset > (rb_off_t)0) {
12943 rb_off_t r;
12944
12945 /* get current offset */
12946 errno = 0;
12947 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12948 if (cur < (rb_off_t)0 && errno) {
12949 stp->error_no = errno;
12950 return 1;
12951 }
12952
12953 errno = 0;
12954 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12955 if (r < (rb_off_t)0 && errno) {
12956 stp->error_no = errno;
12957 return 1;
12958 }
12959 }
12960
12961 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12962 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12963 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12964
12965 if (ret == 0) { /* success */
12966 stp->total = ss;
12967 if (src_offset > (rb_off_t)0) {
12968 rb_off_t r;
12969 errno = 0;
12970 /* reset offset */
12971 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12972 if (r < (rb_off_t)0 && errno) {
12973 stp->error_no = errno;
12974 return 1;
12975 }
12976 }
12977 }
12978 else {
12979 switch (errno) {
12980 case ENOTSUP:
12981 case EPERM:
12982 case EINVAL:
12983 return 0;
12984 }
12985 stp->syserr = "fcopyfile";
12986 stp->error_no = errno;
12987 return (int)ret;
12988 }
12989 return 1;
12990}
12991#endif
12992
12993#ifdef HAVE_SENDFILE
12994
12995# ifdef __linux__
12996# define USE_SENDFILE
12997
12998# ifdef HAVE_SYS_SENDFILE_H
12999# include <sys/sendfile.h>
13000# endif
13001
13002static ssize_t
13003simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13004{
13005 return sendfile(out_fd, in_fd, offset, (size_t)count);
13006}
13007
13008# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
13009/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
13010 * without cpuset -l 0.
13011 */
13012# define USE_SENDFILE
13013
13014static ssize_t
13015simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13016{
13017 int r;
13018 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
13019 rb_off_t sbytes;
13020# ifdef __APPLE__
13021 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
13022 sbytes = count;
13023# else
13024 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
13025# endif
13026 if (r != 0 && sbytes == 0) return r;
13027 if (offset) {
13028 *offset += sbytes;
13029 }
13030 else {
13031 lseek(in_fd, sbytes, SEEK_CUR);
13032 }
13033 return (ssize_t)sbytes;
13034}
13035
13036# endif
13037
13038#endif
13039
13040#ifdef USE_SENDFILE
13041static int
13042nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
13043{
13044 ssize_t ss;
13045 rb_off_t src_size;
13046 rb_off_t copy_length;
13047 rb_off_t src_offset;
13048 int use_pread;
13049
13050 if (!S_ISREG(stp->src_stat.st_mode))
13051 return 0;
13052
13053 src_size = stp->src_stat.st_size;
13054#ifndef __linux__
13055 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
13056 return 0;
13057#endif
13058
13059 src_offset = stp->src_offset;
13060 use_pread = src_offset >= (rb_off_t)0;
13061
13062 copy_length = stp->copy_length;
13063 if (copy_length < (rb_off_t)0) {
13064 if (use_pread)
13065 copy_length = src_size - src_offset;
13066 else {
13067 rb_off_t cur;
13068 errno = 0;
13069 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13070 if (cur < (rb_off_t)0 && errno) {
13071 stp->syserr = "lseek";
13072 stp->error_no = errno;
13073 return (int)cur;
13074 }
13075 copy_length = src_size - cur;
13076 }
13077 }
13078
13079 retry_sendfile:
13080# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13081 /* we are limited by the 32-bit ssize_t return value on 32-bit */
13082 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13083# else
13084 ss = (ssize_t)copy_length;
13085# endif
13086 if (use_pread) {
13087 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
13088 }
13089 else {
13090 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
13091 }
13092 if (0 < ss) {
13093 stp->total += ss;
13094 copy_length -= ss;
13095 if (0 < copy_length) {
13096 goto retry_sendfile;
13097 }
13098 }
13099 if (ss < 0) {
13100 if (maygvl_copy_stream_continue_p(0, stp))
13101 goto retry_sendfile;
13102 switch (errno) {
13103 case EINVAL:
13104#ifdef ENOSYS
13105 case ENOSYS:
13106#endif
13107#ifdef EOPNOTSUP
13108 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
13109 see also: [Feature #16965] */
13110 case EOPNOTSUP:
13111#endif
13112 return 0;
13113 case EAGAIN:
13114#if EWOULDBLOCK != EAGAIN
13115 case EWOULDBLOCK:
13116#endif
13117 {
13118 int ret;
13119#ifndef __linux__
13120 /*
13121 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
13122 * select() reports regular files to always be "ready", so
13123 * there is no need to select() on it.
13124 * Other OSes may have the same limitation for sendfile() which
13125 * allow us to bypass maygvl_copy_stream_wait_read()...
13126 */
13127 ret = maygvl_copy_stream_wait_read(0, stp);
13128 if (ret < 0) return ret;
13129#endif
13130 ret = nogvl_copy_stream_wait_write(stp);
13131 if (ret < 0) return ret;
13132 }
13133 goto retry_sendfile;
13134 }
13135 stp->syserr = "sendfile";
13136 stp->error_no = errno;
13137 return (int)ss;
13138 }
13139 return 1;
13140}
13141#endif
13142
13143static ssize_t
13144maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13145{
13146 if (has_gvl)
13147 return rb_io_read_memory(fptr, buf, count);
13148 else
13149 return read(fptr->fd, buf, count);
13150}
13151
13152static ssize_t
13153maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13154{
13155 ssize_t ss;
13156 retry_read:
13157 if (offset < (rb_off_t)0) {
13158 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13159 }
13160 else {
13161 ss = pread(stp->src_fptr->fd, buf, len, offset);
13162 }
13163 if (ss == 0) {
13164 return 0;
13165 }
13166 if (ss < 0) {
13167 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13168 goto retry_read;
13169 switch (errno) {
13170 case EAGAIN:
13171#if EWOULDBLOCK != EAGAIN
13172 case EWOULDBLOCK:
13173#endif
13174 {
13175 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13176 if (ret < 0) return ret;
13177 }
13178 goto retry_read;
13179#ifdef ENOSYS
13180 case ENOSYS:
13181 stp->notimp = "pread";
13182 return ss;
13183#endif
13184 }
13185 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13186 stp->error_no = errno;
13187 }
13188 return ss;
13189}
13190
13191static int
13192nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13193{
13194 ssize_t ss;
13195 int off = 0;
13196 while (len) {
13197 ss = write(stp->dst_fptr->fd, buf+off, len);
13198 if (ss < 0) {
13199 if (maygvl_copy_stream_continue_p(0, stp))
13200 continue;
13201 if (io_again_p(errno)) {
13202 int ret = nogvl_copy_stream_wait_write(stp);
13203 if (ret < 0) return ret;
13204 continue;
13205 }
13206 stp->syserr = "write";
13207 stp->error_no = errno;
13208 return (int)ss;
13209 }
13210 off += (int)ss;
13211 len -= (int)ss;
13212 stp->total += ss;
13213 }
13214 return 0;
13215}
13216
13217static void
13218nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13219{
13220 char buf[1024*16];
13221 size_t len;
13222 ssize_t ss;
13223 int ret;
13224 rb_off_t copy_length;
13225 rb_off_t src_offset;
13226 int use_eof;
13227 int use_pread;
13228
13229 copy_length = stp->copy_length;
13230 use_eof = copy_length < (rb_off_t)0;
13231 src_offset = stp->src_offset;
13232 use_pread = src_offset >= (rb_off_t)0;
13233
13234 if (use_pread && stp->close_src) {
13235 rb_off_t r;
13236 errno = 0;
13237 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13238 if (r < (rb_off_t)0 && errno) {
13239 stp->syserr = "lseek";
13240 stp->error_no = errno;
13241 return;
13242 }
13243 src_offset = (rb_off_t)-1;
13244 use_pread = 0;
13245 }
13246
13247 while (use_eof || 0 < copy_length) {
13248 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13249 len = (size_t)copy_length;
13250 }
13251 else {
13252 len = sizeof(buf);
13253 }
13254 if (use_pread) {
13255 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13256 if (0 < ss)
13257 src_offset += ss;
13258 }
13259 else {
13260 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13261 }
13262 if (ss <= 0) /* EOF or error */
13263 return;
13264
13265 ret = nogvl_copy_stream_write(stp, buf, ss);
13266 if (ret < 0)
13267 return;
13268
13269 if (!use_eof)
13270 copy_length -= ss;
13271 }
13272}
13273
13274static void *
13275nogvl_copy_stream_func(void *arg)
13276{
13277 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13278#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13279 int ret;
13280#endif
13281
13282#ifdef USE_COPY_FILE_RANGE
13283 ret = nogvl_copy_file_range(stp);
13284 if (ret != 0)
13285 goto finish; /* error or success */
13286#endif
13287
13288#ifdef HAVE_FCOPYFILE
13289 ret = nogvl_fcopyfile(stp);
13290 if (ret != 0)
13291 goto finish; /* error or success */
13292#endif
13293
13294#ifdef USE_SENDFILE
13295 ret = nogvl_copy_stream_sendfile(stp);
13296 if (ret != 0)
13297 goto finish; /* error or success */
13298#endif
13299
13300 nogvl_copy_stream_read_write(stp);
13301
13302#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13303 finish:
13304#endif
13305 return 0;
13306}
13307
13308static VALUE
13309copy_stream_fallback_body(VALUE arg)
13310{
13311 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13312 const int buflen = 16*1024;
13313 VALUE n;
13314 VALUE buf = rb_str_buf_new(buflen);
13315 rb_off_t rest = stp->copy_length;
13316 rb_off_t off = stp->src_offset;
13317 ID read_method = id_readpartial;
13318
13319 if (!stp->src_fptr) {
13320 if (!rb_respond_to(stp->src, read_method)) {
13321 read_method = id_read;
13322 }
13323 }
13324
13325 while (1) {
13326 long numwrote;
13327 long l;
13328 rb_str_make_independent(buf);
13329 if (stp->copy_length < (rb_off_t)0) {
13330 l = buflen;
13331 }
13332 else {
13333 if (rest == 0) {
13334 rb_str_resize(buf, 0);
13335 break;
13336 }
13337 l = buflen < rest ? buflen : (long)rest;
13338 }
13339 if (!stp->src_fptr) {
13340 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13341
13342 if (read_method == id_read && NIL_P(rc))
13343 break;
13344 }
13345 else {
13346 ssize_t ss;
13347 rb_str_resize(buf, buflen);
13348 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13349 rb_str_resize(buf, ss > 0 ? ss : 0);
13350 if (ss < 0)
13351 return Qnil;
13352 if (ss == 0)
13353 rb_eof_error();
13354 if (off >= (rb_off_t)0)
13355 off += ss;
13356 }
13357 n = rb_io_write(stp->dst, buf);
13358 numwrote = NUM2LONG(n);
13359 stp->total += numwrote;
13360 rest -= numwrote;
13361 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13362 break;
13363 }
13364 }
13365
13366 return Qnil;
13367}
13368
13369static VALUE
13370copy_stream_fallback(struct copy_stream_struct *stp)
13371{
13372 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13373 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13374 }
13375 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13376 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13377 rb_eEOFError, (VALUE)0);
13378 return Qnil;
13379}
13380
13381static VALUE
13382copy_stream_body(VALUE arg)
13383{
13384 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13385 VALUE src_io = stp->src, dst_io = stp->dst;
13386 const int common_oflags = 0
13387#ifdef O_NOCTTY
13388 | O_NOCTTY
13389#endif
13390 ;
13391
13392 stp->th = rb_thread_current();
13393
13394 stp->total = 0;
13395
13396 if (src_io == argf ||
13397 !(RB_TYPE_P(src_io, T_FILE) ||
13398 RB_TYPE_P(src_io, T_STRING) ||
13399 rb_respond_to(src_io, rb_intern("to_path")))) {
13400 stp->src_fptr = NULL;
13401 }
13402 else {
13403 int stat_ret;
13404 VALUE tmp_io = rb_io_check_io(src_io);
13405 if (!NIL_P(tmp_io)) {
13406 src_io = tmp_io;
13407 }
13408 else if (!RB_TYPE_P(src_io, T_FILE)) {
13409 VALUE args[2];
13410 FilePathValue(src_io);
13411 args[0] = src_io;
13412 args[1] = INT2NUM(O_RDONLY|common_oflags);
13413 src_io = rb_class_new_instance(2, args, rb_cFile);
13414 stp->src = src_io;
13415 stp->close_src = 1;
13416 }
13417 RB_IO_POINTER(src_io, stp->src_fptr);
13418 rb_io_check_byte_readable(stp->src_fptr);
13419
13420 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13421 if (stat_ret < 0) {
13422 stp->syserr = "fstat";
13423 stp->error_no = errno;
13424 return Qnil;
13425 }
13426 }
13427
13428 if (dst_io == argf ||
13429 !(RB_TYPE_P(dst_io, T_FILE) ||
13430 RB_TYPE_P(dst_io, T_STRING) ||
13431 rb_respond_to(dst_io, rb_intern("to_path")))) {
13432 stp->dst_fptr = NULL;
13433 }
13434 else {
13435 int stat_ret;
13436 VALUE tmp_io = rb_io_check_io(dst_io);
13437 if (!NIL_P(tmp_io)) {
13438 dst_io = GetWriteIO(tmp_io);
13439 }
13440 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13441 VALUE args[3];
13442 FilePathValue(dst_io);
13443 args[0] = dst_io;
13444 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13445 args[2] = INT2FIX(0666);
13446 dst_io = rb_class_new_instance(3, args, rb_cFile);
13447 stp->dst = dst_io;
13448 stp->close_dst = 1;
13449 }
13450 else {
13451 dst_io = GetWriteIO(dst_io);
13452 stp->dst = dst_io;
13453 }
13454 RB_IO_POINTER(dst_io, stp->dst_fptr);
13455 rb_io_check_writable(stp->dst_fptr);
13456
13457 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13458 if (stat_ret < 0) {
13459 stp->syserr = "fstat";
13460 stp->error_no = errno;
13461 return Qnil;
13462 }
13463 }
13464
13465#ifdef O_BINARY
13466 if (stp->src_fptr)
13467 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13468#endif
13469 if (stp->dst_fptr)
13470 io_ascii8bit_binmode(stp->dst_fptr);
13471
13472 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13473 size_t len = stp->src_fptr->rbuf.len;
13474 VALUE str;
13475 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13476 len = (size_t)stp->copy_length;
13477 }
13478 str = rb_str_buf_new(len);
13479 rb_str_resize(str,len);
13480 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13481 if (stp->dst_fptr) { /* IO or filename */
13482 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13483 rb_sys_fail_on_write(stp->dst_fptr);
13484 }
13485 else /* others such as StringIO */
13486 rb_io_write(dst_io, str);
13487 rb_str_resize(str, 0);
13488 stp->total += len;
13489 if (stp->copy_length >= (rb_off_t)0)
13490 stp->copy_length -= len;
13491 }
13492
13493 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13494 rb_raise(rb_eIOError, "flush failed");
13495 }
13496
13497 if (stp->copy_length == 0)
13498 return Qnil;
13499
13500 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13501 return copy_stream_fallback(stp);
13502 }
13503
13504 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13505 return Qnil;
13506}
13507
13508static VALUE
13509copy_stream_finalize(VALUE arg)
13510{
13511 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13512
13513#ifdef HAVE_FCOPYFILE
13514 if (stp->copyfile_state) {
13515 copyfile_state_free(stp->copyfile_state);
13516 }
13517#endif
13518
13519 if (stp->close_src) {
13520 rb_io_close_m(stp->src);
13521 }
13522 if (stp->close_dst) {
13523 rb_io_close_m(stp->dst);
13524 }
13525 if (stp->syserr) {
13526 rb_syserr_fail(stp->error_no, stp->syserr);
13527 }
13528 if (stp->notimp) {
13529 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13530 }
13531 return Qnil;
13532}
13533
13534/*
13535 * call-seq:
13536 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13537 *
13538 * Copies from the given +src+ to the given +dst+,
13539 * returning the number of bytes copied.
13540 *
13541 * - The given +src+ must be one of the following:
13542 *
13543 * - The path to a readable file, from which source data is to be read.
13544 * - An \IO-like object, opened for reading and capable of responding
13545 * to method +:readpartial+ or method +:read+.
13546 *
13547 * - The given +dst+ must be one of the following:
13548 *
13549 * - The path to a writable file, to which data is to be written.
13550 * - An \IO-like object, opened for writing and capable of responding
13551 * to method +:write+.
13552 *
13553 * The examples here use file <tt>t.txt</tt> as source:
13554 *
13555 * File.read('t.txt')
13556 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13557 * File.read('t.txt').size # => 47
13558 *
13559 * If only arguments +src+ and +dst+ are given,
13560 * the entire source stream is copied:
13561 *
13562 * # Paths.
13563 * IO.copy_stream('t.txt', 't.tmp') # => 47
13564 *
13565 * # IOs (recall that a File is also an IO).
13566 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13567 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13568 * IO.copy_stream(src_io, dst_io) # => 47
13569 * src_io.close
13570 * dst_io.close
13571 *
13572 * With argument +src_length+ a non-negative integer,
13573 * no more than that many bytes are copied:
13574 *
13575 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13576 * File.read('t.tmp') # => "First line"
13577 *
13578 * With argument +src_offset+ also given,
13579 * the source stream is read beginning at that offset:
13580 *
13581 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13582 * IO.read('t.tmp') # => "Second line"
13583 *
13584 */
13585static VALUE
13586rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13587{
13588 VALUE src, dst, length, src_offset;
13589 struct copy_stream_struct st;
13590
13591 MEMZERO(&st, struct copy_stream_struct, 1);
13592
13593 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13594
13595 st.src = src;
13596 st.dst = dst;
13597
13598 st.src_fptr = NULL;
13599 st.dst_fptr = NULL;
13600
13601 if (NIL_P(length))
13602 st.copy_length = (rb_off_t)-1;
13603 else
13604 st.copy_length = NUM2OFFT(length);
13605
13606 if (NIL_P(src_offset))
13607 st.src_offset = (rb_off_t)-1;
13608 else
13609 st.src_offset = NUM2OFFT(src_offset);
13610
13611 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13612
13613 return OFFT2NUM(st.total);
13614}
13615
13616/*
13617 * call-seq:
13618 * external_encoding -> encoding or nil
13619 *
13620 * Returns the Encoding object that represents the encoding of the stream,
13621 * or +nil+ if the stream is in write mode and no encoding is specified.
13622 *
13623 * See {Encodings}[rdoc-ref:File@Encodings].
13624 *
13625 */
13626
13627static VALUE
13628rb_io_external_encoding(VALUE io)
13629{
13630 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13631
13632 if (fptr->encs.enc2) {
13633 return rb_enc_from_encoding(fptr->encs.enc2);
13634 }
13635 if (fptr->mode & FMODE_WRITABLE) {
13636 if (fptr->encs.enc)
13637 return rb_enc_from_encoding(fptr->encs.enc);
13638 return Qnil;
13639 }
13640 return rb_enc_from_encoding(io_read_encoding(fptr));
13641}
13642
13643/*
13644 * call-seq:
13645 * internal_encoding -> encoding or nil
13646 *
13647 * Returns the Encoding object that represents the encoding of the internal string,
13648 * if conversion is specified,
13649 * or +nil+ otherwise.
13650 *
13651 * See {Encodings}[rdoc-ref:File@Encodings].
13652 *
13653 */
13654
13655static VALUE
13656rb_io_internal_encoding(VALUE io)
13657{
13658 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13659
13660 if (!fptr->encs.enc2) return Qnil;
13661 return rb_enc_from_encoding(io_read_encoding(fptr));
13662}
13663
13664/*
13665 * call-seq:
13666 * set_encoding(ext_enc) -> self
13667 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13668 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13669 *
13670 * See {Encodings}[rdoc-ref:File@Encodings].
13671 *
13672 * Argument +ext_enc+, if given, must be an Encoding object
13673 * or a String with the encoding name;
13674 * it is assigned as the encoding for the stream.
13675 *
13676 * Argument +int_enc+, if given, must be an Encoding object
13677 * or a String with the encoding name;
13678 * it is assigned as the encoding for the internal string.
13679 *
13680 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13681 * containing two colon-separated encoding names;
13682 * corresponding Encoding objects are assigned as the external
13683 * and internal encodings for the stream.
13684 *
13685 * If the external encoding of a string is binary/ASCII-8BIT,
13686 * the internal encoding of the string is set to nil, since no
13687 * transcoding is needed.
13688 *
13689 * Optional keyword arguments +enc_opts+ specify
13690 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13691 *
13692 */
13693
13694static VALUE
13695rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13696{
13697 rb_io_t *fptr;
13698 VALUE v1, v2, opt;
13699
13700 if (!RB_TYPE_P(io, T_FILE)) {
13701 return forward(io, id_set_encoding, argc, argv);
13702 }
13703
13704 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13705 GetOpenFile(io, fptr);
13706 io_encoding_set(fptr, v1, v2, opt);
13707 return io;
13708}
13709
13710void
13711rb_stdio_set_default_encoding(void)
13712{
13713 VALUE val = Qnil;
13714
13715#ifdef _WIN32
13716 if (isatty(fileno(stdin))) {
13717 rb_encoding *external = rb_locale_encoding();
13718 rb_encoding *internal = rb_default_internal_encoding();
13719 if (!internal) internal = rb_default_external_encoding();
13720 io_encoding_set(RFILE(rb_stdin)->fptr,
13721 rb_enc_from_encoding(external),
13722 rb_enc_from_encoding(internal),
13723 Qnil);
13724 }
13725 else
13726#endif
13727 rb_io_set_encoding(1, &val, rb_stdin);
13728 rb_io_set_encoding(1, &val, rb_stdout);
13729 rb_io_set_encoding(1, &val, rb_stderr);
13730}
13731
13732static inline int
13733global_argf_p(VALUE arg)
13734{
13735 return arg == argf;
13736}
13737
13738typedef VALUE (*argf_encoding_func)(VALUE io);
13739
13740static VALUE
13741argf_encoding(VALUE argf, argf_encoding_func func)
13742{
13743 if (!RTEST(ARGF.current_file)) {
13744 return rb_enc_default_external();
13745 }
13746 return func(rb_io_check_io(ARGF.current_file));
13747}
13748
13749/*
13750 * call-seq:
13751 * ARGF.external_encoding -> encoding
13752 *
13753 * Returns the external encoding for files read from ARGF as an Encoding
13754 * object. The external encoding is the encoding of the text as stored in a
13755 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13756 * represent this text within Ruby.
13757 *
13758 * To set the external encoding use ARGF.set_encoding.
13759 *
13760 * For example:
13761 *
13762 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13763 *
13764 */
13765static VALUE
13766argf_external_encoding(VALUE argf)
13767{
13768 return argf_encoding(argf, rb_io_external_encoding);
13769}
13770
13771/*
13772 * call-seq:
13773 * ARGF.internal_encoding -> encoding
13774 *
13775 * Returns the internal encoding for strings read from ARGF as an
13776 * Encoding object.
13777 *
13778 * If ARGF.set_encoding has been called with two encoding names, the second
13779 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13780 * value is returned. Failing that, if a default external encoding was
13781 * specified on the command-line, that value is used. If the encoding is
13782 * unknown, +nil+ is returned.
13783 */
13784static VALUE
13785argf_internal_encoding(VALUE argf)
13786{
13787 return argf_encoding(argf, rb_io_internal_encoding);
13788}
13789
13790/*
13791 * call-seq:
13792 * ARGF.set_encoding(ext_enc) -> ARGF
13793 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13794 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13795 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13796 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13797 *
13798 * If single argument is specified, strings read from ARGF are tagged with
13799 * the encoding specified.
13800 *
13801 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13802 * the read string is converted from the first encoding (external encoding)
13803 * to the second encoding (internal encoding), then tagged with the second
13804 * encoding.
13805 *
13806 * If two arguments are specified, they must be encoding objects or encoding
13807 * names. Again, the first specifies the external encoding; the second
13808 * specifies the internal encoding.
13809 *
13810 * If the external encoding and the internal encoding are specified, the
13811 * optional Hash argument can be used to adjust the conversion process. The
13812 * structure of this hash is explained in the String#encode documentation.
13813 *
13814 * For example:
13815 *
13816 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13817 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13818 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13819 * # to UTF-8.
13820 */
13821static VALUE
13822argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13823{
13824 rb_io_t *fptr;
13825
13826 if (!next_argv()) {
13827 rb_raise(rb_eArgError, "no stream to set encoding");
13828 }
13829 rb_io_set_encoding(argc, argv, ARGF.current_file);
13830 GetOpenFile(ARGF.current_file, fptr);
13831 ARGF.encs = fptr->encs;
13832 RB_OBJ_WRITTEN(argf, Qundef, ARGF.encs.ecopts);
13833 return argf;
13834}
13835
13836/*
13837 * call-seq:
13838 * ARGF.tell -> Integer
13839 * ARGF.pos -> Integer
13840 *
13841 * Returns the current offset (in bytes) of the current file in ARGF.
13842 *
13843 * ARGF.pos #=> 0
13844 * ARGF.gets #=> "This is line one\n"
13845 * ARGF.pos #=> 17
13846 *
13847 */
13848static VALUE
13849argf_tell(VALUE argf)
13850{
13851 if (!next_argv()) {
13852 rb_raise(rb_eArgError, "no stream to tell");
13853 }
13854 ARGF_FORWARD(0, 0);
13855 return rb_io_tell(ARGF.current_file);
13856}
13857
13858/*
13859 * call-seq:
13860 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13861 *
13862 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13863 * the value of _whence_. See IO#seek for further details.
13864 */
13865static VALUE
13866argf_seek_m(int argc, VALUE *argv, VALUE argf)
13867{
13868 if (!next_argv()) {
13869 rb_raise(rb_eArgError, "no stream to seek");
13870 }
13871 ARGF_FORWARD(argc, argv);
13872 return rb_io_seek_m(argc, argv, ARGF.current_file);
13873}
13874
13875/*
13876 * call-seq:
13877 * ARGF.pos = position -> Integer
13878 *
13879 * Seeks to the position given by _position_ (in bytes) in ARGF.
13880 *
13881 * For example:
13882 *
13883 * ARGF.pos = 17
13884 * ARGF.gets #=> "This is line two\n"
13885 */
13886static VALUE
13887argf_set_pos(VALUE argf, VALUE offset)
13888{
13889 if (!next_argv()) {
13890 rb_raise(rb_eArgError, "no stream to set position");
13891 }
13892 ARGF_FORWARD(1, &offset);
13893 return rb_io_set_pos(ARGF.current_file, offset);
13894}
13895
13896/*
13897 * call-seq:
13898 * ARGF.rewind -> 0
13899 *
13900 * Positions the current file to the beginning of input, resetting
13901 * ARGF.lineno to zero.
13902 *
13903 * ARGF.readline #=> "This is line one\n"
13904 * ARGF.rewind #=> 0
13905 * ARGF.lineno #=> 0
13906 * ARGF.readline #=> "This is line one\n"
13907 */
13908static VALUE
13909argf_rewind(VALUE argf)
13910{
13911 VALUE ret;
13912 int old_lineno;
13913
13914 if (!next_argv()) {
13915 rb_raise(rb_eArgError, "no stream to rewind");
13916 }
13917 ARGF_FORWARD(0, 0);
13918 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13919 ret = rb_io_rewind(ARGF.current_file);
13920 if (!global_argf_p(argf)) {
13921 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13922 }
13923 return ret;
13924}
13925
13926/*
13927 * call-seq:
13928 * ARGF.fileno -> integer
13929 * ARGF.to_i -> integer
13930 *
13931 * Returns an integer representing the numeric file descriptor for
13932 * the current file. Raises an ArgumentError if there isn't a current file.
13933 *
13934 * ARGF.fileno #=> 3
13935 */
13936static VALUE
13937argf_fileno(VALUE argf)
13938{
13939 if (!next_argv()) {
13940 rb_raise(rb_eArgError, "no stream");
13941 }
13942 ARGF_FORWARD(0, 0);
13943 return rb_io_fileno(ARGF.current_file);
13944}
13945
13946/*
13947 * call-seq:
13948 * ARGF.to_io -> IO
13949 *
13950 * Returns an IO object representing the current file. This will be a
13951 * File object unless the current file is a stream such as STDIN.
13952 *
13953 * For example:
13954 *
13955 * ARGF.to_io #=> #<File:glark.txt>
13956 * ARGF.to_io #=> #<IO:<STDIN>>
13957 */
13958static VALUE
13959argf_to_io(VALUE argf)
13960{
13961 next_argv();
13962 ARGF_FORWARD(0, 0);
13963 return ARGF.current_file;
13964}
13965
13966/*
13967 * call-seq:
13968 * ARGF.eof? -> true or false
13969 * ARGF.eof -> true or false
13970 *
13971 * Returns true if the current file in ARGF is at end of file, i.e. it has
13972 * no data to read. The stream must be opened for reading or an IOError
13973 * will be raised.
13974 *
13975 * $ echo "eof" | ruby argf.rb
13976 *
13977 * ARGF.eof? #=> false
13978 * 3.times { ARGF.readchar }
13979 * ARGF.eof? #=> false
13980 * ARGF.readchar #=> "\n"
13981 * ARGF.eof? #=> true
13982 */
13983
13984static VALUE
13985argf_eof(VALUE argf)
13986{
13987 next_argv();
13988 if (RTEST(ARGF.current_file)) {
13989 if (ARGF.init_p == 0) return Qtrue;
13990 next_argv();
13991 ARGF_FORWARD(0, 0);
13992 if (rb_io_eof(ARGF.current_file)) {
13993 return Qtrue;
13994 }
13995 }
13996 return Qfalse;
13997}
13998
13999/*
14000 * call-seq:
14001 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
14002 *
14003 * Reads _length_ bytes from ARGF. The files named on the command line
14004 * are concatenated and treated as a single file by this method, so when
14005 * called without arguments the contents of this pseudo file are returned in
14006 * their entirety.
14007 *
14008 * _length_ must be a non-negative integer or +nil+.
14009 *
14010 * If _length_ is a positive integer, +read+ tries to read
14011 * _length_ bytes without any conversion (binary mode).
14012 * It returns +nil+ if an EOF is encountered before anything can be read.
14013 * Fewer than _length_ bytes are returned if an EOF is encountered during
14014 * the read.
14015 * In the case of an integer _length_, the resulting string is always
14016 * in ASCII-8BIT encoding.
14017 *
14018 * If _length_ is omitted or is +nil+, it reads until EOF
14019 * and the encoding conversion is applied, if applicable.
14020 * A string is returned even if EOF is encountered before any data is read.
14021 *
14022 * If _length_ is zero, it returns an empty string (<code>""</code>).
14023 *
14024 * If the optional _outbuf_ argument is present,
14025 * it must reference a String, which will receive the data.
14026 * The _outbuf_ will contain only the received data after the method call
14027 * even if it is not empty at the beginning.
14028 *
14029 * For example:
14030 *
14031 * $ echo "small" > small.txt
14032 * $ echo "large" > large.txt
14033 * $ ./glark.rb small.txt large.txt
14034 *
14035 * ARGF.read #=> "small\nlarge"
14036 * ARGF.read(200) #=> "small\nlarge"
14037 * ARGF.read(2) #=> "sm"
14038 * ARGF.read(0) #=> ""
14039 *
14040 * Note that this method behaves like the fread() function in C.
14041 * This means it retries to invoke read(2) system calls to read data
14042 * with the specified length.
14043 * If you need the behavior like a single read(2) system call,
14044 * consider ARGF#readpartial or ARGF#read_nonblock.
14045 */
14046
14047static VALUE
14048argf_read(int argc, VALUE *argv, VALUE argf)
14049{
14050 VALUE tmp, str, length;
14051 long len = 0;
14052
14053 rb_scan_args(argc, argv, "02", &length, &str);
14054 if (!NIL_P(length)) {
14055 len = NUM2LONG(argv[0]);
14056 }
14057 if (!NIL_P(str)) {
14058 StringValue(str);
14059 rb_str_resize(str,0);
14060 argv[1] = Qnil;
14061 }
14062
14063 retry:
14064 if (!next_argv()) {
14065 return str;
14066 }
14067 if (ARGF_GENERIC_INPUT_P()) {
14068 tmp = argf_forward(argc, argv, argf);
14069 }
14070 else {
14071 tmp = io_read(argc, argv, ARGF.current_file);
14072 }
14073 if (NIL_P(str)) str = tmp;
14074 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
14075 if (NIL_P(tmp) || NIL_P(length)) {
14076 if (ARGF.next_p != -1) {
14077 argf_close(argf);
14078 ARGF.next_p = 1;
14079 goto retry;
14080 }
14081 }
14082 else if (argc >= 1) {
14083 long slen = RSTRING_LEN(str);
14084 if (slen < len) {
14085 argv[0] = LONG2NUM(len - slen);
14086 goto retry;
14087 }
14088 }
14089 return str;
14090}
14091
14093 int argc;
14094 VALUE *argv;
14095 VALUE argf;
14096};
14097
14098static VALUE
14099argf_forward_call(VALUE arg)
14100{
14101 struct argf_call_arg *p = (struct argf_call_arg *)arg;
14102 argf_forward(p->argc, p->argv, p->argf);
14103 return Qnil;
14104}
14105
14106static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
14107 int nonblock);
14108
14109/*
14110 * call-seq:
14111 * ARGF.readpartial(maxlen) -> string
14112 * ARGF.readpartial(maxlen, outbuf) -> outbuf
14113 *
14114 * Reads at most _maxlen_ bytes from the ARGF stream.
14115 *
14116 * If the optional _outbuf_ argument is present,
14117 * it must reference a String, which will receive the data.
14118 * The _outbuf_ will contain only the received data after the method call
14119 * even if it is not empty at the beginning.
14120 *
14121 * It raises EOFError on end of ARGF stream.
14122 * Since ARGF stream is a concatenation of multiple files,
14123 * internally EOF is occur for each file.
14124 * ARGF.readpartial returns empty strings for EOFs except the last one and
14125 * raises EOFError for the last one.
14126 *
14127 */
14128
14129static VALUE
14130argf_readpartial(int argc, VALUE *argv, VALUE argf)
14131{
14132 return argf_getpartial(argc, argv, argf, Qnil, 0);
14133}
14134
14135/*
14136 * call-seq:
14137 * ARGF.read_nonblock(maxlen[, options]) -> string
14138 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14139 *
14140 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14141 */
14142
14143static VALUE
14144argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14145{
14146 VALUE opts;
14147
14148 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14149
14150 if (!NIL_P(opts))
14151 argc--;
14152
14153 return argf_getpartial(argc, argv, argf, opts, 1);
14154}
14155
14156static VALUE
14157argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14158{
14159 VALUE tmp, str, length;
14160 int no_exception;
14161
14162 rb_scan_args(argc, argv, "11", &length, &str);
14163 if (!NIL_P(str)) {
14164 StringValue(str);
14165 argv[1] = str;
14166 }
14167 no_exception = no_exception_p(opts);
14168
14169 if (!next_argv()) {
14170 if (!NIL_P(str)) {
14171 rb_str_resize(str, 0);
14172 }
14173 rb_eof_error();
14174 }
14175 if (ARGF_GENERIC_INPUT_P()) {
14176 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14177 struct argf_call_arg arg;
14178 arg.argc = argc;
14179 arg.argv = argv;
14180 arg.argf = argf;
14181 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14182 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14183 }
14184 else {
14185 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14186 }
14187 if (NIL_P(tmp)) {
14188 if (ARGF.next_p == -1) {
14189 return io_nonblock_eof(no_exception);
14190 }
14191 argf_close(argf);
14192 ARGF.next_p = 1;
14193 if (RARRAY_LEN(ARGF.argv) == 0) {
14194 return io_nonblock_eof(no_exception);
14195 }
14196 if (NIL_P(str))
14197 str = rb_str_new(NULL, 0);
14198 return str;
14199 }
14200 return tmp;
14201}
14202
14203/*
14204 * call-seq:
14205 * ARGF.getc -> String or nil
14206 *
14207 * Reads the next character from ARGF and returns it as a String. Returns
14208 * +nil+ at the end of the stream.
14209 *
14210 * ARGF treats the files named on the command line as a single file created
14211 * by concatenating their contents. After returning the last character of the
14212 * first file, it returns the first character of the second file, and so on.
14213 *
14214 * For example:
14215 *
14216 * $ echo "foo" > file
14217 * $ ruby argf.rb file
14218 *
14219 * ARGF.getc #=> "f"
14220 * ARGF.getc #=> "o"
14221 * ARGF.getc #=> "o"
14222 * ARGF.getc #=> "\n"
14223 * ARGF.getc #=> nil
14224 * ARGF.getc #=> nil
14225 */
14226static VALUE
14227argf_getc(VALUE argf)
14228{
14229 VALUE ch;
14230
14231 retry:
14232 if (!next_argv()) return Qnil;
14233 if (ARGF_GENERIC_INPUT_P()) {
14234 ch = forward_current(rb_intern("getc"), 0, 0);
14235 }
14236 else {
14237 ch = rb_io_getc(ARGF.current_file);
14238 }
14239 if (NIL_P(ch) && ARGF.next_p != -1) {
14240 argf_close(argf);
14241 ARGF.next_p = 1;
14242 goto retry;
14243 }
14244
14245 return ch;
14246}
14247
14248/*
14249 * call-seq:
14250 * ARGF.getbyte -> Integer or nil
14251 *
14252 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14253 * the end of the stream.
14254 *
14255 * For example:
14256 *
14257 * $ echo "foo" > file
14258 * $ ruby argf.rb file
14259 *
14260 * ARGF.getbyte #=> 102
14261 * ARGF.getbyte #=> 111
14262 * ARGF.getbyte #=> 111
14263 * ARGF.getbyte #=> 10
14264 * ARGF.getbyte #=> nil
14265 */
14266static VALUE
14267argf_getbyte(VALUE argf)
14268{
14269 VALUE ch;
14270
14271 retry:
14272 if (!next_argv()) return Qnil;
14273 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14274 ch = forward_current(rb_intern("getbyte"), 0, 0);
14275 }
14276 else {
14277 ch = rb_io_getbyte(ARGF.current_file);
14278 }
14279 if (NIL_P(ch) && ARGF.next_p != -1) {
14280 argf_close(argf);
14281 ARGF.next_p = 1;
14282 goto retry;
14283 }
14284
14285 return ch;
14286}
14287
14288/*
14289 * call-seq:
14290 * ARGF.readchar -> String or nil
14291 *
14292 * Reads the next character from ARGF and returns it as a String. Raises
14293 * an EOFError after the last character of the last file has been read.
14294 *
14295 * For example:
14296 *
14297 * $ echo "foo" > file
14298 * $ ruby argf.rb file
14299 *
14300 * ARGF.readchar #=> "f"
14301 * ARGF.readchar #=> "o"
14302 * ARGF.readchar #=> "o"
14303 * ARGF.readchar #=> "\n"
14304 * ARGF.readchar #=> end of file reached (EOFError)
14305 */
14306static VALUE
14307argf_readchar(VALUE argf)
14308{
14309 VALUE ch;
14310
14311 retry:
14312 if (!next_argv()) rb_eof_error();
14313 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14314 ch = forward_current(rb_intern("getc"), 0, 0);
14315 }
14316 else {
14317 ch = rb_io_getc(ARGF.current_file);
14318 }
14319 if (NIL_P(ch) && ARGF.next_p != -1) {
14320 argf_close(argf);
14321 ARGF.next_p = 1;
14322 goto retry;
14323 }
14324
14325 return ch;
14326}
14327
14328/*
14329 * call-seq:
14330 * ARGF.readbyte -> Integer
14331 *
14332 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14333 * an EOFError after the last byte of the last file has been read.
14334 *
14335 * For example:
14336 *
14337 * $ echo "foo" > file
14338 * $ ruby argf.rb file
14339 *
14340 * ARGF.readbyte #=> 102
14341 * ARGF.readbyte #=> 111
14342 * ARGF.readbyte #=> 111
14343 * ARGF.readbyte #=> 10
14344 * ARGF.readbyte #=> end of file reached (EOFError)
14345 */
14346static VALUE
14347argf_readbyte(VALUE argf)
14348{
14349 VALUE c;
14350
14351 NEXT_ARGF_FORWARD(0, 0);
14352 c = argf_getbyte(argf);
14353 if (NIL_P(c)) {
14354 rb_eof_error();
14355 }
14356 return c;
14357}
14358
14359#define FOREACH_ARGF() while (next_argv())
14360
14361static VALUE
14362argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14363{
14364 const VALUE current = ARGF.current_file;
14365 rb_yield_values2(argc, argv);
14366 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14368 }
14369 return Qnil;
14370}
14371
14372#define ARGF_block_call(mid, argc, argv, func, argf) \
14373 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14374 func, argf, rb_keyword_given_p())
14375
14376static void
14377argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14378{
14379 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14380 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14381}
14382
14383static VALUE
14384argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14385{
14386 if (!global_argf_p(argf)) {
14387 ARGF.last_lineno = ++ARGF.lineno;
14388 }
14389 return argf_block_call_i(i, argf, argc, argv, blockarg);
14390}
14391
14392static void
14393argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14394{
14395 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14396 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14397}
14398
14399/*
14400 * call-seq:
14401 * ARGF.each(sep=$/) {|line| block } -> ARGF
14402 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14403 * ARGF.each(...) -> an_enumerator
14404 *
14405 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14406 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14407 * ARGF.each_line(...) -> an_enumerator
14408 *
14409 * Returns an enumerator which iterates over each line (separated by _sep_,
14410 * which defaults to your platform's newline character) of each file in
14411 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14412 * block, otherwise an enumerator is returned.
14413 * The optional _limit_ argument is an Integer specifying the maximum
14414 * length of each line; longer lines will be split according to this limit.
14415 *
14416 * This method allows you to treat the files supplied on the command line as
14417 * a single file consisting of the concatenation of each named file. After
14418 * the last line of the first file has been returned, the first line of the
14419 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14420 * used to determine the filename of the current line and line number of the
14421 * whole input, respectively.
14422 *
14423 * For example, the following code prints out each line of each named file
14424 * prefixed with its line number, displaying the filename once per file:
14425 *
14426 * ARGF.each_line do |line|
14427 * puts ARGF.filename if ARGF.file.lineno == 1
14428 * puts "#{ARGF.file.lineno}: #{line}"
14429 * end
14430 *
14431 * While the following code prints only the first file's name at first, and
14432 * the contents with line number counted through all named files.
14433 *
14434 * ARGF.each_line do |line|
14435 * puts ARGF.filename if ARGF.lineno == 1
14436 * puts "#{ARGF.lineno}: #{line}"
14437 * end
14438 */
14439static VALUE
14440argf_each_line(int argc, VALUE *argv, VALUE argf)
14441{
14442 RETURN_ENUMERATOR(argf, argc, argv);
14443 FOREACH_ARGF() {
14444 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14445 }
14446 return argf;
14447}
14448
14449/*
14450 * call-seq:
14451 * ARGF.each_byte {|byte| block } -> ARGF
14452 * ARGF.each_byte -> an_enumerator
14453 *
14454 * Iterates over each byte of each file in +ARGV+.
14455 * A byte is returned as an Integer in the range 0..255.
14456 *
14457 * This method allows you to treat the files supplied on the command line as
14458 * a single file consisting of the concatenation of each named file. After
14459 * the last byte of the first file has been returned, the first byte of the
14460 * second file is returned. The ARGF.filename method can be used to
14461 * determine the filename of the current byte.
14462 *
14463 * If no block is given, an enumerator is returned instead.
14464 *
14465 * For example:
14466 *
14467 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14468 *
14469 */
14470static VALUE
14471argf_each_byte(VALUE argf)
14472{
14473 RETURN_ENUMERATOR(argf, 0, 0);
14474 FOREACH_ARGF() {
14475 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14476 }
14477 return argf;
14478}
14479
14480/*
14481 * call-seq:
14482 * ARGF.each_char {|char| block } -> ARGF
14483 * ARGF.each_char -> an_enumerator
14484 *
14485 * Iterates over each character of each file in ARGF.
14486 *
14487 * This method allows you to treat the files supplied on the command line as
14488 * a single file consisting of the concatenation of each named file. After
14489 * the last character of the first file has been returned, the first
14490 * character of the second file is returned. The ARGF.filename method can
14491 * be used to determine the name of the file in which the current character
14492 * appears.
14493 *
14494 * If no block is given, an enumerator is returned instead.
14495 */
14496static VALUE
14497argf_each_char(VALUE argf)
14498{
14499 RETURN_ENUMERATOR(argf, 0, 0);
14500 FOREACH_ARGF() {
14501 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14502 }
14503 return argf;
14504}
14505
14506/*
14507 * call-seq:
14508 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14509 * ARGF.each_codepoint -> an_enumerator
14510 *
14511 * Iterates over each codepoint of each file in ARGF.
14512 *
14513 * This method allows you to treat the files supplied on the command line as
14514 * a single file consisting of the concatenation of each named file. After
14515 * the last codepoint of the first file has been returned, the first
14516 * codepoint of the second file is returned. The ARGF.filename method can
14517 * be used to determine the name of the file in which the current codepoint
14518 * appears.
14519 *
14520 * If no block is given, an enumerator is returned instead.
14521 */
14522static VALUE
14523argf_each_codepoint(VALUE argf)
14524{
14525 RETURN_ENUMERATOR(argf, 0, 0);
14526 FOREACH_ARGF() {
14527 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14528 }
14529 return argf;
14530}
14531
14532/*
14533 * call-seq:
14534 * ARGF.filename -> String
14535 * ARGF.path -> String
14536 *
14537 * Returns the current filename. "-" is returned when the current file is
14538 * STDIN.
14539 *
14540 * For example:
14541 *
14542 * $ echo "foo" > foo
14543 * $ echo "bar" > bar
14544 * $ echo "glark" > glark
14545 *
14546 * $ ruby argf.rb foo bar glark
14547 *
14548 * ARGF.filename #=> "foo"
14549 * ARGF.read(5) #=> "foo\nb"
14550 * ARGF.filename #=> "bar"
14551 * ARGF.skip
14552 * ARGF.filename #=> "glark"
14553 */
14554static VALUE
14555argf_filename(VALUE argf)
14556{
14557 next_argv();
14558 return ARGF.filename;
14559}
14560
14561static VALUE
14562argf_filename_getter(ID id, VALUE *var)
14563{
14564 return argf_filename(*var);
14565}
14566
14567/*
14568 * call-seq:
14569 * ARGF.file -> IO or File object
14570 *
14571 * Returns the current file as an IO or File object.
14572 * <code>$stdin</code> is returned when the current file is STDIN.
14573 *
14574 * For example:
14575 *
14576 * $ echo "foo" > foo
14577 * $ echo "bar" > bar
14578 *
14579 * $ ruby argf.rb foo bar
14580 *
14581 * ARGF.file #=> #<File:foo>
14582 * ARGF.read(5) #=> "foo\nb"
14583 * ARGF.file #=> #<File:bar>
14584 */
14585static VALUE
14586argf_file(VALUE argf)
14587{
14588 next_argv();
14589 return ARGF.current_file;
14590}
14591
14592/*
14593 * call-seq:
14594 * ARGF.binmode -> ARGF
14595 *
14596 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14597 * be reset to non-binary mode. This option has the following effects:
14598 *
14599 * * Newline conversion is disabled.
14600 * * Encoding conversion is disabled.
14601 * * Content is treated as ASCII-8BIT.
14602 */
14603static VALUE
14604argf_binmode_m(VALUE argf)
14605{
14606 ARGF.binmode = 1;
14607 next_argv();
14608 ARGF_FORWARD(0, 0);
14609 rb_io_ascii8bit_binmode(ARGF.current_file);
14610 return argf;
14611}
14612
14613/*
14614 * call-seq:
14615 * ARGF.binmode? -> true or false
14616 *
14617 * Returns true if ARGF is being read in binary mode; false otherwise.
14618 * To enable binary mode use ARGF.binmode.
14619 *
14620 * For example:
14621 *
14622 * ARGF.binmode? #=> false
14623 * ARGF.binmode
14624 * ARGF.binmode? #=> true
14625 */
14626static VALUE
14627argf_binmode_p(VALUE argf)
14628{
14629 return RBOOL(ARGF.binmode);
14630}
14631
14632/*
14633 * call-seq:
14634 * ARGF.skip -> ARGF
14635 *
14636 * Sets the current file to the next file in ARGV. If there aren't any more
14637 * files it has no effect.
14638 *
14639 * For example:
14640 *
14641 * $ ruby argf.rb foo bar
14642 * ARGF.filename #=> "foo"
14643 * ARGF.skip
14644 * ARGF.filename #=> "bar"
14645 */
14646static VALUE
14647argf_skip(VALUE argf)
14648{
14649 if (ARGF.init_p && ARGF.next_p == 0) {
14650 argf_close(argf);
14651 ARGF.next_p = 1;
14652 }
14653 return argf;
14654}
14655
14656/*
14657 * call-seq:
14658 * ARGF.close -> ARGF
14659 *
14660 * Closes the current file and skips to the next file in ARGV. If there are
14661 * no more files to open, just closes the current file. STDIN will not be
14662 * closed.
14663 *
14664 * For example:
14665 *
14666 * $ ruby argf.rb foo bar
14667 *
14668 * ARGF.filename #=> "foo"
14669 * ARGF.close
14670 * ARGF.filename #=> "bar"
14671 * ARGF.close
14672 */
14673static VALUE
14674argf_close_m(VALUE argf)
14675{
14676 next_argv();
14677 argf_close(argf);
14678 if (ARGF.next_p != -1) {
14679 ARGF.next_p = 1;
14680 }
14681 ARGF.lineno = 0;
14682 return argf;
14683}
14684
14685/*
14686 * call-seq:
14687 * ARGF.closed? -> true or false
14688 *
14689 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14690 * ARGF.close to actually close the current file.
14691 */
14692static VALUE
14693argf_closed(VALUE argf)
14694{
14695 next_argv();
14696 ARGF_FORWARD(0, 0);
14697 return rb_io_closed_p(ARGF.current_file);
14698}
14699
14700/*
14701 * call-seq:
14702 * ARGF.to_s -> String
14703 *
14704 * Returns "ARGF".
14705 */
14706static VALUE
14707argf_to_s(VALUE argf)
14708{
14709 return rb_str_new2("ARGF");
14710}
14711
14712/*
14713 * call-seq:
14714 * ARGF.inplace_mode -> String
14715 *
14716 * Returns the file extension appended to the names of backup copies of
14717 * modified files under in-place edit mode. This value can be set using
14718 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14719 */
14720static VALUE
14721argf_inplace_mode_get(VALUE argf)
14722{
14723 if (!ARGF.inplace) return Qnil;
14724 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14725 return rb_str_dup(ARGF.inplace);
14726}
14727
14728static VALUE
14729opt_i_get(ID id, VALUE *var)
14730{
14731 return argf_inplace_mode_get(*var);
14732}
14733
14734/*
14735 * call-seq:
14736 * ARGF.inplace_mode = ext -> ARGF
14737 *
14738 * Sets the filename extension for in-place editing mode to the given String.
14739 * The backup copy of each file being edited has this value appended to its
14740 * filename.
14741 *
14742 * For example:
14743 *
14744 * $ ruby argf.rb file.txt
14745 *
14746 * ARGF.inplace_mode = '.bak'
14747 * ARGF.each_line do |line|
14748 * print line.sub("foo","bar")
14749 * end
14750 *
14751 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14752 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14753 * "bar".
14754 */
14755static VALUE
14756argf_inplace_mode_set(VALUE argf, VALUE val)
14757{
14758 if (!RTEST(val)) {
14759 ARGF.inplace = Qfalse;
14760 }
14761 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14762 ARGF.inplace = Qnil;
14763 }
14764 else {
14765 ARGF_SET(inplace, rb_str_new_frozen(val));
14766 }
14767 return argf;
14768}
14769
14770static void
14771opt_i_set(VALUE val, ID id, VALUE *var)
14772{
14773 argf_inplace_mode_set(*var, val);
14774}
14775
14776void
14777ruby_set_inplace_mode(const char *suffix)
14778{
14779 ARGF_SET(inplace, !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix)));
14780}
14781
14782/*
14783 * call-seq:
14784 * ARGF.argv -> ARGV
14785 *
14786 * Returns the +ARGV+ array, which contains the arguments passed to your
14787 * script, one per element.
14788 *
14789 * For example:
14790 *
14791 * $ ruby argf.rb -v glark.txt
14792 *
14793 * ARGF.argv #=> ["-v", "glark.txt"]
14794 *
14795 */
14796static VALUE
14797argf_argv(VALUE argf)
14798{
14799 return ARGF.argv;
14800}
14801
14802static VALUE
14803argf_argv_getter(ID id, VALUE *var)
14804{
14805 return argf_argv(*var);
14806}
14807
14808VALUE
14810{
14811 return ARGF.argv;
14812}
14813
14814/*
14815 * call-seq:
14816 * ARGF.to_write_io -> io
14817 *
14818 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14819 * enabled.
14820 */
14821static VALUE
14822argf_write_io(VALUE argf)
14823{
14824 if (!RTEST(ARGF.current_file)) {
14825 rb_raise(rb_eIOError, "not opened for writing");
14826 }
14827 return GetWriteIO(ARGF.current_file);
14828}
14829
14830/*
14831 * call-seq:
14832 * ARGF.write(*objects) -> integer
14833 *
14834 * Writes each of the given +objects+ if inplace mode.
14835 */
14836static VALUE
14837argf_write(int argc, VALUE *argv, VALUE argf)
14838{
14839 return rb_io_writev(argf_write_io(argf), argc, argv);
14840}
14841
14842void
14843rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14844{
14845 rb_readwrite_syserr_fail(waiting, errno, mesg);
14846}
14847
14848void
14849rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14850{
14851 VALUE arg, c = Qnil;
14852 arg = mesg ? rb_str_new2(mesg) : Qnil;
14853 switch (waiting) {
14854 case RB_IO_WAIT_WRITABLE:
14855 switch (n) {
14856 case EAGAIN:
14857 c = rb_eEAGAINWaitWritable;
14858 break;
14859#if EAGAIN != EWOULDBLOCK
14860 case EWOULDBLOCK:
14861 c = rb_eEWOULDBLOCKWaitWritable;
14862 break;
14863#endif
14864 case EINPROGRESS:
14865 c = rb_eEINPROGRESSWaitWritable;
14866 break;
14867 default:
14869 }
14870 break;
14871 case RB_IO_WAIT_READABLE:
14872 switch (n) {
14873 case EAGAIN:
14874 c = rb_eEAGAINWaitReadable;
14875 break;
14876#if EAGAIN != EWOULDBLOCK
14877 case EWOULDBLOCK:
14878 c = rb_eEWOULDBLOCKWaitReadable;
14879 break;
14880#endif
14881 case EINPROGRESS:
14882 c = rb_eEINPROGRESSWaitReadable;
14883 break;
14884 default:
14886 }
14887 break;
14888 default:
14889 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14890 }
14892}
14893
14894static VALUE
14895get_LAST_READ_LINE(ID _x, VALUE *_y)
14896{
14897 return rb_lastline_get();
14898}
14899
14900static void
14901set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14902{
14903 rb_lastline_set(val);
14904}
14905
14906/*
14907 * Document-class: IOError
14908 *
14909 * Raised when an IO operation fails.
14910 *
14911 * File.open("/etc/hosts") {|f| f << "example"}
14912 * #=> IOError: not opened for writing
14913 *
14914 * File.open("/etc/hosts") {|f| f.close; f.read }
14915 * #=> IOError: closed stream
14916 *
14917 * Note that some IO failures raise <code>SystemCallError</code>s
14918 * and these are not subclasses of IOError:
14919 *
14920 * File.open("does/not/exist")
14921 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14922 */
14923
14924/*
14925 * Document-class: EOFError
14926 *
14927 * Raised by some IO operations when reaching the end of file. Many IO
14928 * methods exist in two forms,
14929 *
14930 * one that returns +nil+ when the end of file is reached, the other
14931 * raises EOFError.
14932 *
14933 * EOFError is a subclass of IOError.
14934 *
14935 * file = File.open("/etc/hosts")
14936 * file.read
14937 * file.gets #=> nil
14938 * file.readline #=> EOFError: end of file reached
14939 * file.close
14940 */
14941
14942/*
14943 * Document-class: ARGF
14944 *
14945 * == \ARGF and +ARGV+
14946 *
14947 * The \ARGF object works with the array at global variable +ARGV+
14948 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14949 *
14950 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14951 *
14952 * Initially, it contains the command-line arguments and options
14953 * that are passed to the Ruby program;
14954 * the program can modify that array as it likes.
14955 *
14956 * - **ARGF** may be thought of as the <b>argument files</b> object.
14957 *
14958 * It can access file streams and/or the <tt>$stdin</tt> stream,
14959 * based on what it finds in +ARGV+.
14960 * This provides a convenient way for the command line
14961 * to specify streams for a Ruby program to read.
14962 *
14963 * == Reading
14964 *
14965 * \ARGF may read from _source_ streams,
14966 * which at any particular time are determined by the content of +ARGV+.
14967 *
14968 * === Simplest Case
14969 *
14970 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14971 * the source is <tt>$stdin</tt>:
14972 *
14973 * - \File +t.rb+:
14974 *
14975 * p ['ARGV', ARGV]
14976 * p ['ARGF.read', ARGF.read]
14977 *
14978 * - Commands and outputs
14979 * (see below for the content of files +foo.txt+ and +bar.txt+):
14980 *
14981 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14982 * ["ARGV", []]
14983 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14984 *
14985 * $ cat foo.txt bar.txt | ruby t.rb
14986 * ["ARGV", []]
14987 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14988 *
14989 * === About the Examples
14990 *
14991 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14992 *
14993 * $ cat foo.txt
14994 * Foo 0
14995 * Foo 1
14996 * $ cat bar.txt
14997 * Bar 0
14998 * Bar 1
14999 * Bar 2
15000 * Bar 3
15001 *
15002 * === Sources in +ARGV+
15003 *
15004 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
15005 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
15006 * the sources are found in +ARGV+.
15007 *
15008 * \ARGF assumes that each element in array +ARGV+ is a potential source,
15009 * and is one of:
15010 *
15011 * - The string path to a file that may be opened as a stream.
15012 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
15013 *
15014 * Each element that is _not_ one of these
15015 * should be removed from +ARGV+ before \ARGF accesses that source.
15016 *
15017 * In the following example:
15018 *
15019 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
15020 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
15021 *
15022 * Example:
15023 *
15024 * - \File +t.rb+:
15025 *
15026 * # Print arguments (and options, if any) found on command line.
15027 * p ['ARGV', ARGV]
15028 *
15029 * - Command and output:
15030 *
15031 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
15032 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
15033 *
15034 * \ARGF's stream access considers the elements of +ARGV+, left to right:
15035 *
15036 * - \File +t.rb+:
15037 *
15038 * p "ARGV: #{ARGV}"
15039 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
15040 *
15041 * - Command and output:
15042 *
15043 * $ ruby t.rb foo.txt bar.txt
15044 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15045 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15046 *
15047 * Because the value at +ARGV+ is an ordinary array,
15048 * you can manipulate it to control which sources \ARGF considers:
15049 *
15050 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
15051 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
15052 *
15053 * Each element in +ARGV+ is removed when its corresponding source is accessed;
15054 * when all sources have been accessed, the array is empty:
15055 *
15056 * - \File +t.rb+:
15057 *
15058 * until ARGV.empty? && ARGF.eof?
15059 * p "ARGV: #{ARGV}"
15060 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
15061 * end
15062 *
15063 * - Command and output:
15064 *
15065 * $ ruby t.rb foo.txt bar.txt
15066 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15067 * "Line: Foo 0\n"
15068 * "ARGV: [\"bar.txt\"]"
15069 * "Line: Foo 1\n"
15070 * "ARGV: [\"bar.txt\"]"
15071 * "Line: Bar 0\n"
15072 * "ARGV: []"
15073 * "Line: Bar 1\n"
15074 * "ARGV: []"
15075 * "Line: Bar 2\n"
15076 * "ARGV: []"
15077 * "Line: Bar 3\n"
15078 *
15079 * ==== Filepaths in +ARGV+
15080 *
15081 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
15082 *
15083 * This program prints what it reads from files at the paths specified
15084 * on the command line:
15085 *
15086 * - \File +t.rb+:
15087 *
15088 * p ['ARGV', ARGV]
15089 * # Read and print all content from the specified sources.
15090 * p ['ARGF.read', ARGF.read]
15091 *
15092 * - Command and output:
15093 *
15094 * $ ruby t.rb foo.txt bar.txt
15095 * ["ARGV", [foo.txt, bar.txt]
15096 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
15097 *
15098 * ==== Specifying <tt>$stdin</tt> in +ARGV+
15099 *
15100 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
15101 *
15102 * - \File +t.rb+:
15103 *
15104 * p ['ARGV', ARGV]
15105 * p ['ARGF.read', ARGF.read]
15106 *
15107 * - Command and output:
15108 *
15109 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
15110 * ["ARGV", ["-"]]
15111 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15112 *
15113 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored.
15114 *
15115 * - Command and output:
15116 *
15117 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
15118 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15119 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15120 *
15121 * ==== Mixtures and Repetitions in +ARGV+
15122 *
15123 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
15124 * and character <tt>'-'</tt>, including repetitions.
15125 *
15126 * ==== Modifications to +ARGV+
15127 *
15128 * The running Ruby program may make any modifications to the +ARGV+ array;
15129 * the current value of +ARGV+ affects \ARGF reading.
15130 *
15131 * ==== Empty +ARGV+
15132 *
15133 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15134 * or raises an exception, depending on the specific method.
15135 *
15136 * === More Read Methods
15137 *
15138 * As seen above, method ARGF#read reads the content of all sources
15139 * into a single string.
15140 * Other \ARGF methods provide other ways to access that content;
15141 * these include:
15142 *
15143 * - Byte access: #each_byte, #getbyte, #readbyte.
15144 * - Character access: #each_char, #getc, #readchar.
15145 * - Codepoint access: #each_codepoint.
15146 * - Line access: #each_line, #gets, #readline, #readlines.
15147 * - Source access: #read, #read_nonblock, #readpartial.
15148 *
15149 * === About \Enumerable
15150 *
15151 * \ARGF includes module Enumerable.
15152 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15153 *
15154 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15155 * _not_ from +ARGV+;
15156 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15157 * not an array of the strings from +ARGV+:
15158 *
15159 * - \File +t.rb+:
15160 *
15161 * p ['ARGV', ARGV]
15162 * p ['ARGF.entries', ARGF.entries]
15163 *
15164 * - Command and output:
15165 *
15166 * $ ruby t.rb foo.txt bar.txt
15167 * ["ARGV", ["foo.txt", "bar.txt"]]
15168 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15169 *
15170 * == Writing
15171 *
15172 * If <i>inplace mode</i> is in effect,
15173 * \ARGF may write to target streams,
15174 * which at any particular time are determined by the content of ARGV.
15175 *
15176 * Methods about inplace mode:
15177 *
15178 * - #inplace_mode
15179 * - #inplace_mode=
15180 * - #to_write_io
15181 *
15182 * Methods for writing:
15183 *
15184 * - #print
15185 * - #printf
15186 * - #putc
15187 * - #puts
15188 * - #write
15189 *
15190 */
15191
15192/*
15193 * An instance of class \IO (commonly called a _stream_)
15194 * represents an input/output stream in the underlying operating system.
15195 * Class \IO is the basis for input and output in Ruby.
15196 *
15197 * Class File is the only class in the Ruby core that is a subclass of \IO.
15198 * Some classes in the Ruby standard library are also subclasses of \IO;
15199 * these include TCPSocket and UDPSocket.
15200 *
15201 * The global constant ARGF (also accessible as <tt>$<</tt>)
15202 * provides an IO-like stream that allows access to all file paths
15203 * found in ARGV (or found in STDIN if ARGV is empty).
15204 * ARGF is not itself a subclass of \IO.
15205 *
15206 * Class StringIO provides an IO-like stream that handles a String.
15207 * StringIO is not itself a subclass of \IO.
15208 *
15209 * Important objects based on \IO include:
15210 *
15211 * - $stdin.
15212 * - $stdout.
15213 * - $stderr.
15214 * - Instances of class File.
15215 *
15216 * An instance of \IO may be created using:
15217 *
15218 * - IO.new: returns a new \IO object for the given integer file descriptor.
15219 * - IO.open: passes a new \IO object to the given block.
15220 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15221 * of a newly-launched subprocess.
15222 * - Kernel#open: Returns a new \IO object connected to a given source:
15223 * stream, file, or subprocess.
15224 *
15225 * Like a File stream, an \IO stream has:
15226 *
15227 * - A read/write mode, which may be read-only, write-only, or read/write;
15228 * see {Read/Write Mode}[rdoc-ref:File@ReadWrite+Mode].
15229 * - A data mode, which may be text-only or binary;
15230 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15231 * - Internal and external encodings;
15232 * see {Encodings}[rdoc-ref:File@Encodings].
15233 *
15234 * And like other \IO streams, it has:
15235 *
15236 * - A position, which determines where in the stream the next
15237 * read or write is to occur;
15238 * see {Position}[rdoc-ref:IO@Position].
15239 * - A line number, which is a special, line-oriented, "position"
15240 * (different from the position mentioned above);
15241 * see {Line Number}[rdoc-ref:IO@Line+Number].
15242 *
15243 * == Extension <tt>io/console</tt>
15244 *
15245 * Extension <tt>io/console</tt> provides numerous methods
15246 * for interacting with the console;
15247 * requiring it adds numerous methods to class \IO.
15248 *
15249 * == Example Files
15250 *
15251 * Many examples here use these variables:
15252 *
15253 * :include: doc/examples/files.rdoc
15254 *
15255 * == Open Options
15256 *
15257 * A number of \IO methods accept optional keyword arguments
15258 * that determine how a new stream is to be opened:
15259 *
15260 * - +:mode+: Stream mode.
15261 * - +:flags+: Integer file open flags;
15262 * If +mode+ is also given, the two are bitwise-ORed.
15263 * - +:external_encoding+: External encoding for the stream.
15264 * - +:internal_encoding+: Internal encoding for the stream.
15265 * <tt>'-'</tt> is a synonym for the default internal encoding.
15266 * If the value is +nil+ no conversion occurs.
15267 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15268 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15269 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15270 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15271 * when the stream closes; otherwise it remains open.
15272 * - +:path+: If a string value is provided, it is used in #inspect and is available as
15273 * #path method.
15274 *
15275 * Also available are the options offered in String#encode,
15276 * which may control conversion between external and internal encoding.
15277 *
15278 * == Basic \IO
15279 *
15280 * You can perform basic stream \IO with these methods,
15281 * which typically operate on multi-byte strings:
15282 *
15283 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15284 * - IO#write: Writes zero or more strings to the stream;
15285 * each given object that is not already a string is converted via +to_s+.
15286 *
15287 * === Position
15288 *
15289 * An \IO stream has a nonnegative integer _position_,
15290 * which is the byte offset at which the next read or write is to occur.
15291 * A new stream has position zero (and line number zero);
15292 * method +rewind+ resets the position (and line number) to zero.
15293 *
15294 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15295 * Encoding::Converter instances used for that \IO.
15296 *
15297 * The relevant methods:
15298 *
15299 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15300 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15301 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15302 * relative to a given position +whence+
15303 * (indicating the beginning, end, or current position).
15304 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15305 *
15306 * === Open and Closed Streams
15307 *
15308 * A new \IO stream may be open for reading, open for writing, or both.
15309 *
15310 * A stream is automatically closed when claimed by the garbage collector.
15311 *
15312 * Attempted reading or writing on a closed stream raises an exception.
15313 *
15314 * The relevant methods:
15315 *
15316 * - IO#close: Closes the stream for both reading and writing.
15317 * - IO#close_read: Closes the stream for reading.
15318 * - IO#close_write: Closes the stream for writing.
15319 * - IO#closed?: Returns whether the stream is closed.
15320 *
15321 * === End-of-Stream
15322 *
15323 * You can query whether a stream is positioned at its end:
15324 *
15325 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15326 *
15327 * You can reposition to end-of-stream by using method IO#seek:
15328 *
15329 * f = File.new('t.txt')
15330 * f.eof? # => false
15331 * f.seek(0, :END)
15332 * f.eof? # => true
15333 * f.close
15334 *
15335 * Or by reading all stream content (which is slower than using IO#seek):
15336 *
15337 * f.rewind
15338 * f.eof? # => false
15339 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15340 * f.eof? # => true
15341 *
15342 * == Line \IO
15343 *
15344 * Class \IO supports line-oriented
15345 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15346 *
15347 * === Line Input
15348 *
15349 * Class \IO supports line-oriented input for
15350 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input].
15351 *
15352 * ==== Line Input Options
15353 *
15354 * Optional keyword argument +chomp+ (default: +false+)
15355 * specifies whether line separators are to be excluded from the result of a read.
15356 *
15357 * ==== \File Line Input
15358 *
15359 * You can read lines from a file using these methods:
15360 *
15361 * - IO.foreach: Reads each line and passes it to the given block.
15362 * - IO.readlines: Reads and returns all lines in an array.
15363 *
15364 * For each of these methods:
15365 *
15366 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15367 * - Line parsing depends on the effective <i>line separator</i>;
15368 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15369 * - The length of each returned line depends on the effective <i>line limit</i>;
15370 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15371 *
15372 * ==== Stream Line Input
15373 *
15374 * You can read lines from an \IO stream using these methods:
15375 *
15376 * - IO#each_line: Reads each remaining line, passing it to the given block.
15377 * - IO#gets: Returns the next line.
15378 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15379 * - IO#readlines: Returns all remaining lines in an array.
15380 *
15381 * For each of these methods:
15382 *
15383 * - Reading may begin mid-line,
15384 * depending on the stream's _position_;
15385 * see {Position}[rdoc-ref:IO@Position].
15386 * - Line parsing depends on the effective <i>line separator</i>;
15387 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15388 * - The length of each returned line depends on the effective <i>line limit</i>;
15389 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15390 *
15391 * ===== Line Separator
15392 *
15393 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15394 * the string that determines what is considered a line;
15395 * it is sometimes called the <i>input record separator</i>.
15396 *
15397 * The default line separator is taken from global variable <tt>$/</tt>,
15398 * whose initial value is <tt>"\n"</tt>.
15399 *
15400 * Generally, the line to be read next is all data
15401 * from the current {position}[rdoc-ref:IO@Position]
15402 * to the next line separator
15403 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15404 *
15405 * f = File.new('t.txt')
15406 * # Method gets with no sep argument returns the next line, according to $/.
15407 * f.gets # => "First line\n"
15408 * f.gets # => "Second line\n"
15409 * f.gets # => "\n"
15410 * f.gets # => "Fourth line\n"
15411 * f.gets # => "Fifth line\n"
15412 * f.close
15413 *
15414 * You can use a different line separator by passing argument +sep+:
15415 *
15416 * f = File.new('t.txt')
15417 * f.gets('l') # => "First l"
15418 * f.gets('li') # => "ine\nSecond li"
15419 * f.gets('lin') # => "ne\n\nFourth lin"
15420 * f.gets # => "e\n"
15421 * f.close
15422 *
15423 * Or by setting global variable <tt>$/</tt>:
15424 *
15425 * f = File.new('t.txt')
15426 * $/ = 'l'
15427 * f.gets # => "First l"
15428 * f.gets # => "ine\nSecond l"
15429 * f.gets # => "ine\n\nFourth l"
15430 * f.close
15431 *
15432 * ===== Special Line Separator Values
15433 *
15434 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15435 * accepts two special values for parameter +sep+:
15436 *
15437 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15438 *
15439 * f = File.new('t.txt')
15440 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15441 * f.close
15442 *
15443 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15444 * (paragraphs being separated by two consecutive line separators):
15445 *
15446 * f = File.new('t.txt')
15447 * f.gets('') # => "First line\nSecond line\n\n"
15448 * f.gets('') # => "Fourth line\nFifth line\n"
15449 * f.close
15450 *
15451 * ===== Line Limit
15452 *
15453 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15454 * uses an integer <i>line limit</i>,
15455 * which restricts the number of bytes that may be returned.
15456 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15457 * than the limit).
15458 *
15459 * The default limit value is <tt>-1</tt>;
15460 * any negative limit value means that there is no limit.
15461 *
15462 * If there is no limit, the line is determined only by +sep+.
15463 *
15464 * # Text with 1-byte characters.
15465 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15466 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15467 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15468 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15469 * # No more than one line.
15470 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15471 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15472 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15473 *
15474 * # Text with 3-byte characters, which will not be split.
15475 * File.read('t.ja') # => "こんにちは"
15476 * File.open('t.ja') {|f| f.gets(1).size } # => 1
15477 * File.open('t.ja') {|f| f.gets(2).size } # => 1
15478 * File.open('t.ja') {|f| f.gets(3).size } # => 1
15479 * File.open('t.ja') {|f| f.gets(4).size } # => 2
15480 * File.open('t.ja') {|f| f.gets(5).size } # => 2
15481 *
15482 * ===== Line Separator and Line Limit
15483 *
15484 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15485 *
15486 * - Returns the next line as determined by line separator +sep+.
15487 * - But returns no more bytes than are allowed by the limit +limit+.
15488 *
15489 * Example:
15490 *
15491 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15492 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15493 *
15494 * ===== Line Number
15495 *
15496 * A readable \IO stream has a non-negative integer <i>line number</i>:
15497 *
15498 * - IO#lineno: Returns the line number.
15499 * - IO#lineno=: Resets and returns the line number.
15500 *
15501 * Unless modified by a call to method IO#lineno=,
15502 * the line number is the number of lines read
15503 * by certain line-oriented methods,
15504 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15505 *
15506 * - IO.foreach: Increments the line number on each call to the block.
15507 * - IO#each_line: Increments the line number on each call to the block.
15508 * - IO#gets: Increments the line number.
15509 * - IO#readline: Increments the line number.
15510 * - IO#readlines: Increments the line number for each line read.
15511 *
15512 * A new stream is initially has line number zero (and position zero);
15513 * method +rewind+ resets the line number (and position) to zero:
15514 *
15515 * f = File.new('t.txt')
15516 * f.lineno # => 0
15517 * f.gets # => "First line\n"
15518 * f.lineno # => 1
15519 * f.rewind
15520 * f.lineno # => 0
15521 * f.close
15522 *
15523 * Reading lines from a stream usually changes its line number:
15524 *
15525 * f = File.new('t.txt', 'r')
15526 * f.lineno # => 0
15527 * f.readline # => "This is line one.\n"
15528 * f.lineno # => 1
15529 * f.readline # => "This is the second line.\n"
15530 * f.lineno # => 2
15531 * f.readline # => "Here's the third line.\n"
15532 * f.lineno # => 3
15533 * f.eof? # => true
15534 * f.close
15535 *
15536 * Iterating over lines in a stream usually changes its line number:
15537 *
15538 * File.open('t.txt') do |f|
15539 * f.each_line do |line|
15540 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15541 * end
15542 * end
15543 *
15544 * Output:
15545 *
15546 * "position=11 eof?=false lineno=1"
15547 * "position=23 eof?=false lineno=2"
15548 * "position=24 eof?=false lineno=3"
15549 * "position=36 eof?=false lineno=4"
15550 * "position=47 eof?=true lineno=5"
15551 *
15552 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15553 * the line number does not affect where the next read or write will occur:
15554 *
15555 * f = File.new('t.txt')
15556 * f.lineno = 1000
15557 * f.lineno # => 1000
15558 * f.gets # => "First line\n"
15559 * f.lineno # => 1001
15560 * f.close
15561 *
15562 * Associated with the line number is the global variable <tt>$.</tt>:
15563 *
15564 * - When a stream is opened, <tt>$.</tt> is not set;
15565 * its value is left over from previous activity in the process:
15566 *
15567 * $. = 41
15568 * f = File.new('t.txt')
15569 * $. = 41
15570 * # => 41
15571 * f.close
15572 *
15573 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15574 *
15575 * f0 = File.new('t.txt')
15576 * f1 = File.new('t.dat')
15577 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15578 * $. # => 5
15579 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15580 * $. # => 1
15581 * f0.close
15582 * f1.close
15583 *
15584 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15585 *
15586 * f = File.new('t.txt')
15587 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15588 * $. # => 5
15589 * f.rewind
15590 * f.seek(0, :SET)
15591 * $. # => 5
15592 * f.close
15593 *
15594 * === Line Output
15595 *
15596 * You can write to an \IO stream line-by-line using this method:
15597 *
15598 * - IO#puts: Writes objects to the stream.
15599 *
15600 * == Character \IO
15601 *
15602 * You can process an \IO stream character-by-character using these methods:
15603 *
15604 * - IO#getc: Reads and returns the next character from the stream.
15605 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15606 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15607 * - IO#putc: Writes a character to the stream.
15608 * - IO#each_char: Reads each remaining character in the stream,
15609 * passing the character to the given block.
15610 *
15611 * == Byte \IO
15612 *
15613 * You can process an \IO stream byte-by-byte using these methods:
15614 *
15615 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15616 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15617 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15618 * - IO#each_byte: Reads each remaining byte in the stream,
15619 * passing the byte to the given block.
15620 *
15621 * == Codepoint \IO
15622 *
15623 * You can process an \IO stream codepoint-by-codepoint:
15624 *
15625 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15626 *
15627 * == What's Here
15628 *
15629 * First, what's elsewhere. Class \IO:
15630 *
15631 * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
15632 * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
15633 * which provides dozens of additional methods.
15634 *
15635 * Here, class \IO provides methods that are useful for:
15636 *
15637 * - {Creating}[rdoc-ref:IO@Creating]
15638 * - {Reading}[rdoc-ref:IO@Reading]
15639 * - {Writing}[rdoc-ref:IO@Writing]
15640 * - {Positioning}[rdoc-ref:IO@Positioning]
15641 * - {Iterating}[rdoc-ref:IO@Iterating]
15642 * - {Settings}[rdoc-ref:IO@Settings]
15643 * - {Querying}[rdoc-ref:IO@Querying]
15644 * - {Buffering}[rdoc-ref:IO@Buffering]
15645 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15646 * - {Other}[rdoc-ref:IO@Other]
15647 *
15648 * === Creating
15649 *
15650 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15651 * integer file descriptor.
15652 * - ::open: Creates a new \IO object.
15653 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15654 * - ::popen: Creates an \IO object to interact with a subprocess.
15655 * - ::select: Selects which given \IO instances are ready for reading,
15656 * writing, or have pending exceptions.
15657 *
15658 * === Reading
15659 *
15660 * - ::binread: Returns a binary string with all or a subset of bytes
15661 * from the given file.
15662 * - ::read: Returns a string with all or a subset of bytes from the given file.
15663 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15664 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15665 * - #getc: Returns the next character read from +self+ as a string.
15666 * - #gets: Returns the line read from +self+.
15667 * - #pread: Returns all or the next _n_ bytes read from +self+,
15668 * not updating the receiver's offset.
15669 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15670 * for a given _n_.
15671 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15672 * in non-block mode.
15673 * - #readbyte: Returns the next byte read from +self+;
15674 * same as #getbyte, but raises an exception on end-of-stream.
15675 * - #readchar: Returns the next character read from +self+;
15676 * same as #getc, but raises an exception on end-of-stream.
15677 * - #readline: Returns the next line read from +self+;
15678 * same as #getline, but raises an exception of end-of-stream.
15679 * - #readlines: Returns an array of all lines read read from +self+.
15680 * - #readpartial: Returns up to the given number of bytes from +self+.
15681 *
15682 * === Writing
15683 *
15684 * - ::binwrite: Writes the given string to the file at the given filepath,
15685 * in binary mode.
15686 * - ::write: Writes the given string to +self+.
15687 * - #<<: Appends the given string to +self+.
15688 * - #print: Prints last read line or given objects to +self+.
15689 * - #printf: Writes to +self+ based on the given format string and objects.
15690 * - #putc: Writes a character to +self+.
15691 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15692 * - #pwrite: Writes the given string at the given offset,
15693 * not updating the receiver's offset.
15694 * - #write: Writes one or more given strings to +self+.
15695 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15696 *
15697 * === Positioning
15698 *
15699 * - #lineno: Returns the current line number in +self+.
15700 * - #lineno=: Sets the line number is +self+.
15701 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15702 * - #pos=: Sets the byte offset in +self+.
15703 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15704 * - #rewind: Positions +self+ to the beginning of input.
15705 * - #seek: Sets the offset for +self+ relative to given position.
15706 *
15707 * === Iterating
15708 *
15709 * - ::foreach: Yields each line of given file to the block.
15710 * - #each (aliased as #each_line): Calls the given block
15711 * with each successive line in +self+.
15712 * - #each_byte: Calls the given block with each successive byte in +self+
15713 * as an integer.
15714 * - #each_char: Calls the given block with each successive character in +self+
15715 * as a string.
15716 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15717 * as an integer.
15718 *
15719 * === Settings
15720 *
15721 * - #autoclose=: Sets whether +self+ auto-closes.
15722 * - #binmode: Sets +self+ to binary mode.
15723 * - #close: Closes +self+.
15724 * - #close_on_exec=: Sets the close-on-exec flag.
15725 * - #close_read: Closes +self+ for reading.
15726 * - #close_write: Closes +self+ for writing.
15727 * - #set_encoding: Sets the encoding for +self+.
15728 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15729 * Unicode byte-order-mark.
15730 * - #sync=: Sets the sync-mode to the given value.
15731 *
15732 * === Querying
15733 *
15734 * - #autoclose?: Returns whether +self+ auto-closes.
15735 * - #binmode?: Returns whether +self+ is in binary mode.
15736 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15737 * - #closed?: Returns whether +self+ is closed.
15738 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15739 * - #external_encoding: Returns the external encoding object for +self+.
15740 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15741 * - #internal_encoding: Returns the internal encoding object for +self+.
15742 * - #pid: Returns the process ID of a child process associated with +self+,
15743 * if +self+ was created by ::popen.
15744 * - #stat: Returns the File::Stat object containing status information for +self+.
15745 * - #sync: Returns whether +self+ is in sync-mode.
15746 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15747 *
15748 * === Buffering
15749 *
15750 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15751 * - #flush: Flushes any buffered data within +self+ to the underlying
15752 * operating system.
15753 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15754 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15755 * - #ungetc: Prepends buffer for +self+ with given string.
15756 *
15757 * === Low-Level Access
15758 *
15759 * - ::sysopen: Opens the file given by its path,
15760 * returning the integer file descriptor.
15761 * - #advise: Announces the intention to access data from +self+ in a specific way.
15762 * - #fcntl: Passes a low-level command to the file specified
15763 * by the given file descriptor.
15764 * - #ioctl: Passes a low-level command to the device specified
15765 * by the given file descriptor.
15766 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15767 * - #sysseek: Sets the offset for +self+.
15768 * - #syswrite: Writes the given string to +self+ using a low-level write.
15769 *
15770 * === Other
15771 *
15772 * - ::copy_stream: Copies data from a source to a destination,
15773 * each of which is a filepath or an \IO-like object.
15774 * - ::try_convert: Returns a new \IO object resulting from converting
15775 * the given object.
15776 * - #inspect: Returns the string representation of +self+.
15777 *
15778 */
15779
15780void
15781Init_IO(void)
15782{
15783 VALUE rb_cARGF;
15784#ifdef __CYGWIN__
15785#include <sys/cygwin.h>
15786 static struct __cygwin_perfile pf[] =
15787 {
15788 {"", O_RDONLY | O_BINARY},
15789 {"", O_WRONLY | O_BINARY},
15790 {"", O_RDWR | O_BINARY},
15791 {"", O_APPEND | O_BINARY},
15792 {NULL, 0}
15793 };
15794 cygwin_internal(CW_PERFILE, pf);
15795#endif
15796
15797 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
15798 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
15799
15800 id_write = rb_intern_const("write");
15801 id_read = rb_intern_const("read");
15802 id_flush = rb_intern_const("flush");
15803 id_readpartial = rb_intern_const("readpartial");
15804 id_set_encoding = rb_intern_const("set_encoding");
15805 id_fileno = rb_intern_const("fileno");
15806
15807 rb_define_global_function("syscall", rb_f_syscall, -1);
15808
15809 rb_define_global_function("open", rb_f_open, -1);
15810 rb_define_global_function("printf", rb_f_printf, -1);
15811 rb_define_global_function("print", rb_f_print, -1);
15812 rb_define_global_function("putc", rb_f_putc, 1);
15813 rb_define_global_function("puts", rb_f_puts, -1);
15814 rb_define_global_function("gets", rb_f_gets, -1);
15815 rb_define_global_function("readline", rb_f_readline, -1);
15816 rb_define_global_function("select", rb_f_select, -1);
15817
15818 rb_define_global_function("readlines", rb_f_readlines, -1);
15819
15820 rb_define_global_function("`", rb_f_backquote, 1);
15821
15822 rb_define_global_function("p", rb_f_p, -1);
15823 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15824
15825 rb_cIO = rb_define_class("IO", rb_cObject);
15827
15828 /* Can be raised by IO operations when IO#timeout= is set. */
15829 rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
15830
15831 /* Readable event mask for IO#wait. */
15832 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15833 /* Writable event mask for IO#wait. */
15834 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15835 /* Priority event mask for IO#wait. */
15836 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15837
15838 /* exception to wait for reading. see IO.select. */
15839 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
15840 /* exception to wait for writing. see IO.select. */
15841 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
15842 /* exception to wait for reading by EAGAIN. see IO.select. */
15843 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15844 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15845 /* exception to wait for writing by EAGAIN. see IO.select. */
15846 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15847 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15848#if EAGAIN == EWOULDBLOCK
15849 /* same as IO::EAGAINWaitReadable */
15850 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15851 /* same as IO::EAGAINWaitWritable */
15852 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15853#else
15854 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15855 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15856 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15857 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15858 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15859 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15860#endif
15861 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15862 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15863 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15864 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15865 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15866 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15867
15868#if 0
15869 /* This is necessary only for forcing rdoc handle File::open */
15870 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15871#endif
15872
15873 rb_define_alloc_func(rb_cIO, io_alloc);
15874 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15875 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15876 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15877 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15878 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15879 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15880 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15881 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15882 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15883 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15884 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15885 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15886 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15887 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15888 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15889
15890 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15891
15893 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
15894
15895 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15896 rb_vm_register_global_object(rb_default_rs);
15897 rb_rs = rb_default_rs;
15899 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15900 rb_gvar_ractor_local("$/"); // not local but ractor safe
15901 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15902 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15903 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
15904
15905 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15906 rb_gvar_ractor_local("$_");
15907 rb_gvar_box_dynamic("$_");
15908
15909 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15910 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15911
15912 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15913 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15914 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15915 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15916
15917 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15918 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15919 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15920 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15921 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15922
15923 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15924 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15925
15926 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15927 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15928
15929 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15930 rb_define_alias(rb_cIO, "to_i", "fileno");
15931 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15932
15933 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15934 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15935
15936 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15937 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15938 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15939 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15940
15941 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15942 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15943
15944 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15945
15946 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15947 rb_define_method(rb_cIO, "read", io_read, -1);
15948 rb_define_method(rb_cIO, "write", io_write_m, -1);
15949 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15950 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15951 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15952 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15953 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15954 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15955 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15957 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15958 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15959 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15960 /* Set I/O position from the beginning */
15961 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15962 /* Set I/O position from the current position */
15963 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15964 /* Set I/O position from the end */
15965 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15966#ifdef SEEK_DATA
15967 /* Set I/O position to the next location containing data */
15968 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15969#endif
15970#ifdef SEEK_HOLE
15971 /* Set I/O position to the next hole */
15972 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15973#endif
15974 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15975 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15976 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15977 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15978 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15979
15980 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15981 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15982
15983 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15984 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15985 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15986 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15987
15988 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15989 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15990 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15991 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15992 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15993 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15994
15995 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15996 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15997 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15998
15999 rb_define_method(rb_cIO, "path", rb_io_path, 0);
16000 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
16001
16002 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
16003
16004 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
16005 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
16006 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
16007 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
16008
16009 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
16010 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
16011
16012 rb_define_method(rb_cIO, "wait", io_wait, -1);
16013
16014 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
16015 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
16016 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
16017
16018 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
16019 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
16020 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
16021 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
16022
16023 rb_gvar_ractor_local("$stdin");
16024 rb_gvar_ractor_local("$stdout");
16025 rb_gvar_ractor_local("$>");
16026 rb_gvar_ractor_local("$stderr");
16027
16028 rb_gvar_box_dynamic("$stdin");
16029 rb_gvar_box_dynamic("$stdout");
16030 rb_gvar_box_dynamic("$>");
16031 rb_gvar_box_dynamic("$stderr");
16032
16034 rb_stdin = rb_io_prep_stdin();
16036 rb_stdout = rb_io_prep_stdout();
16038 rb_stderr = rb_io_prep_stderr();
16039
16040 orig_stdout = rb_stdout;
16041 orig_stderr = rb_stderr;
16042
16043 /* Holds the original stdin */
16045 /* Holds the original stdout */
16047 /* Holds the original stderr */
16049
16050#if 0
16051 /* Hack to get rdoc to regard ARGF as a class: */
16052 rb_cARGF = rb_define_class("ARGF", rb_cObject);
16053#endif
16054
16055 rb_cARGF = rb_class_new(rb_cObject);
16056 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
16057 rb_define_alloc_func(rb_cARGF, argf_alloc);
16058
16060
16061 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
16062 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
16063 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
16064 rb_define_alias(rb_cARGF, "inspect", "to_s");
16065 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
16066
16067 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
16068 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
16069 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
16070 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
16071 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
16072 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
16073 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
16074 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
16075 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
16076
16077 rb_define_method(rb_cARGF, "read", argf_read, -1);
16078 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
16079 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
16080 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
16081 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
16082 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
16083 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
16084 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
16085 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
16086 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
16087 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
16088 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
16089 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
16090 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
16091 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
16092 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
16093 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
16094 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
16095 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
16096 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
16097
16098 rb_define_method(rb_cARGF, "write", argf_write, -1);
16099 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
16100 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
16101 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
16102 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
16103
16104 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
16105 rb_define_method(rb_cARGF, "path", argf_filename, 0);
16106 rb_define_method(rb_cARGF, "file", argf_file, 0);
16107 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
16108 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
16109 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
16110
16111 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
16112 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
16113
16114 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
16115 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
16116
16117 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
16118 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
16119 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
16120
16121 argf = rb_class_new_instance(0, 0, rb_cARGF);
16122
16124 /*
16125 * ARGF is a stream designed for use in scripts that process files given
16126 * as command-line arguments or passed in via STDIN.
16127 *
16128 * See ARGF (the class) for more details.
16129 */
16131
16132 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
16133 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
16134 ARGF_SET(filename, rb_str_new2("-"));
16135
16136 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
16137 rb_gvar_ractor_local("$-i");
16138
16139 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16140
16141#if defined (_WIN32) || defined(__CYGWIN__)
16142 atexit(pipe_atexit);
16143#endif
16144
16145 Init_File();
16146
16147 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16148
16149 sym_mode = ID2SYM(rb_intern_const("mode"));
16150 sym_perm = ID2SYM(rb_intern_const("perm"));
16151 sym_flags = ID2SYM(rb_intern_const("flags"));
16152 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16153 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16154 sym_encoding = ID2SYM(rb_id_encoding());
16155 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16156 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16157 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16158 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16159 sym_normal = ID2SYM(rb_intern_const("normal"));
16160 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16161 sym_random = ID2SYM(rb_intern_const("random"));
16162 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16163 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16164 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16165 sym_SET = ID2SYM(rb_intern_const("SET"));
16166 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16167 sym_END = ID2SYM(rb_intern_const("END"));
16168#ifdef SEEK_DATA
16169 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16170#endif
16171#ifdef SEEK_HOLE
16172 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16173#endif
16174 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16175 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16176}
16177
16178static void init_builtin_io(void);
16179#define Init_builtin_io init_builtin_io
16180#include "io.rbinc"
16181#undef Init_builtin_io
16182
16183void
16184Init_builtin_io(void)
16185{
16186 init_builtin_io();
16187
16188 /* Init_IO is called earlier than `loaded_features` is initialized */
16189 rb_provide("io/wait.rb");
16190 rb_provide("io/wait.so");
16191}
#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:14849
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:14843
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:8729
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4405
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:8862
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:9291
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:5277
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5182
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:9472
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:9271
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:6520
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6474
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5341
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7517
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10560
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:7405
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:7412
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5877
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:6606
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:6739
#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:7222
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:6888
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:9518
#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:3071
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:7013
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:5788
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:5985
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:3526
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:9384
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:7509
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:14809
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9170
#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.