Ruby 4.0.9p0 (2026-10-23 revision 3e93b23afcec3433f6aecc34b5d832799d754238)
io.c
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;
200static VALUE rb_eEWOULDBLOCKWaitReadable;
201static VALUE rb_eEWOULDBLOCKWaitWritable;
202static VALUE rb_eEINPROGRESSWaitWritable;
203static VALUE rb_eEINPROGRESSWaitReadable;
204
206static VALUE orig_stdout, orig_stderr;
207
209VALUE rb_rs;
212
213static VALUE argf;
214
215static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
216static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
217static VALUE sym_textmode, sym_binmode, sym_autoclose;
218static VALUE sym_SET, sym_CUR, sym_END;
219static VALUE sym_wait_readable, sym_wait_writable;
220#ifdef SEEK_DATA
221static VALUE sym_DATA;
222#endif
223#ifdef SEEK_HOLE
224static VALUE sym_HOLE;
225#endif
226
227static VALUE prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path);
228
229VALUE
230rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
231{
232 return rb_thread_io_blocking_call(io, function, argument, events);
233}
234
235VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
236{
237 return rb_io_blocking_region_wait(io, function, argument, 0);
238}
239
240struct argf {
241 VALUE filename, current_file;
242 long last_lineno; /* $. */
243 long lineno;
244 VALUE argv;
245 VALUE inplace;
246 struct rb_io_encoding encs;
247 int8_t init_p, next_p, binmode;
248};
249
250
251#if defined(__APPLE__) && \
252 (!defined(MAC_OS_VERSION_27_0) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_27_0))
253
254# if __has_attribute(availability) && __has_warning("-Wunguarded-availability-new")
255
257RBIMPL_WARNING_IGNORED(-Wunguarded-availability-new)
258
259# ifdef HAVE_DUP3
260static inline int (*rb_dup3(void))(int, int, int) {return &dup3;}
261# define dup3 rb_dup3()
262# endif
263
264# ifdef HAVE_PIPE2
265static inline int (*rb_pipe2(void))(int [2], int) {return &pipe2;}
266# define pipe2 rb_pipe2()
267# endif
268
270
271# else /* __API_AVAILABLE macro does nothing on gcc */
272
273# ifdef HAVE_DUP3
274__attribute__((weak)) int dup3(int, int, int);
275# endif
276# ifdef HAVE_PIPE2
277__attribute__((weak)) int pipe2(int [2], int);
278# endif
279
280# endif
281#endif /* __APPLE__ && < MAC_OS_X_VERSION_27_0 */
282
283static rb_atomic_t max_file_descriptor = NOFILE;
284void
286{
287 rb_atomic_t afd = (rb_atomic_t)fd;
288 rb_atomic_t max_fd = max_file_descriptor;
289 int err;
290
291 if (fd < 0 || afd <= max_fd)
292 return;
293
294#if defined(HAVE_FCNTL) && defined(F_GETFL)
295 err = fcntl(fd, F_GETFL) == -1;
296#else
297 {
298 struct stat buf;
299 err = fstat(fd, &buf) != 0;
300 }
301#endif
302 if (err && errno == EBADF) {
303 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
304 }
305
306 while (max_fd < afd) {
307 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
308 }
309}
310
311void
312rb_maygvl_fd_fix_cloexec(int fd)
313{
314 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
315#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
316 int flags, flags2, ret;
317 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
318 if (flags == -1) {
319 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
320 }
321 if (fd <= 2)
322 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
323 else
324 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
325 if (flags != flags2) {
326 ret = fcntl(fd, F_SETFD, flags2);
327 if (ret != 0) {
328 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
329 }
330 }
331#endif
332}
333
334void
336{
337 rb_maygvl_fd_fix_cloexec(fd);
339}
340
341/* this is only called once */
342static int
343rb_fix_detect_o_cloexec(int fd)
344{
345#if defined(O_CLOEXEC) && defined(F_GETFD)
346 int flags = fcntl(fd, F_GETFD);
347
348 if (flags == -1)
349 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
350
351 if (flags & FD_CLOEXEC)
352 return 1;
353#endif /* fall through if O_CLOEXEC does not work: */
354 rb_maygvl_fd_fix_cloexec(fd);
355 return 0;
356}
357
358static inline bool
359io_again_p(int e)
360{
361 return (e == EWOULDBLOCK) || (e == EAGAIN);
362}
363
364int
365rb_cloexec_open(const char *pathname, int flags, mode_t mode)
366{
367 int ret;
368 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
369
370 static const int retry_interval = 0;
371 static const int retry_max_count = 10000;
372
373 int retry_count = 0;
374
375#ifdef O_CLOEXEC
376 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
377 flags |= O_CLOEXEC;
378#elif defined O_NOINHERIT
379 flags |= O_NOINHERIT;
380#endif
381
382 while ((ret = open(pathname, flags, mode)) == -1) {
383 int e = errno;
384 if (!io_again_p(e)) break;
385 if (retry_count++ >= retry_max_count) break;
386
387 sleep(retry_interval);
388 }
389
390 if (ret < 0) return ret;
391 if (ret <= 2 || o_cloexec_state == 0) {
392 rb_maygvl_fd_fix_cloexec(ret);
393 }
394 else if (o_cloexec_state > 0) {
395 return ret;
396 }
397 else {
398 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
399 }
400 return ret;
401}
402
403int
405{
406 /* Don't allocate standard file descriptors: 0, 1, 2 */
407 return rb_cloexec_fcntl_dupfd(oldfd, 3);
408}
409
410int
411rb_cloexec_dup2(int oldfd, int newfd)
412{
413 int ret;
414
415 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
416 * rb_cloexec_dup2 succeeds as dup2. */
417 if (oldfd == newfd) {
418 ret = newfd;
419 }
420 else {
421#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
422# if defined(__APPLE__)
423# define try_dup3 (dup3 != NULL)
424# define abandon_dup3() true
425# else
426 static bool try_dup3 = true;
427# define abandon_dup3() (errno != ENOSYS || !!(try_dup3 = false))
428# endif
429 if (newfd <= 2) {
430 /* pass stdin, stdout and stderr to children */
431 }
432 else if (try_dup3) {
433 ret = dup3(oldfd, newfd, O_CLOEXEC);
434 /* dup3 is available since:
435 * - Linux 2.6.27, glibc 2.9
436 * - macOS 27.0
437 */
438 if (ret != -1)
439 return ret;
440 if (abandon_dup3()) return ret;
441 }
442#endif
443 ret = dup2(oldfd, newfd);
444 if (ret < 0) return ret;
445 }
446 rb_maygvl_fd_fix_cloexec(ret);
447 return ret;
448}
449
450static int
451rb_fd_set_nonblock(int fd)
452{
453#ifdef _WIN32
454 return rb_w32_set_nonblock(fd);
455#elif defined(F_GETFL)
456 int oflags = fcntl(fd, F_GETFL);
457
458 if (oflags == -1)
459 return -1;
460 if (oflags & O_NONBLOCK)
461 return 0;
462 oflags |= O_NONBLOCK;
463 return fcntl(fd, F_SETFL, oflags);
464#endif
465 return 0;
466}
467
468static inline int
469cloexec_pipe(int descriptors[2], int flags, bool force_cloexec)
470{
471 int result = -1;
472#ifdef HAVE_PIPE2
473# if defined(__APPLE__)
474# define try_pipe2 (pipe2 != NULL)
475# define abandon_pipe2() true
476# else
477 static bool try_pipe2 = true;
478# define abandon_pipe2() (errno != ENOSYS || !!(try_pipe2 = false))
479# endif
480 if (try_pipe2) {
481 result = pipe2(descriptors, O_CLOEXEC | flags);
482 if (result == 0) return result;
483 if (abandon_pipe2()) return result;
484 }
485#endif
486 if (result < 0 && (result = pipe(descriptors)) < 0)
487 return result;
488
489#ifdef __CYGWIN__
490 if (result == 0 && descriptors[1] == -1) {
491 close(descriptors[0]);
492 descriptors[0] = -1;
493 errno = ENFILE;
494 return -1;
495 }
496#endif
497
498 if (!force_cloexec) return result;
499
500 /* no pipe2 or fallenback to dup */
501 rb_maygvl_fd_fix_cloexec(descriptors[0]);
502 rb_maygvl_fd_fix_cloexec(descriptors[1]);
503
504#ifndef _WIN32
505 rb_fd_set_nonblock(descriptors[0]);
506 rb_fd_set_nonblock(descriptors[1]);
507#endif
508
509 return result;
510}
511
512int
513rb_cloexec_pipe(int descriptors[2])
514{
515 return cloexec_pipe(descriptors, O_NONBLOCK, true);
516}
517
518int
519rb_cloexec_fcntl_dupfd(int fd, int minfd)
520{
521 int ret;
522
523#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
524 static int try_dupfd_cloexec = 1;
525 if (try_dupfd_cloexec) {
526 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
527 if (ret != -1) {
528 if (ret <= 2)
529 rb_maygvl_fd_fix_cloexec(ret);
530 return ret;
531 }
532 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
533 if (errno == EINVAL) {
534 ret = fcntl(fd, F_DUPFD, minfd);
535 if (ret != -1) {
536 try_dupfd_cloexec = 0;
537 }
538 }
539 }
540 else {
541 ret = fcntl(fd, F_DUPFD, minfd);
542 }
543#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
544 ret = fcntl(fd, F_DUPFD, minfd);
545#else
546 ret = dup(fd);
547 if (ret >= 0 && ret < minfd) {
548 const int prev_fd = ret;
549 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
550 close(prev_fd);
551 }
552 return ret;
553#endif
554 if (ret < 0) return ret;
555 rb_maygvl_fd_fix_cloexec(ret);
556 return ret;
557}
558
559#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
560#define ARGF argf_of(argf)
561
562#define GetWriteIO(io) rb_io_get_write_io(io)
563
564#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
565#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
566#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
567#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
568
569#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
570#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
571#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
572
573#if defined(_WIN32)
574#define WAIT_FD_IN_WIN32(fptr) \
575 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
576#else
577#define WAIT_FD_IN_WIN32(fptr)
578#endif
579
580#define READ_CHECK(fptr) do {\
581 if (!READ_DATA_PENDING(fptr)) {\
582 WAIT_FD_IN_WIN32(fptr);\
583 rb_io_check_closed(fptr);\
584 }\
585} while(0)
586
587#ifndef S_ISSOCK
588# ifdef _S_ISSOCK
589# define S_ISSOCK(m) _S_ISSOCK(m)
590# else
591# ifdef _S_IFSOCK
592# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
593# else
594# ifdef S_IFSOCK
595# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
596# endif
597# endif
598# endif
599#endif
600
601static int io_fflush(rb_io_t *);
602static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
603static void clear_codeconv(rb_io_t *fptr);
604
605#define FMODE_SIGNAL_ON_EPIPE (1<<17)
606
607#define fptr_signal_on_epipe(fptr) \
608 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
609
610#define fptr_set_signal_on_epipe(fptr, flag) \
611 ((flag) ? \
612 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
613 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
614
615extern ID ruby_static_id_signo;
616
617NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
618static void
619rb_sys_fail_on_write(rb_io_t *fptr)
620{
621 int e = errno;
622 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
623#if defined EPIPE
624 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
625 const VALUE sig =
626# if defined SIGPIPE
627 INT2FIX(SIGPIPE) - INT2FIX(0) +
628# endif
629 INT2FIX(0);
630 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
631 }
632#endif
633 rb_exc_raise(errinfo);
634}
635
636#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
637#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
638#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
639# define RUBY_CRLF_ENVIRONMENT 1
640#else
641# define RUBY_CRLF_ENVIRONMENT 0
642#endif
643
644#if RUBY_CRLF_ENVIRONMENT
645/* Windows */
646# define DEFAULT_TEXTMODE FMODE_TEXTMODE
647# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
648/*
649 * CRLF newline is set as default newline decorator.
650 * If only CRLF newline conversion is needed, we use binary IO process
651 * with OS's text mode for IO performance improvement.
652 * If encoding conversion is needed or a user sets text mode, we use encoding
653 * conversion IO process and universal newline decorator by default.
654 */
655#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
656#define WRITECONV_MASK ( \
657 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
658 ECONV_STATEFUL_DECORATOR_MASK|\
659 0)
660#define NEED_WRITECONV(fptr) ( \
661 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
662 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
663 0)
664#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
665
666#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
667 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
668 if (((fptr)->mode & FMODE_READABLE) &&\
669 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
670 setmode((fptr)->fd, O_BINARY);\
671 }\
672 else {\
673 setmode((fptr)->fd, O_TEXT);\
674 }\
675 }\
676} while(0)
677
678#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
679 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
680 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
681 }\
682} while(0)
683
684/*
685 * IO unread with taking care of removed '\r' in text mode.
686 */
687static void
688io_unread(rb_io_t *fptr, bool discard_rbuf)
689{
690 rb_off_t r, pos;
691 ssize_t read_size;
692 long i;
693 long newlines = 0;
694 long extra_max;
695 char *p;
696 char *buf;
697
698 rb_io_check_closed(fptr);
699 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
700 return;
701 }
702
703 errno = 0;
704 if (!rb_w32_fd_is_text(fptr->fd)) {
705 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
706 if (r < 0 && errno) {
707 if (errno == ESPIPE)
708 fptr->mode |= FMODE_DUPLEX;
709 if (!discard_rbuf) return;
710 }
711
712 goto end;
713 }
714
715 pos = lseek(fptr->fd, 0, SEEK_CUR);
716 if (pos < 0 && errno) {
717 if (errno == ESPIPE)
718 fptr->mode |= FMODE_DUPLEX;
719 if (!discard_rbuf) goto end;
720 }
721
722 /* add extra offset for removed '\r' in rbuf */
723 extra_max = (long)(pos - fptr->rbuf.len);
724 p = fptr->rbuf.ptr + fptr->rbuf.off;
725
726 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
727 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
728 newlines++;
729 }
730
731 for (i = 0; i < fptr->rbuf.len; i++) {
732 if (*p == '\n') newlines++;
733 if (extra_max == newlines) break;
734 p++;
735 }
736
737 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
738 while (newlines >= 0) {
739 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
740 if (newlines == 0) break;
741 if (r < 0) {
742 newlines--;
743 continue;
744 }
745 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
746 if (read_size < 0) {
747 int e = errno;
748 free(buf);
749 rb_syserr_fail_path(e, fptr->pathv);
750 }
751 if (read_size == fptr->rbuf.len) {
752 lseek(fptr->fd, r, SEEK_SET);
753 break;
754 }
755 else {
756 newlines--;
757 }
758 }
759 free(buf);
760 end:
761 fptr->rbuf.off = 0;
762 fptr->rbuf.len = 0;
763 clear_codeconv(fptr);
764 return;
765}
766
767/*
768 * We use io_seek to back cursor position when changing mode from text to binary,
769 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
770 * conversion for working properly with mode change.
771 *
772 * Return previous translation mode.
773 */
774static inline int
775set_binary_mode_with_seek_cur(rb_io_t *fptr)
776{
777 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
778
779 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
780 return setmode(fptr->fd, O_BINARY);
781 }
782 flush_before_seek(fptr, false);
783 return setmode(fptr->fd, O_BINARY);
784}
785#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
786
787#else
788/* Unix */
789# define DEFAULT_TEXTMODE 0
790#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
791#define NEED_WRITECONV(fptr) ( \
792 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
793 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
794 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
795 0)
796#define SET_BINARY_MODE(fptr) (void)(fptr)
797#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
798#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
799#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
800#endif
801
802#if !defined HAVE_SHUTDOWN && !defined shutdown
803#define shutdown(a,b) 0
804#endif
805
806#if defined(_WIN32)
807#define is_socket(fd, path) rb_w32_is_socket(fd)
808#elif !defined(S_ISSOCK)
809#define is_socket(fd, path) 0
810#else
811static int
812is_socket(int fd, VALUE path)
813{
814 struct stat sbuf;
815 if (fstat(fd, &sbuf) < 0)
816 rb_sys_fail_path(path);
817 return S_ISSOCK(sbuf.st_mode);
818}
819#endif
820
821static const char closed_stream[] = "closed stream";
822
823static void
824io_fd_check_closed(int fd)
825{
826 if (fd < 0) {
827 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
828 rb_raise(rb_eIOError, closed_stream);
829 }
830}
831
832void
834{
835 rb_raise(rb_eEOFError, "end of file reached");
836}
837
838VALUE
840{
841 rb_check_frozen(io);
842 return io;
843}
844
845void
847{
848 if (!fptr) {
849 rb_raise(rb_eIOError, "uninitialized stream");
850 }
851}
852
853void
854rb_io_check_closed(rb_io_t *fptr)
855{
857 io_fd_check_closed(fptr->fd);
858}
859
860static rb_io_t *
861rb_io_get_fptr(VALUE io)
862{
863 rb_io_t *fptr = RFILE(io)->fptr;
865 return fptr;
866}
867
868VALUE
870{
871 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
872}
873
874VALUE
876{
877 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
878}
879
880VALUE
882{
883 VALUE write_io;
884 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
885 if (write_io) {
886 return write_io;
887 }
888 return io;
889}
890
891VALUE
893{
894 VALUE write_io;
895 rb_io_t *fptr = rb_io_get_fptr(io);
896 if (!RTEST(w)) {
897 w = 0;
898 }
899 else {
900 GetWriteIO(w);
901 }
902 write_io = fptr->tied_io_for_writing;
903 fptr->tied_io_for_writing = w;
904 return write_io ? write_io : Qnil;
905}
906
907/*
908 * call-seq:
909 * timeout -> duration or nil
910 *
911 * Get the internal timeout duration or nil if it was not set.
912 *
913 */
914VALUE
916{
917 rb_io_t *fptr = rb_io_get_fptr(self);
918
919 return fptr->timeout;
920}
921
922/*
923 * call-seq:
924 * timeout = duration -> duration
925 * timeout = nil -> nil
926 *
927 * Sets the internal timeout to the specified duration or nil. The timeout
928 * applies to all blocking operations where possible.
929 *
930 * When the operation performs longer than the timeout set, IO::TimeoutError
931 * is raised.
932 *
933 * This affects the following methods (but is not limited to): #gets, #puts,
934 * #read, #write, #wait_readable and #wait_writable. This also affects
935 * blocking socket operations like Socket#accept and Socket#connect.
936 *
937 * Some operations like File#open and IO#close are not affected by the
938 * timeout. A timeout during a write operation may leave the IO in an
939 * inconsistent state, e.g. data was partially written. Generally speaking, a
940 * timeout is a last ditch effort to prevent an application from hanging on
941 * slow I/O operations, such as those that occur during a slowloris attack.
942 */
943VALUE
945{
946 // Validate it:
947 if (RTEST(timeout)) {
948 rb_time_interval(timeout);
949 }
950
951 rb_io_t *fptr = rb_io_get_fptr(self);
952
953 fptr->timeout = timeout;
954
955 return self;
956}
957
958/*
959 * call-seq:
960 * IO.try_convert(object) -> new_io or nil
961 *
962 * Attempts to convert +object+ into an \IO object via method +to_io+;
963 * returns the new \IO object if successful, or +nil+ otherwise:
964 *
965 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
966 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
967 * IO.try_convert('STDOUT') # => nil
968 *
969 */
970static VALUE
971rb_io_s_try_convert(VALUE dummy, VALUE io)
972{
973 return rb_io_check_io(io);
974}
975
976#if !RUBY_CRLF_ENVIRONMENT
977static void
978io_unread(rb_io_t *fptr, bool discard_rbuf)
979{
980 rb_off_t r;
981 rb_io_check_closed(fptr);
982 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
983 return;
984 /* xxx: target position may be negative if buffer is filled by ungetc */
985 errno = 0;
986 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
987 if (r < 0 && errno) {
988 if (errno == ESPIPE)
989 fptr->mode |= FMODE_DUPLEX;
990 if (!discard_rbuf) return;
991 }
992 fptr->rbuf.off = 0;
993 fptr->rbuf.len = 0;
994 clear_codeconv(fptr);
995 return;
996}
997#endif
998
999static rb_encoding *io_input_encoding(rb_io_t *fptr);
1000
1001static void
1002io_ungetbyte(VALUE str, rb_io_t *fptr)
1003{
1004 long len = RSTRING_LEN(str);
1005
1006 if (fptr->rbuf.ptr == NULL) {
1007 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
1008 fptr->rbuf.off = 0;
1009 fptr->rbuf.len = 0;
1010#if SIZEOF_LONG > SIZEOF_INT
1011 if (len > INT_MAX)
1012 rb_raise(rb_eIOError, "ungetbyte failed");
1013#endif
1014 if (len > min_capa)
1015 fptr->rbuf.capa = (int)len;
1016 else
1017 fptr->rbuf.capa = min_capa;
1018 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
1019 }
1020 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
1021 rb_raise(rb_eIOError, "ungetbyte failed");
1022 }
1023 if (fptr->rbuf.off < len) {
1024 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
1025 fptr->rbuf.ptr+fptr->rbuf.off,
1026 char, fptr->rbuf.len);
1027 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
1028 }
1029 fptr->rbuf.off-=(int)len;
1030 fptr->rbuf.len+=(int)len;
1031 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
1032}
1033
1034static rb_io_t *
1035flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
1036{
1037 if (io_fflush(fptr) < 0)
1038 rb_sys_fail_on_write(fptr);
1039 io_unread(fptr, discard_rbuf);
1040 errno = 0;
1041 return fptr;
1042}
1043
1044#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
1045#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1046
1047#ifndef SEEK_CUR
1048# define SEEK_SET 0
1049# define SEEK_CUR 1
1050# define SEEK_END 2
1051#endif
1052
1053void
1055{
1056 rb_io_check_closed(fptr);
1057 if (!(fptr->mode & FMODE_READABLE)) {
1058 rb_raise(rb_eIOError, "not opened for reading");
1059 }
1060 if (fptr->wbuf.len) {
1061 if (io_fflush(fptr) < 0)
1062 rb_sys_fail_on_write(fptr);
1063 }
1064 if (fptr->tied_io_for_writing) {
1065 rb_io_t *wfptr;
1066 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1067 if (io_fflush(wfptr) < 0)
1068 rb_sys_fail_on_write(wfptr);
1069 }
1070}
1071
1072void
1074{
1076 if (READ_CHAR_PENDING(fptr)) {
1077 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1078 }
1079}
1080
1081void
1083{
1085}
1086
1087static rb_encoding*
1088io_read_encoding(rb_io_t *fptr)
1089{
1090 if (fptr->encs.enc) {
1091 return fptr->encs.enc;
1092 }
1093 return rb_default_external_encoding();
1094}
1095
1096static rb_encoding*
1097io_input_encoding(rb_io_t *fptr)
1098{
1099 if (fptr->encs.enc2) {
1100 return fptr->encs.enc2;
1101 }
1102 return io_read_encoding(fptr);
1103}
1104
1105void
1107{
1108 rb_io_check_closed(fptr);
1109 if (!(fptr->mode & FMODE_WRITABLE)) {
1110 rb_raise(rb_eIOError, "not opened for writing");
1111 }
1112 if (fptr->rbuf.len) {
1113 io_unread(fptr, true);
1114 }
1115}
1116
1117int
1119{
1120 /* This function is used for bytes and chars. Confusing. */
1121 if (READ_CHAR_PENDING(fptr))
1122 return 1; /* should raise? */
1123 return READ_DATA_PENDING(fptr);
1124}
1125
1126void
1127rb_io_read_check(rb_io_t *fptr)
1128{
1129 if (!READ_DATA_PENDING(fptr)) {
1130 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1131 }
1132 return;
1133}
1134
1135int
1136rb_gc_for_fd(int err)
1137{
1138 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1139 rb_gc();
1140 return 1;
1141 }
1142 return 0;
1143}
1144
1145/* try `expr` upto twice while it returns false and `errno`
1146 * is to GC. Each `errno`s are available as `first_errno` and
1147 * `retried_errno` respectively */
1148#define TRY_WITH_GC(expr) \
1149 for (int first_errno, retried_errno = 0, retried = 0; \
1150 (!retried && \
1151 !(expr) && \
1152 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1153 (retried_errno = errno, 1)); \
1154 (void)retried_errno, retried = 1)
1155
1156static int
1157ruby_dup(int orig)
1158{
1159 int fd = -1;
1160
1161 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1162 rb_syserr_fail(first_errno, 0);
1163 }
1164 rb_update_max_fd(fd);
1165 return fd;
1166}
1167
1168static VALUE
1169io_alloc(VALUE klass)
1170{
1171 NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
1172
1173 io->fptr = 0;
1174
1175 return (VALUE)io;
1176}
1177
1178#ifndef S_ISREG
1179# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1180#endif
1181
1183 VALUE th;
1184 rb_io_t *fptr;
1185 int nonblock;
1186 int fd;
1187
1188 void *buf;
1189 size_t capa;
1190 struct timeval *timeout;
1191};
1192
1194 VALUE th;
1195 rb_io_t *fptr;
1196 int nonblock;
1197 int fd;
1198
1199 const void *buf;
1200 size_t capa;
1201 struct timeval *timeout;
1202};
1203
1204#ifdef HAVE_WRITEV
1205struct io_internal_writev_struct {
1206 VALUE th;
1207 rb_io_t *fptr;
1208 int nonblock;
1209 int fd;
1210
1211 int iovcnt;
1212 const struct iovec *iov;
1213 struct timeval *timeout;
1214};
1215#endif
1216
1217static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1218
1224static inline int
1225io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1226{
1227 if (!timeout && rb_thread_mn_schedulable(thread)) {
1228 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1229 return -1;
1230 }
1231
1232 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1233
1234 if (ready > 0) {
1235 return ready;
1236 }
1237 else if (ready == 0) {
1238 errno = ETIMEDOUT;
1239 return -1;
1240 }
1241
1242 // If there was an error BEFORE we started waiting, return it:
1243 if (error) {
1244 errno = error;
1245 return -1;
1246 }
1247 else {
1248 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1249 return ready;
1250 }
1251}
1252
1253static VALUE
1254internal_read_func(void *ptr)
1255{
1256 struct io_internal_read_struct *iis = ptr;
1257 ssize_t result;
1258
1259 if (iis->timeout && !iis->nonblock) {
1260 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1261 return -1;
1262 }
1263 }
1264
1265 retry:
1266 result = read(iis->fd, iis->buf, iis->capa);
1267
1268 if (result < 0 && !iis->nonblock) {
1269 if (io_again_p(errno)) {
1270 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1271 return -1;
1272 }
1273 else {
1274 goto retry;
1275 }
1276 }
1277 }
1278
1279 return result;
1280}
1281
1282#if defined __APPLE__
1283# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1284#else
1285# define do_write_retry(code) result = code
1286#endif
1287
1288static VALUE
1289internal_write_func(void *ptr)
1290{
1291 struct io_internal_write_struct *iis = ptr;
1292 ssize_t result;
1293
1294 if (iis->timeout && !iis->nonblock) {
1295 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1296 return -1;
1297 }
1298 }
1299
1300 retry:
1301 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1302
1303 if (result < 0 && !iis->nonblock) {
1304 int e = errno;
1305 if (io_again_p(e)) {
1306 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1307 return -1;
1308 }
1309 else {
1310 goto retry;
1311 }
1312 }
1313 }
1314
1315 return result;
1316}
1317
1318#ifdef HAVE_WRITEV
1319static VALUE
1320internal_writev_func(void *ptr)
1321{
1322 struct io_internal_writev_struct *iis = ptr;
1323 ssize_t result;
1324
1325 if (iis->timeout && !iis->nonblock) {
1326 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1327 return -1;
1328 }
1329 }
1330
1331 retry:
1332 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1333
1334 if (result < 0 && !iis->nonblock) {
1335 if (io_again_p(errno)) {
1336 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1337 return -1;
1338 }
1339 else {
1340 goto retry;
1341 }
1342 }
1343 }
1344
1345 return result;
1346}
1347#endif
1348
1349static ssize_t
1350rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1351{
1352 rb_thread_t *th = GET_THREAD();
1354 if (scheduler != Qnil) {
1355 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1356
1357 if (!UNDEF_P(result)) {
1358 return rb_fiber_scheduler_io_result_apply(result);
1359 }
1360 }
1361
1362 struct io_internal_read_struct iis = {
1363 .th = th->self,
1364 .fptr = fptr,
1365 .nonblock = 0,
1366 .fd = fptr->fd,
1367
1368 .buf = buf,
1369 .capa = count,
1370 .timeout = NULL,
1371 };
1372
1373 struct timeval timeout_storage;
1374
1375 if (fptr->timeout != Qnil) {
1376 timeout_storage = rb_time_interval(fptr->timeout);
1377 iis.timeout = &timeout_storage;
1378 }
1379
1380 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1381}
1382
1383static ssize_t
1384rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1385{
1386 rb_thread_t *th = GET_THREAD();
1388 if (scheduler != Qnil) {
1389 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1390
1391 if (!UNDEF_P(result)) {
1392 return rb_fiber_scheduler_io_result_apply(result);
1393 }
1394 }
1395
1396 struct io_internal_write_struct iis = {
1397 .th = th->self,
1398 .fptr = fptr,
1399 .nonblock = 0,
1400 .fd = fptr->fd,
1401
1402 .buf = buf,
1403 .capa = count,
1404 .timeout = NULL
1405 };
1406
1407 struct timeval timeout_storage;
1408
1409 if (fptr->timeout != Qnil) {
1410 timeout_storage = rb_time_interval(fptr->timeout);
1411 iis.timeout = &timeout_storage;
1412 }
1413
1414 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1415}
1416
1417#ifdef HAVE_WRITEV
1418static ssize_t
1419rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1420{
1421 if (!iovcnt) return 0;
1422
1423 rb_thread_t *th = GET_THREAD();
1424
1426 if (scheduler != Qnil) {
1427 // This path assumes at least one `iov`:
1428 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1429
1430 if (!UNDEF_P(result)) {
1431 return rb_fiber_scheduler_io_result_apply(result);
1432 }
1433 }
1434
1435 struct io_internal_writev_struct iis = {
1436 .th = th->self,
1437 .fptr = fptr,
1438 .nonblock = 0,
1439 .fd = fptr->fd,
1440
1441 .iov = iov,
1442 .iovcnt = iovcnt,
1443 .timeout = NULL
1444 };
1445
1446 struct timeval timeout_storage;
1447
1448 if (fptr->timeout != Qnil) {
1449 timeout_storage = rb_time_interval(fptr->timeout);
1450 iis.timeout = &timeout_storage;
1451 }
1452
1453 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1454}
1455#endif
1456
1457static VALUE
1458io_flush_buffer_sync(void *arg)
1459{
1460 rb_io_t *fptr = arg;
1461 long l = fptr->wbuf.len;
1462 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1463
1464 if (fptr->wbuf.len <= r) {
1465 fptr->wbuf.off = 0;
1466 fptr->wbuf.len = 0;
1467 return 0;
1468 }
1469
1470 if (0 <= r) {
1471 fptr->wbuf.off += (int)r;
1472 fptr->wbuf.len -= (int)r;
1473 errno = EAGAIN;
1474 }
1475
1476 return (VALUE)-1;
1477}
1478
1479static inline VALUE
1480io_flush_buffer_fiber_scheduler(VALUE scheduler, rb_io_t *fptr)
1481{
1482 VALUE ret = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, fptr->wbuf.ptr+fptr->wbuf.off, fptr->wbuf.len, 0);
1483 if (!UNDEF_P(ret)) {
1484 ssize_t result = rb_fiber_scheduler_io_result_apply(ret);
1485 if (result > 0) {
1486 fptr->wbuf.off += result;
1487 fptr->wbuf.len -= result;
1488 }
1489 return result >= 0 ? (VALUE)0 : (VALUE)-1;
1490 }
1491 return ret;
1492}
1493
1494static VALUE
1495io_flush_buffer_async(VALUE arg)
1496{
1497 rb_io_t *fptr = (rb_io_t *)arg;
1498
1499 VALUE scheduler = rb_fiber_scheduler_current();
1500 if (scheduler != Qnil) {
1501 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1502 if (!UNDEF_P(result)) {
1503 return result;
1504 }
1505 }
1506
1507 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1508}
1509
1510static inline int
1511io_flush_buffer(rb_io_t *fptr)
1512{
1513 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1514 return (int)io_flush_buffer_async((VALUE)fptr);
1515 }
1516 else {
1517 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1518 }
1519}
1520
1521static int
1522io_fflush(rb_io_t *fptr)
1523{
1524 rb_io_check_closed(fptr);
1525
1526 if (fptr->wbuf.len == 0)
1527 return 0;
1528
1529 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1530 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1531 return -1;
1532
1533 rb_io_check_closed(fptr);
1534 }
1535
1536 return 0;
1537}
1538
1539VALUE
1540rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1541{
1542 rb_thread_t *th = GET_THREAD();
1544
1545 if (scheduler != Qnil) {
1546 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1547 }
1548
1549 rb_io_t * fptr = NULL;
1550 RB_IO_POINTER(io, fptr);
1551
1552 struct timeval tv_storage;
1553 struct timeval *tv = NULL;
1554
1555 if (NIL_OR_UNDEF_P(timeout)) {
1556 timeout = fptr->timeout;
1557 }
1558
1559 if (timeout != Qnil) {
1560 tv_storage = rb_time_interval(timeout);
1561 tv = &tv_storage;
1562 }
1563
1564 int ready = rb_thread_io_wait(th, fptr, RB_NUM2INT(events), tv);
1565
1566 if (ready < 0) {
1567 rb_sys_fail(0);
1568 }
1569
1570 // Not sure if this is necessary:
1571 rb_io_check_closed(fptr);
1572
1573 if (ready) {
1574 return RB_INT2NUM(ready);
1575 }
1576 else {
1577 return Qfalse;
1578 }
1579}
1580
1581static VALUE
1582io_from_fd(int fd)
1583{
1584 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1585}
1586
1587static int
1588io_wait_for_single_fd(int fd, int events, struct timeval *timeout, rb_thread_t *th, VALUE scheduler)
1589{
1590 if (scheduler != Qnil) {
1591 return RTEST(
1592 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1593 );
1594 }
1595
1596 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1597}
1598
1599int
1601{
1602 io_fd_check_closed(f);
1603
1604 rb_thread_t *th = GET_THREAD();
1606
1607 switch (errno) {
1608 case EINTR:
1609#if defined(ERESTART)
1610 case ERESTART:
1611#endif
1613 return TRUE;
1614
1615 case EAGAIN:
1616#if EWOULDBLOCK != EAGAIN
1617 case EWOULDBLOCK:
1618#endif
1619 if (scheduler != Qnil) {
1620 return RTEST(
1621 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1622 );
1623 }
1624 else {
1625 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL, th, scheduler);
1626 }
1627 return TRUE;
1628
1629 default:
1630 return FALSE;
1631 }
1632}
1633
1634int
1636{
1637 io_fd_check_closed(f);
1638
1639 rb_thread_t *th = GET_THREAD();
1641
1642 switch (errno) {
1643 case EINTR:
1644#if defined(ERESTART)
1645 case ERESTART:
1646#endif
1647 /*
1648 * In old Linux, several special files under /proc and /sys don't handle
1649 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1650 * Otherwise, we face nasty hang up. Sigh.
1651 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1652 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1653 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1654 * Then rb_thread_check_ints() is enough.
1655 */
1657 return TRUE;
1658
1659 case EAGAIN:
1660#if EWOULDBLOCK != EAGAIN
1661 case EWOULDBLOCK:
1662#endif
1663 if (scheduler != Qnil) {
1664 return RTEST(
1665 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1666 );
1667 }
1668 else {
1669 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL, th, scheduler);
1670 }
1671 return TRUE;
1672
1673 default:
1674 return FALSE;
1675 }
1676}
1677
1678int
1679rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1680{
1681 rb_thread_t *th = GET_THREAD();
1683 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1684}
1685
1686int
1688{
1689 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1690}
1691
1692int
1694{
1695 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1696}
1697
1698VALUE
1699rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1700{
1701 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1702 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1703 // instead relies on `read(-1) -> -1` which causes this code path. We then
1704 // check here whether the IO was in fact closed. Probably it's better to
1705 // check that `fptr->fd != -1` before using it in syscall.
1706 rb_io_check_closed(RFILE(io)->fptr);
1707
1708 switch (error) {
1709 // In old Linux, several special files under /proc and /sys don't handle
1710 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1711 // Otherwise, we face nasty hang up. Sigh.
1712 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1713 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1714 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1715 // Then rb_thread_check_ints() is enough.
1716 case EINTR:
1717#if defined(ERESTART)
1718 case ERESTART:
1719#endif
1720 // We might have pending interrupts since the previous syscall was interrupted:
1722
1723 // The operation was interrupted, so retry it immediately:
1724 return events;
1725
1726 case EAGAIN:
1727#if EWOULDBLOCK != EAGAIN
1728 case EWOULDBLOCK:
1729#endif
1730 {
1731 // The operation would block, so wait for the specified events:
1732 VALUE result = rb_io_wait(io, events, timeout);
1733 // The scheduler may change errno while waiting. Preserve the original
1734 // error in case no events are ready and the caller reports the failure.
1735 errno = error;
1736 return result;
1737 }
1738
1739 default:
1740 // Non-specific error, no event is ready:
1741 return Qnil;
1742 }
1743}
1744
1745int
1747{
1748 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1749
1750 if (RTEST(result)) {
1751 return RB_NUM2INT(result);
1752 }
1753 else if (result == RUBY_Qfalse) {
1754 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1755 }
1756
1757 return 0;
1758}
1759
1760int
1762{
1763 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1764
1765 if (RTEST(result)) {
1766 return RB_NUM2INT(result);
1767 }
1768 else if (result == RUBY_Qfalse) {
1769 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1770 }
1771
1772 return 0;
1773}
1774
1775static void
1776make_writeconv(rb_io_t *fptr)
1777{
1778 if (!fptr->writeconv_initialized) {
1779 const char *senc, *denc;
1780 rb_encoding *enc;
1781 int ecflags;
1782 VALUE ecopts;
1783
1784 fptr->writeconv_initialized = 1;
1785
1787 ecopts = fptr->encs.ecopts;
1788
1789 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1790 /* no encoding conversion */
1791 fptr->writeconv_pre_ecflags = 0;
1792 fptr->writeconv_pre_ecopts = Qnil;
1793 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1794 if (!fptr->writeconv)
1795 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1797 }
1798 else {
1799 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1800 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1801 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1802 /* single conversion */
1803 fptr->writeconv_pre_ecflags = ecflags;
1804 fptr->writeconv_pre_ecopts = ecopts;
1805 fptr->writeconv = NULL;
1807 }
1808 else {
1809 /* double conversion */
1811 fptr->writeconv_pre_ecopts = ecopts;
1812 if (senc) {
1813 denc = rb_enc_name(enc);
1814 fptr->writeconv_asciicompat = rb_str_new2(senc);
1815 }
1816 else {
1817 senc = denc = "";
1818 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1819 }
1821 ecopts = fptr->encs.ecopts;
1822 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1823 if (!fptr->writeconv)
1824 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1825 }
1826 }
1827 }
1828}
1829
1830/* writing functions */
1832 rb_io_t *fptr;
1833 const char *ptr;
1834 long length;
1835};
1836
1838 VALUE io;
1839 VALUE str;
1840 int nosync;
1841};
1842
1843#ifdef HAVE_WRITEV
1844static ssize_t
1845io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1846{
1847 if (fptr->wbuf.len) {
1848 struct iovec iov[2];
1849
1850 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1851 iov[0].iov_len = fptr->wbuf.len;
1852 iov[1].iov_base = (void*)ptr;
1853 iov[1].iov_len = length;
1854
1855 ssize_t result = rb_writev_internal(fptr, iov, 2);
1856
1857 if (result < 0)
1858 return result;
1859
1860 if (result >= fptr->wbuf.len) {
1861 // We wrote more than the internal buffer:
1862 result -= fptr->wbuf.len;
1863 fptr->wbuf.off = 0;
1864 fptr->wbuf.len = 0;
1865 }
1866 else {
1867 // We only wrote less data than the internal buffer:
1868 fptr->wbuf.off += (int)result;
1869 fptr->wbuf.len -= (int)result;
1870
1871 result = 0;
1872 }
1873
1874 return result;
1875 }
1876 else {
1877 return rb_io_write_memory(fptr, ptr, length);
1878 }
1879}
1880#else
1881static ssize_t
1882io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1883{
1884 long remaining = length;
1885
1886 if (fptr->wbuf.len) {
1887 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1888 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1889 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1890 fptr->wbuf.off = 0;
1891 }
1892
1893 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1894 fptr->wbuf.len += (int)length;
1895
1896 // We copied the entire incoming data to the internal buffer:
1897 remaining = 0;
1898 }
1899
1900 // Flush the internal buffer:
1901 if (io_fflush(fptr) < 0) {
1902 return -1;
1903 }
1904
1905 // If all the data was buffered, we are done:
1906 if (remaining == 0) {
1907 return length;
1908 }
1909 }
1910
1911 // Otherwise, we should write the data directly:
1912 return rb_io_write_memory(fptr, ptr, length);
1913}
1914#endif
1915
1916static VALUE
1917io_binwrite_string(VALUE arg)
1918{
1919 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1920
1921 const char *ptr = p->ptr;
1922 size_t remaining = p->length;
1923
1924 while (remaining) {
1925 // Write as much as possible:
1926 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1927
1928 if (result == 0) {
1929 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1930 // should try again immediately.
1931 }
1932 else if (result > 0) {
1933 if ((size_t)result == remaining) break;
1934 ptr += result;
1935 remaining -= result;
1936 }
1937 // Wait for it to become writable:
1938 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1939 rb_io_check_closed(p->fptr);
1940 }
1941 else {
1942 // The error was unrelated to waiting for it to become writable, so we fail:
1943 return -1;
1944 }
1945 }
1946
1947 return p->length;
1948}
1949
1950inline static void
1951io_allocate_write_buffer(rb_io_t *fptr, int sync)
1952{
1953 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1954 fptr->wbuf.off = 0;
1955 fptr->wbuf.len = 0;
1956 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1957 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1958 }
1959
1960 if (NIL_P(fptr->write_lock)) {
1961 fptr->write_lock = rb_mutex_new();
1962 rb_mutex_allow_trap(fptr->write_lock, 1);
1963 }
1964}
1965
1966static inline int
1967io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1968{
1969 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1970 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1971 return 1;
1972
1973 // If the amount of data we want to write exceeds the internal buffer:
1974 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1975 return 1;
1976
1977 // Otherwise, we can append to the internal buffer:
1978 return 0;
1979}
1980
1981static long
1982io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1983{
1984 if (len <= 0) return len;
1985
1986 // Don't write anything if current thread has a pending interrupt:
1988
1989 io_allocate_write_buffer(fptr, !nosync);
1990
1991 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1992 struct binwrite_arg arg;
1993
1994 arg.fptr = fptr;
1995 arg.ptr = ptr;
1996 arg.length = len;
1997
1998 if (!NIL_P(fptr->write_lock)) {
1999 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
2000 }
2001 else {
2002 return io_binwrite_string((VALUE)&arg);
2003 }
2004 }
2005 else {
2006 if (fptr->wbuf.off) {
2007 if (fptr->wbuf.len)
2008 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
2009 fptr->wbuf.off = 0;
2010 }
2011
2012 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
2013 fptr->wbuf.len += (int)len;
2014
2015 return len;
2016 }
2017}
2018
2019# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
2020 (fmode & FMODE_TEXTMODE) ? (c) : (a))
2021
2022#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
2023 MODE_BTMODE(d, e, f) : \
2024 MODE_BTMODE(a, b, c))
2025
2026static VALUE
2027do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
2028{
2029 if (NEED_WRITECONV(fptr)) {
2030 VALUE common_encoding = Qnil;
2031 SET_BINARY_MODE(fptr);
2032
2033 make_writeconv(fptr);
2034
2035 if (fptr->writeconv) {
2036#define fmode (fptr->mode)
2037 if (!NIL_P(fptr->writeconv_asciicompat))
2038 common_encoding = fptr->writeconv_asciicompat;
2039 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
2040 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2041 rb_enc_name(rb_enc_get(str)));
2042 }
2043#undef fmode
2044 }
2045 else {
2046 if (fptr->encs.enc2)
2047 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
2048 else if (fptr->encs.enc != rb_ascii8bit_encoding())
2049 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
2050 }
2051
2052 if (!NIL_P(common_encoding)) {
2053 str = rb_str_encode(str, common_encoding,
2055 *converted = 1;
2056 }
2057
2058 if (fptr->writeconv) {
2060 *converted = 1;
2061 }
2062 }
2063#if RUBY_CRLF_ENVIRONMENT
2064#define fmode (fptr->mode)
2065 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2066 if ((fptr->mode & FMODE_READABLE) &&
2068 setmode(fptr->fd, O_BINARY);
2069 }
2070 else {
2071 setmode(fptr->fd, O_TEXT);
2072 }
2073 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2074 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2075 rb_enc_name(rb_enc_get(str)));
2076 }
2077 }
2078#undef fmode
2079#endif
2080 return str;
2081}
2082
2083static long
2084io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
2085{
2086 int converted = 0;
2087 VALUE tmp;
2088 long n, len;
2089 const char *ptr;
2090
2091#ifdef _WIN32
2092 if (fptr->mode & FMODE_TTY) {
2093 long len = rb_w32_write_console(str, fptr->fd);
2094 if (len > 0) return len;
2095 }
2096#endif
2097
2098 str = do_writeconv(str, fptr, &converted);
2099 if (converted)
2100 OBJ_FREEZE(str);
2101
2102 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2103 RSTRING_GETMEM(tmp, ptr, len);
2104 n = io_binwrite(ptr, len, fptr, nosync);
2105 rb_str_tmp_frozen_release(str, tmp);
2106
2107 return n;
2108}
2109
2110ssize_t
2111rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2112{
2113 rb_io_t *fptr;
2114
2115 GetOpenFile(io, fptr);
2117 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2118}
2119
2120static VALUE
2121io_write(VALUE io, VALUE str, int nosync)
2122{
2123 rb_io_t *fptr;
2124 long n;
2125 VALUE tmp;
2126
2127 io = GetWriteIO(io);
2128 str = rb_obj_as_string(str);
2129 tmp = rb_io_check_io(io);
2130
2131 if (NIL_P(tmp)) {
2132 /* port is not IO, call write method for it. */
2133 return rb_funcall(io, id_write, 1, str);
2134 }
2135
2136 io = tmp;
2137 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2138
2139 GetOpenFile(io, fptr);
2141
2142 n = io_fwrite(str, fptr, nosync);
2143 if (n < 0L) rb_sys_fail_on_write(fptr);
2144
2145 return LONG2FIX(n);
2146}
2147
2148#ifdef HAVE_WRITEV
2149struct binwritev_arg {
2150 rb_io_t *fptr;
2151 struct iovec *iov;
2152 int iovcnt;
2153 size_t total;
2154};
2155
2156static VALUE
2157io_binwritev_internal(VALUE arg)
2158{
2159 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2160
2161 size_t remaining = p->total;
2162 size_t offset = 0;
2163
2164 rb_io_t *fptr = p->fptr;
2165 struct iovec *iov = p->iov;
2166 int iovcnt = p->iovcnt;
2167
2168 while (remaining) {
2169 long result = rb_writev_internal(fptr, iov, iovcnt);
2170
2171 if (result >= 0) {
2172 offset += result;
2173 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2174 if (offset < (size_t)fptr->wbuf.len) {
2175 fptr->wbuf.off += result;
2176 fptr->wbuf.len -= result;
2177 }
2178 else {
2179 offset -= (size_t)fptr->wbuf.len;
2180 fptr->wbuf.off = 0;
2181 fptr->wbuf.len = 0;
2182 }
2183 }
2184
2185 if (offset == p->total) {
2186 return p->total;
2187 }
2188
2189 while (result >= (ssize_t)iov->iov_len) {
2190 /* iovcnt > 0 */
2191 result -= iov->iov_len;
2192 iov->iov_len = 0;
2193 iov++;
2194
2195 if (!--iovcnt) {
2196 // I don't believe this code path can ever occur.
2197 return offset;
2198 }
2199 }
2200
2201 iov->iov_base = (char *)iov->iov_base + result;
2202 iov->iov_len -= result;
2203 }
2204 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2205 rb_io_check_closed(fptr);
2206 }
2207 else {
2208 return -1;
2209 }
2210 }
2211
2212 return offset;
2213}
2214
2215static long
2216io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2217{
2218 // Don't write anything if current thread has a pending interrupt:
2220
2221 if (iovcnt == 0) return 0;
2222
2223 size_t total = 0;
2224 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2225
2226 io_allocate_write_buffer(fptr, 1);
2227
2228 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2229 // The end of the buffered data:
2230 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2231
2232 if (offset + total <= (size_t)fptr->wbuf.capa) {
2233 for (int i = 1; i < iovcnt; i++) {
2234 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2235 offset += iov[i].iov_len;
2236 }
2237
2238 fptr->wbuf.len += total;
2239
2240 return total;
2241 }
2242 else {
2243 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2244 iov[0].iov_len = fptr->wbuf.len;
2245 }
2246 }
2247 else {
2248 // The first iov is reserved for the internal buffer, and it's empty.
2249 iov++;
2250
2251 if (!--iovcnt) {
2252 // If there are no other io vectors we are done.
2253 return 0;
2254 }
2255 }
2256
2257 struct binwritev_arg arg;
2258 arg.fptr = fptr;
2259 arg.iov = iov;
2260 arg.iovcnt = iovcnt;
2261 arg.total = total;
2262
2263 if (!NIL_P(fptr->write_lock)) {
2264 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2265 }
2266 else {
2267 return io_binwritev_internal((VALUE)&arg);
2268 }
2269}
2270
2271static long
2272io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2273{
2274 int i, converted, iovcnt = argc + 1;
2275 long n;
2276 VALUE v1, v2, str, tmp, *tmp_array;
2277 struct iovec *iov;
2278
2279 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2280 tmp_array = ALLOCV_N(VALUE, v2, argc);
2281
2282 for (i = 0; i < argc; i++) {
2283 str = rb_obj_as_string(argv[i]);
2284 converted = 0;
2285 str = do_writeconv(str, fptr, &converted);
2286
2287 if (converted)
2288 OBJ_FREEZE(str);
2289
2290 tmp = rb_str_tmp_frozen_acquire(str);
2291 tmp_array[i] = tmp;
2292
2293 /* iov[0] is reserved for buffer of fptr */
2294 iov[i+1].iov_base = RSTRING_PTR(tmp);
2295 iov[i+1].iov_len = RSTRING_LEN(tmp);
2296 }
2297
2298 n = io_binwritev(iov, iovcnt, fptr);
2299 if (v1) ALLOCV_END(v1);
2300
2301 for (i = 0; i < argc; i++) {
2302 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2303 }
2304
2305 if (v2) ALLOCV_END(v2);
2306
2307 return n;
2308}
2309
2310static int
2311iovcnt_ok(int iovcnt)
2312{
2313#ifdef IOV_MAX
2314 return iovcnt < IOV_MAX;
2315#else /* GNU/Hurd has writev, but no IOV_MAX */
2316 return 1;
2317#endif
2318}
2319#endif /* HAVE_WRITEV */
2320
2321static VALUE
2322io_writev(int argc, const VALUE *argv, VALUE io)
2323{
2324 rb_io_t *fptr;
2325 long n;
2326 VALUE tmp, total = INT2FIX(0);
2327 int i, cnt = 1;
2328
2329 io = GetWriteIO(io);
2330 tmp = rb_io_check_io(io);
2331
2332 if (NIL_P(tmp)) {
2333 /* port is not IO, call write method for it. */
2334 return rb_funcallv(io, id_write, argc, argv);
2335 }
2336
2337 io = tmp;
2338
2339 GetOpenFile(io, fptr);
2341
2342 for (i = 0; i < argc; i += cnt) {
2343#ifdef HAVE_WRITEV
2344 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2345 n = io_fwritev(cnt, &argv[i], fptr);
2346 }
2347 else
2348#endif
2349 {
2350 cnt = 1;
2351 /* sync at last item */
2352 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2353 }
2354
2355 if (n < 0L)
2356 rb_sys_fail_on_write(fptr);
2357
2358 total = rb_fix_plus(LONG2FIX(n), total);
2359 }
2360
2361 return total;
2362}
2363
2364/*
2365 * call-seq:
2366 * write(*objects) -> integer
2367 *
2368 * Writes each of the given +objects+ to +self+,
2369 * which must be opened for writing
2370 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2371 * returns the total number bytes written;
2372 * each of +objects+ that is not a string is converted via method +to_s+:
2373 *
2374 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2375 * $stdout.write('foo', :bar, 2, "\n") # => 8
2376 *
2377 * Output:
2378 *
2379 * Hello, World!
2380 * foobar2
2381 *
2382 * Related: IO#read.
2383 */
2384
2385static VALUE
2386io_write_m(int argc, VALUE *argv, VALUE io)
2387{
2388 if (argc != 1) {
2389 return io_writev(argc, argv, io);
2390 }
2391 else {
2392 VALUE str = argv[0];
2393 return io_write(io, str, 0);
2394 }
2395}
2396
2397VALUE
2398rb_io_write(VALUE io, VALUE str)
2399{
2400 return rb_funcallv(io, id_write, 1, &str);
2401}
2402
2403static VALUE
2404rb_io_writev(VALUE io, int argc, const VALUE *argv)
2405{
2406 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2407 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2408 VALUE klass = CLASS_OF(io);
2409 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2411 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2412 " which accepts just one argument",
2413 klass, sep
2414 );
2415 }
2416
2417 do rb_io_write(io, *argv++); while (--argc);
2418
2419 return Qnil;
2420 }
2421
2422 return rb_funcallv(io, id_write, argc, argv);
2423}
2424
2425/*
2426 * call-seq:
2427 * self << object -> self
2428 *
2429 * Writes the given +object+ to +self+,
2430 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2431 * returns +self+;
2432 * if +object+ is not a string, it is converted via method +to_s+:
2433 *
2434 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2435 * $stdout << 'foo' << :bar << 2 << "\n"
2436 *
2437 * Output:
2438 *
2439 * Hello, World!
2440 * foobar2
2441 *
2442 */
2443
2444
2445VALUE
2447{
2448 rb_io_write(io, str);
2449 return io;
2450}
2451
2452#ifdef HAVE_FSYNC
2453static VALUE
2454nogvl_fsync(void *ptr)
2455{
2456 rb_io_t *fptr = ptr;
2457
2458#ifdef _WIN32
2459 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2460 return 0;
2461#endif
2462 return (VALUE)fsync(fptr->fd);
2463}
2464#endif
2465
2466VALUE
2467rb_io_flush_raw(VALUE io, int sync)
2468{
2469 rb_io_t *fptr;
2470
2471 if (!RB_TYPE_P(io, T_FILE)) {
2472 return rb_funcall(io, id_flush, 0);
2473 }
2474
2475 io = GetWriteIO(io);
2476 GetOpenFile(io, fptr);
2477
2478 if (fptr->mode & FMODE_WRITABLE) {
2479 if (io_fflush(fptr) < 0)
2480 rb_sys_fail_on_write(fptr);
2481 }
2482 if (fptr->mode & FMODE_READABLE) {
2483 io_unread(fptr, true);
2484 }
2485
2486 return io;
2487}
2488
2489/*
2490 * call-seq:
2491 * flush -> self
2492 *
2493 * Flushes data buffered in +self+ to the operating system
2494 * (but does not necessarily flush data buffered in the operating system):
2495 *
2496 * $stdout.print 'no newline' # Not necessarily flushed.
2497 * $stdout.flush # Flushed.
2498 *
2499 */
2500
2501VALUE
2502rb_io_flush(VALUE io)
2503{
2504 return rb_io_flush_raw(io, 1);
2505}
2506
2507/*
2508 * call-seq:
2509 * tell -> integer
2510 *
2511 * Returns the current position (in bytes) in +self+
2512 * (see {Position}[rdoc-ref:IO@Position]):
2513 *
2514 * f = File.open('t.txt')
2515 * f.tell # => 0
2516 * f.gets # => "First line\n"
2517 * f.tell # => 12
2518 * f.close
2519 *
2520 * Related: IO#pos=, IO#seek.
2521 */
2522
2523static VALUE
2524rb_io_tell(VALUE io)
2525{
2526 rb_io_t *fptr;
2527 rb_off_t pos;
2528
2529 GetOpenFile(io, fptr);
2530 pos = io_tell(fptr);
2531 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2532 pos -= fptr->rbuf.len;
2533 return OFFT2NUM(pos);
2534}
2535
2536static VALUE
2537rb_io_seek(VALUE io, VALUE offset, int whence)
2538{
2539 rb_io_t *fptr;
2540 rb_off_t pos;
2541
2542 pos = NUM2OFFT(offset);
2543 GetOpenFile(io, fptr);
2544 pos = io_seek(fptr, pos, whence);
2545 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2546
2547 return INT2FIX(0);
2548}
2549
2550static int
2551interpret_seek_whence(VALUE vwhence)
2552{
2553 if (vwhence == sym_SET)
2554 return SEEK_SET;
2555 if (vwhence == sym_CUR)
2556 return SEEK_CUR;
2557 if (vwhence == sym_END)
2558 return SEEK_END;
2559#ifdef SEEK_DATA
2560 if (vwhence == sym_DATA)
2561 return SEEK_DATA;
2562#endif
2563#ifdef SEEK_HOLE
2564 if (vwhence == sym_HOLE)
2565 return SEEK_HOLE;
2566#endif
2567 return NUM2INT(vwhence);
2568}
2569
2570/*
2571 * call-seq:
2572 * seek(offset, whence = IO::SEEK_SET) -> 0
2573 *
2574 * Seeks to the position given by integer +offset+
2575 * (see {Position}[rdoc-ref:IO@Position])
2576 * and constant +whence+, which is one of:
2577 *
2578 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2579 * Repositions the stream to its current position plus the given +offset+:
2580 *
2581 * f = File.open('t.txt')
2582 * f.tell # => 0
2583 * f.seek(20, :CUR) # => 0
2584 * f.tell # => 20
2585 * f.seek(-10, :CUR) # => 0
2586 * f.tell # => 10
2587 * f.close
2588 *
2589 * - +:END+ or <tt>IO::SEEK_END</tt>:
2590 * Repositions the stream to its end plus the given +offset+:
2591 *
2592 * f = File.open('t.txt')
2593 * f.tell # => 0
2594 * f.seek(0, :END) # => 0 # Repositions to stream end.
2595 * f.tell # => 52
2596 * f.seek(-20, :END) # => 0
2597 * f.tell # => 32
2598 * f.seek(-40, :END) # => 0
2599 * f.tell # => 12
2600 * f.close
2601 *
2602 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2603 * Repositions the stream to the given +offset+:
2604 *
2605 * f = File.open('t.txt')
2606 * f.tell # => 0
2607 * f.seek(20, :SET) # => 0
2608 * f.tell # => 20
2609 * f.seek(40, :SET) # => 0
2610 * f.tell # => 40
2611 * f.close
2612 *
2613 * Related: IO#pos=, IO#tell.
2614 *
2615 */
2616
2617static VALUE
2618rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2619{
2620 VALUE offset, ptrname;
2621 int whence = SEEK_SET;
2622
2623 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2624 whence = interpret_seek_whence(ptrname);
2625 }
2626
2627 return rb_io_seek(io, offset, whence);
2628}
2629
2630/*
2631 * call-seq:
2632 * pos = new_position -> new_position
2633 *
2634 * Seeks to the given +new_position+ (in bytes);
2635 * see {Position}[rdoc-ref:IO@Position]:
2636 *
2637 * f = File.open('t.txt')
2638 * f.tell # => 0
2639 * f.pos = 20 # => 20
2640 * f.tell # => 20
2641 * f.close
2642 *
2643 * Related: IO#seek, IO#tell.
2644 *
2645 */
2646
2647static VALUE
2648rb_io_set_pos(VALUE io, VALUE offset)
2649{
2650 rb_io_t *fptr;
2651 rb_off_t pos;
2652
2653 pos = NUM2OFFT(offset);
2654 GetOpenFile(io, fptr);
2655 pos = io_seek(fptr, pos, SEEK_SET);
2656 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2657
2658 return OFFT2NUM(pos);
2659}
2660
2661static void clear_readconv(rb_io_t *fptr);
2662
2663/*
2664 * call-seq:
2665 * rewind -> 0
2666 *
2667 * Repositions the stream to its beginning,
2668 * setting both the position and the line number to zero;
2669 * see {Position}[rdoc-ref:IO@Position]
2670 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2671 *
2672 * f = File.open('t.txt')
2673 * f.tell # => 0
2674 * f.lineno # => 0
2675 * f.gets # => "First line\n"
2676 * f.tell # => 12
2677 * f.lineno # => 1
2678 * f.rewind # => 0
2679 * f.tell # => 0
2680 * f.lineno # => 0
2681 * f.close
2682 *
2683 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2684 *
2685 */
2686
2687static VALUE
2688rb_io_rewind(VALUE io)
2689{
2690 rb_io_t *fptr;
2691
2692 GetOpenFile(io, fptr);
2693 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2694 if (io == ARGF.current_file) {
2695 ARGF.lineno -= fptr->lineno;
2696 }
2697 fptr->lineno = 0;
2698 if (fptr->readconv) {
2699 clear_readconv(fptr);
2700 }
2701
2702 return INT2FIX(0);
2703}
2704
2705static int
2706fptr_wait_readable(rb_io_t *fptr)
2707{
2708 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2709
2710 if (result)
2711 rb_io_check_closed(fptr);
2712
2713 return result;
2714}
2715
2716static int
2717io_fillbuf(rb_io_t *fptr)
2718{
2719 ssize_t r;
2720
2721 if (fptr->rbuf.ptr == NULL) {
2722 fptr->rbuf.off = 0;
2723 fptr->rbuf.len = 0;
2724 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2725 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2726 }
2727 if (fptr->rbuf.len == 0) {
2728 retry:
2729 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2730
2731 if (r < 0) {
2732 if (fptr_wait_readable(fptr))
2733 goto retry;
2734
2735 int e = errno;
2736 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2737 if (!NIL_P(fptr->pathv)) {
2738 rb_str_append(path, fptr->pathv);
2739 }
2740
2741 rb_syserr_fail_path(e, path);
2742 }
2743 if (r > 0) rb_io_check_closed(fptr);
2744 fptr->rbuf.off = 0;
2745 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2746 if (r == 0)
2747 return -1; /* EOF */
2748 }
2749 return 0;
2750}
2751
2752/*
2753 * call-seq:
2754 * eof -> true or false
2755 *
2756 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2757 * see {Position}[rdoc-ref:IO@Position]:
2758 *
2759 * f = File.open('t.txt')
2760 * f.eof # => false
2761 * f.seek(0, :END) # => 0
2762 * f.eof # => true
2763 * f.close
2764 *
2765 * Raises an exception unless the stream is opened for reading;
2766 * see {Mode}[rdoc-ref:File@Access+Modes].
2767 *
2768 * If +self+ is a stream such as pipe or socket, this method
2769 * blocks until the other end sends some data or closes it:
2770 *
2771 * r, w = IO.pipe
2772 * Thread.new { sleep 1; w.close }
2773 * r.eof? # => true # After 1-second wait.
2774 *
2775 * r, w = IO.pipe
2776 * Thread.new { sleep 1; w.puts "a" }
2777 * r.eof? # => false # After 1-second wait.
2778 *
2779 * r, w = IO.pipe
2780 * r.eof? # blocks forever
2781 *
2782 * Note that this method reads data to the input byte buffer. So
2783 * IO#sysread may not behave as you intend with IO#eof?, unless you
2784 * call IO#rewind first (which is not available for some streams).
2785 */
2786
2787VALUE
2789{
2790 rb_io_t *fptr;
2791
2792 GetOpenFile(io, fptr);
2794
2795 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2796 if (READ_DATA_PENDING(fptr)) return Qfalse;
2797 READ_CHECK(fptr);
2798#if RUBY_CRLF_ENVIRONMENT
2799 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2800 return RBOOL(eof(fptr->fd));
2801 }
2802#endif
2803 return RBOOL(io_fillbuf(fptr) < 0);
2804}
2805
2806/*
2807 * call-seq:
2808 * sync -> true or false
2809 *
2810 * Returns the current sync mode of the stream.
2811 * When sync mode is true, all output is immediately flushed to the underlying
2812 * operating system and is not buffered by Ruby internally. See also #fsync.
2813 *
2814 * f = File.open('t.tmp', 'w')
2815 * f.sync # => false
2816 * f.sync = true
2817 * f.sync # => true
2818 * f.close
2819 *
2820 */
2821
2822static VALUE
2823rb_io_sync(VALUE io)
2824{
2825 rb_io_t *fptr;
2826
2827 io = GetWriteIO(io);
2828 GetOpenFile(io, fptr);
2829 return RBOOL(fptr->mode & FMODE_SYNC);
2830}
2831
2832#ifdef HAVE_FSYNC
2833
2834/*
2835 * call-seq:
2836 * sync = boolean -> boolean
2837 *
2838 * Sets the _sync_ _mode_ for the stream to the given value;
2839 * returns the given value.
2840 *
2841 * Values for the sync mode:
2842 *
2843 * - +true+: All output is immediately flushed to the
2844 * underlying operating system and is not buffered internally.
2845 * - +false+: Output may be buffered internally.
2846 *
2847 * Example;
2848 *
2849 * f = File.open('t.tmp', 'w')
2850 * f.sync # => false
2851 * f.sync = true
2852 * f.sync # => true
2853 * f.close
2854 *
2855 * Related: IO#fsync.
2856 *
2857 */
2858
2859static VALUE
2860rb_io_set_sync(VALUE io, VALUE sync)
2861{
2862 rb_io_t *fptr;
2863
2864 io = GetWriteIO(io);
2865 GetOpenFile(io, fptr);
2866 if (RTEST(sync)) {
2867 fptr->mode |= FMODE_SYNC;
2868 }
2869 else {
2870 fptr->mode &= ~FMODE_SYNC;
2871 }
2872 return sync;
2873}
2874
2875/*
2876 * call-seq:
2877 * fsync -> 0
2878 *
2879 * Immediately writes to disk all data buffered in the stream,
2880 * via the operating system's <tt>fsync(2)</tt>.
2881
2882 * Note this difference:
2883 *
2884 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2885 * but does not guarantee that the operating system actually writes the data to disk.
2886 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2887 * and that data is written to disk.
2888 *
2889 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2890 *
2891 */
2892
2893static VALUE
2894rb_io_fsync(VALUE io)
2895{
2896 rb_io_t *fptr;
2897
2898 io = GetWriteIO(io);
2899 GetOpenFile(io, fptr);
2900
2901 if (io_fflush(fptr) < 0)
2902 rb_sys_fail_on_write(fptr);
2903
2904 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2905 rb_sys_fail_path(fptr->pathv);
2906
2907 return INT2FIX(0);
2908}
2909#else
2910# define rb_io_fsync rb_f_notimplement
2911# define rb_io_sync rb_f_notimplement
2912static VALUE
2913rb_io_set_sync(VALUE io, VALUE sync)
2914{
2917}
2918#endif
2919
2920#ifdef HAVE_FDATASYNC
2921static VALUE
2922nogvl_fdatasync(void *ptr)
2923{
2924 rb_io_t *fptr = ptr;
2925
2926#ifdef _WIN32
2927 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2928 return 0;
2929#endif
2930 return (VALUE)fdatasync(fptr->fd);
2931}
2932
2933/*
2934 * call-seq:
2935 * fdatasync -> 0
2936 *
2937 * Immediately writes to disk all data buffered in the stream,
2938 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2939 * otherwise via <tt>fsync(2)</tt>, if supported;
2940 * otherwise raises an exception.
2941 *
2942 */
2943
2944static VALUE
2945rb_io_fdatasync(VALUE io)
2946{
2947 rb_io_t *fptr;
2948
2949 io = GetWriteIO(io);
2950 GetOpenFile(io, fptr);
2951
2952 if (io_fflush(fptr) < 0)
2953 rb_sys_fail_on_write(fptr);
2954
2955 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2956 return INT2FIX(0);
2957
2958 /* fall back */
2959 return rb_io_fsync(io);
2960}
2961#else
2962#define rb_io_fdatasync rb_io_fsync
2963#endif
2964
2965/*
2966 * call-seq:
2967 * fileno -> integer
2968 *
2969 * Returns the integer file descriptor for the stream:
2970 *
2971 * $stdin.fileno # => 0
2972 * $stdout.fileno # => 1
2973 * $stderr.fileno # => 2
2974 * File.open('t.txt').fileno # => 10
2975 * f.close
2976 *
2977 */
2978
2979static VALUE
2980rb_io_fileno(VALUE io)
2981{
2982 rb_io_t *fptr = RFILE(io)->fptr;
2983 int fd;
2984
2985 rb_io_check_closed(fptr);
2986 fd = fptr->fd;
2987 return INT2FIX(fd);
2988}
2989
2990int
2992{
2993 if (RB_TYPE_P(io, T_FILE)) {
2994 rb_io_t *fptr = RFILE(io)->fptr;
2995 rb_io_check_closed(fptr);
2996 return fptr->fd;
2997 }
2998 else {
2999 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
3000 if (!UNDEF_P(fileno)) {
3001 return RB_NUM2INT(fileno);
3002 }
3003 }
3004
3005 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
3006
3008}
3009
3010int
3011rb_io_mode(VALUE io)
3012{
3013 rb_io_t *fptr;
3014 GetOpenFile(io, fptr);
3015 return fptr->mode;
3016}
3017
3018/*
3019 * call-seq:
3020 * pid -> integer or nil
3021 *
3022 * Returns the process ID of a child process associated with the stream,
3023 * which will have been set by IO#popen, or +nil+ if the stream was not
3024 * created by IO#popen:
3025 *
3026 * pipe = IO.popen("-")
3027 * if pipe
3028 * $stderr.puts "In parent, child pid is #{pipe.pid}"
3029 * else
3030 * $stderr.puts "In child, pid is #{$$}"
3031 * end
3032 *
3033 * Output:
3034 *
3035 * In child, pid is 26209
3036 * In parent, child pid is 26209
3037 *
3038 */
3039
3040static VALUE
3041rb_io_pid(VALUE io)
3042{
3043 rb_io_t *fptr;
3044
3045 GetOpenFile(io, fptr);
3046 if (!fptr->pid)
3047 return Qnil;
3048 return PIDT2NUM(fptr->pid);
3049}
3050
3051/*
3052 * call-seq:
3053 * path -> string or nil
3054 *
3055 * Returns the path associated with the IO, or +nil+ if there is no path
3056 * associated with the IO. It is not guaranteed that the path exists on
3057 * the filesystem.
3058 *
3059 * $stdin.path # => "<STDIN>"
3060 *
3061 * File.open("testfile") {|f| f.path} # => "testfile"
3062 */
3063
3064VALUE
3066{
3067 rb_io_t *fptr = RFILE(io)->fptr;
3068
3069 if (!fptr)
3070 return Qnil;
3071
3072 return rb_obj_dup(fptr->pathv);
3073}
3074
3075/*
3076 * call-seq:
3077 * inspect -> string
3078 *
3079 * Returns a string representation of +self+:
3080 *
3081 * f = File.open('t.txt')
3082 * f.inspect # => "#<File:t.txt>"
3083 * f.close
3084 *
3085 */
3086
3087static VALUE
3088rb_io_inspect(VALUE obj)
3089{
3090 rb_io_t *fptr;
3091 VALUE result;
3092 static const char closed[] = " (closed)";
3093
3094 fptr = RFILE(obj)->fptr;
3095 if (!fptr) return rb_any_to_s(obj);
3096 result = rb_str_new_cstr("#<");
3097 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3098 rb_str_cat2(result, ":");
3099 if (NIL_P(fptr->pathv)) {
3100 if (fptr->fd < 0) {
3101 rb_str_cat(result, closed+1, strlen(closed)-1);
3102 }
3103 else {
3104 rb_str_catf(result, "fd %d", fptr->fd);
3105 }
3106 }
3107 else {
3108 rb_str_append(result, fptr->pathv);
3109 if (fptr->fd < 0) {
3110 rb_str_cat(result, closed, strlen(closed));
3111 }
3112 }
3113 return rb_str_cat2(result, ">");
3114}
3115
3116/*
3117 * call-seq:
3118 * to_io -> self
3119 *
3120 * Returns +self+.
3121 *
3122 */
3123
3124static VALUE
3125rb_io_to_io(VALUE io)
3126{
3127 return io;
3128}
3129
3130/* reading functions */
3131static long
3132read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3133{
3134 int n;
3135
3136 n = READ_DATA_PENDING_COUNT(fptr);
3137 if (n <= 0) return 0;
3138 if (n > len) n = (int)len;
3139 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3140 fptr->rbuf.off += n;
3141 fptr->rbuf.len -= n;
3142 return n;
3143}
3144
3145static long
3146io_bufread(char *ptr, long len, rb_io_t *fptr)
3147{
3148 long offset = 0;
3149 long n = len;
3150 long c;
3151
3152 if (READ_DATA_PENDING(fptr) == 0) {
3153 while (n > 0) {
3154 again:
3155 rb_io_check_closed(fptr);
3156 c = rb_io_read_memory(fptr, ptr+offset, n);
3157 if (c == 0) break;
3158 if (c < 0) {
3159 if (fptr_wait_readable(fptr))
3160 goto again;
3161 return -1;
3162 }
3163 offset += c;
3164 if ((n -= c) <= 0) break;
3165 }
3166 return len - n;
3167 }
3168
3169 while (n > 0) {
3170 c = read_buffered_data(ptr+offset, n, fptr);
3171 if (c > 0) {
3172 offset += c;
3173 if ((n -= c) <= 0) break;
3174 }
3175 rb_io_check_closed(fptr);
3176 if (io_fillbuf(fptr) < 0) {
3177 break;
3178 }
3179 }
3180 return len - n;
3181}
3182
3183static int io_setstrbuf(VALUE *str, long len);
3184
3186 char *str_ptr;
3187 long len;
3188 rb_io_t *fptr;
3189};
3190
3191static VALUE
3192bufread_call(VALUE arg)
3193{
3194 struct bufread_arg *p = (struct bufread_arg *)arg;
3195 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3196 return Qundef;
3197}
3198
3199static long
3200io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3201{
3202 long len;
3203 struct bufread_arg arg;
3204
3205 io_setstrbuf(&str, offset + size);
3206 arg.str_ptr = RSTRING_PTR(str) + offset;
3207 arg.len = size;
3208 arg.fptr = fptr;
3209 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3210 len = arg.len;
3211 if (len < 0) rb_sys_fail_path(fptr->pathv);
3212 return len;
3213}
3214
3215static long
3216remain_size(rb_io_t *fptr)
3217{
3218 struct stat st;
3219 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3220 rb_off_t pos;
3221
3222 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3223#if defined(__HAIKU__)
3224 && (st.st_dev > 3)
3225#endif
3226 )
3227 {
3228 if (io_fflush(fptr) < 0)
3229 rb_sys_fail_on_write(fptr);
3230 pos = lseek(fptr->fd, 0, SEEK_CUR);
3231 if (st.st_size >= pos && pos >= 0) {
3232 siz += st.st_size - pos;
3233 if (siz > LONG_MAX) {
3234 rb_raise(rb_eIOError, "file too big for single read");
3235 }
3236 }
3237 }
3238 else {
3239 siz += BUFSIZ;
3240 }
3241 return (long)siz;
3242}
3243
3244static VALUE
3245io_enc_str(VALUE str, rb_io_t *fptr)
3246{
3247 rb_enc_associate(str, io_read_encoding(fptr));
3248 return str;
3249}
3250
3251static void
3252make_readconv(rb_io_t *fptr, int size)
3253{
3254 if (!fptr->readconv) {
3255 int ecflags;
3256 VALUE ecopts;
3257 const char *sname, *dname;
3259 ecopts = fptr->encs.ecopts;
3260 if (fptr->encs.enc2) {
3261 sname = rb_enc_name(fptr->encs.enc2);
3262 dname = rb_enc_name(io_read_encoding(fptr));
3263 }
3264 else {
3265 sname = dname = "";
3266 }
3267 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3268 if (!fptr->readconv)
3269 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3270 fptr->cbuf.off = 0;
3271 fptr->cbuf.len = 0;
3272 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3273 fptr->cbuf.capa = size;
3274 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3275 }
3276}
3277
3278#define MORE_CHAR_SUSPENDED Qtrue
3279#define MORE_CHAR_FINISHED Qnil
3280static VALUE
3281fill_cbuf(rb_io_t *fptr, int ec_flags)
3282{
3283 const unsigned char *ss, *sp, *se;
3284 unsigned char *ds, *dp, *de;
3286 int putbackable;
3287 int cbuf_len0;
3288 VALUE exc;
3289
3290 ec_flags |= ECONV_PARTIAL_INPUT;
3291
3292 if (fptr->cbuf.len == fptr->cbuf.capa)
3293 return MORE_CHAR_SUSPENDED; /* cbuf full */
3294 if (fptr->cbuf.len == 0)
3295 fptr->cbuf.off = 0;
3296 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3297 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3298 fptr->cbuf.off = 0;
3299 }
3300
3301 cbuf_len0 = fptr->cbuf.len;
3302
3303 while (1) {
3304 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3305 se = sp + fptr->rbuf.len;
3306 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3307 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3308 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3309 fptr->rbuf.off += (int)(sp - ss);
3310 fptr->rbuf.len -= (int)(sp - ss);
3311 fptr->cbuf.len += (int)(dp - ds);
3312
3313 putbackable = rb_econv_putbackable(fptr->readconv);
3314 if (putbackable) {
3315 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3316 fptr->rbuf.off -= putbackable;
3317 fptr->rbuf.len += putbackable;
3318 }
3319
3320 exc = rb_econv_make_exception(fptr->readconv);
3321 if (!NIL_P(exc))
3322 return exc;
3323
3324 if (cbuf_len0 != fptr->cbuf.len)
3325 return MORE_CHAR_SUSPENDED;
3326
3327 if (res == econv_finished) {
3328 return MORE_CHAR_FINISHED;
3329 }
3330
3331 if (res == econv_source_buffer_empty) {
3332 if (fptr->rbuf.len == 0) {
3333 READ_CHECK(fptr);
3334 if (io_fillbuf(fptr) < 0) {
3335 if (!fptr->readconv) {
3336 return MORE_CHAR_FINISHED;
3337 }
3338 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3339 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3340 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3341 fptr->cbuf.len += (int)(dp - ds);
3343 break;
3344 }
3345 }
3346 }
3347 }
3348 if (cbuf_len0 != fptr->cbuf.len)
3349 return MORE_CHAR_SUSPENDED;
3350
3351 return MORE_CHAR_FINISHED;
3352}
3353
3354static VALUE
3355more_char(rb_io_t *fptr)
3356{
3357 VALUE v;
3358 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3359 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3360 rb_exc_raise(v);
3361 return v;
3362}
3363
3364static VALUE
3365io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3366{
3367 VALUE str = Qnil;
3368 if (strp) {
3369 str = *strp;
3370 if (NIL_P(str)) {
3371 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3372 }
3373 else {
3374 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3375 }
3376 rb_enc_associate(str, fptr->encs.enc);
3377 }
3378 fptr->cbuf.off += len;
3379 fptr->cbuf.len -= len;
3380 /* xxx: set coderange */
3381 if (fptr->cbuf.len == 0)
3382 fptr->cbuf.off = 0;
3383 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3384 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3385 fptr->cbuf.off = 0;
3386 }
3387 return str;
3388}
3389
3390static int
3391io_setstrbuf(VALUE *str, long len)
3392{
3393 if (NIL_P(*str)) {
3394 *str = rb_str_new(0, len);
3395 return TRUE;
3396 }
3397 else {
3398 VALUE s = StringValue(*str);
3399 rb_str_modify(s);
3400
3401 long clen = RSTRING_LEN(s);
3402 if (clen >= len) {
3403 return FALSE;
3404 }
3405 len -= clen;
3406 }
3407 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3409 }
3410 return FALSE;
3411}
3412
3413#define MAX_REALLOC_GAP 4096
3414static void
3415io_shrink_read_string(VALUE str, long n)
3416{
3417 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3418 rb_str_resize(str, n);
3419 }
3420}
3421
3422static void
3423io_set_read_length(VALUE str, long n, int shrinkable)
3424{
3425 if (RSTRING_LEN(str) != n) {
3426 rb_str_modify(str);
3427 rb_str_set_len(str, n);
3428 if (shrinkable) io_shrink_read_string(str, n);
3429 }
3430}
3431
3432static VALUE
3433read_all(rb_io_t *fptr, long siz, VALUE str)
3434{
3435 long bytes;
3436 long n;
3437 long pos;
3438 rb_encoding *enc;
3439 int cr;
3440 int shrinkable;
3441
3442 if (NEED_READCONV(fptr)) {
3443 int first = !NIL_P(str);
3444 SET_BINARY_MODE(fptr);
3445 shrinkable = io_setstrbuf(&str,0);
3446 make_readconv(fptr, 0);
3447 while (1) {
3448 VALUE v;
3449 if (fptr->cbuf.len) {
3450 if (first) rb_str_set_len(str, first = 0);
3451 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3452 }
3453 v = fill_cbuf(fptr, 0);
3454 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
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 rb_exc_raise(v);
3460 }
3461 if (v == MORE_CHAR_FINISHED) {
3462 clear_readconv(fptr);
3463 if (first) rb_str_set_len(str, first = 0);
3464 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3465 return io_enc_str(str, fptr);
3466 }
3467 }
3468 }
3469
3470 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3471 bytes = 0;
3472 pos = 0;
3473
3474 enc = io_read_encoding(fptr);
3475 cr = 0;
3476
3477 if (siz == 0) siz = BUFSIZ;
3478 shrinkable = io_setstrbuf(&str, siz);
3479 for (;;) {
3480 READ_CHECK(fptr);
3481 n = io_fread(str, bytes, siz - bytes, fptr);
3482 if (n == 0 && bytes == 0) {
3483 rb_str_set_len(str, 0);
3484 break;
3485 }
3486 bytes += n;
3487 rb_str_set_len(str, bytes);
3488 if (cr != ENC_CODERANGE_BROKEN)
3489 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3490 if (bytes < siz) break;
3491 siz += BUFSIZ;
3492
3493 size_t capa = rb_str_capacity(str);
3494 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3495 if (capa < BUFSIZ) {
3496 capa = BUFSIZ;
3497 }
3498 else if (capa > IO_MAX_BUFFER_GROWTH) {
3499 capa = IO_MAX_BUFFER_GROWTH;
3500 }
3502 }
3503 }
3504 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3505 str = io_enc_str(str, fptr);
3506 ENC_CODERANGE_SET(str, cr);
3507 return str;
3508}
3509
3510void
3512{
3513 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3514 rb_sys_fail_path(fptr->pathv);
3515 }
3516}
3517
3518static VALUE
3519io_read_memory_call(VALUE arg)
3520{
3521 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3522
3523 VALUE scheduler = rb_fiber_scheduler_current();
3524 if (scheduler != Qnil) {
3525 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3526
3527 if (!UNDEF_P(result)) {
3528 // This is actually returned as a pseudo-VALUE and later cast to a long:
3529 return (VALUE)rb_fiber_scheduler_io_result_apply(result);
3530 }
3531 }
3532
3533 if (iis->nonblock) {
3534 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3535 }
3536 else {
3537 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3538 }
3539}
3540
3541static long
3542io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3543{
3544 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3545}
3546
3547#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3548
3549static VALUE
3550io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3551{
3552 rb_io_t *fptr;
3553 VALUE length, str;
3554 long n, len;
3555 struct io_internal_read_struct iis;
3556 int shrinkable;
3557
3558 rb_scan_args(argc, argv, "11", &length, &str);
3559
3560 if ((len = NUM2LONG(length)) < 0) {
3561 rb_raise(rb_eArgError, "negative length %ld given", len);
3562 }
3563
3564 shrinkable = io_setstrbuf(&str, len);
3565
3566 GetOpenFile(io, fptr);
3568
3569 if (len == 0) {
3570 io_set_read_length(str, 0, shrinkable);
3571 return str;
3572 }
3573
3574 if (!nonblock)
3575 READ_CHECK(fptr);
3576 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3577 if (n <= 0) {
3578 again:
3579 if (nonblock) {
3580 rb_io_set_nonblock(fptr);
3581 }
3582 io_setstrbuf(&str, len);
3583 iis.th = rb_thread_current();
3584 iis.fptr = fptr;
3585 iis.nonblock = nonblock;
3586 iis.fd = fptr->fd;
3587 iis.buf = RSTRING_PTR(str);
3588 iis.capa = len;
3589 iis.timeout = NULL;
3590 n = io_read_memory_locktmp(str, &iis);
3591 if (n < 0) {
3592 int e = errno;
3593 if (!nonblock && fptr_wait_readable(fptr))
3594 goto again;
3595 if (nonblock && (io_again_p(e))) {
3596 if (no_exception)
3597 return sym_wait_readable;
3598 else
3599 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3600 e, "read would block");
3601 }
3602 rb_syserr_fail_path(e, fptr->pathv);
3603 }
3604 }
3605 io_set_read_length(str, n, shrinkable);
3606
3607 if (n == 0)
3608 return Qnil;
3609 else
3610 return str;
3611}
3612
3613/*
3614 * call-seq:
3615 * readpartial(maxlen) -> string
3616 * readpartial(maxlen, out_string) -> out_string
3617 *
3618 * Reads up to +maxlen+ bytes from the stream;
3619 * returns a string (either a new string or the given +out_string+).
3620 * Its encoding is:
3621 *
3622 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3623 * - ASCII-8BIT, otherwise.
3624 *
3625 * - Contains +maxlen+ bytes from the stream, if available.
3626 * - Otherwise contains all available bytes, if any available.
3627 * - Otherwise is an empty string.
3628 *
3629 * With the single non-negative integer argument +maxlen+ given,
3630 * returns a new string:
3631 *
3632 * f = File.new('t.txt')
3633 * f.readpartial(20) # => "First line\nSecond l"
3634 * f.readpartial(20) # => "ine\n\nFourth line\n"
3635 * f.readpartial(20) # => "Fifth line\n"
3636 * f.readpartial(20) # Raises EOFError.
3637 * f.close
3638 *
3639 * With both argument +maxlen+ and string argument +out_string+ given,
3640 * returns modified +out_string+:
3641 *
3642 * f = File.new('t.txt')
3643 * s = 'foo'
3644 * f.readpartial(20, s) # => "First line\nSecond l"
3645 * s = 'bar'
3646 * f.readpartial(0, s) # => ""
3647 * f.close
3648 *
3649 * This method is useful for a stream such as a pipe, a socket, or a tty.
3650 * It blocks only when no data is immediately available.
3651 * This means that it blocks only when _all_ of the following are true:
3652 *
3653 * - The byte buffer in the stream is empty.
3654 * - The content of the stream is empty.
3655 * - The stream is not at EOF.
3656 *
3657 * When blocked, the method waits for either more data or EOF on the stream:
3658 *
3659 * - If more data is read, the method returns the data.
3660 * - If EOF is reached, the method raises EOFError.
3661 *
3662 * When not blocked, the method responds immediately:
3663 *
3664 * - Returns data from the buffer if there is any.
3665 * - Otherwise returns data from the stream if there is any.
3666 * - Otherwise raises EOFError if the stream has reached EOF.
3667 *
3668 * Note that this method is similar to sysread. The differences are:
3669 *
3670 * - If the byte buffer is not empty, read from the byte buffer
3671 * instead of "sysread for buffered IO (IOError)".
3672 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3673 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3674 * readpartial retries the system call.
3675 *
3676 * The latter means that readpartial is non-blocking-flag insensitive.
3677 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3678 * if the fd is blocking mode.
3679 *
3680 * Examples:
3681 *
3682 * # # Returned Buffer Content Pipe Content
3683 * r, w = IO.pipe #
3684 * w << 'abc' # "" "abc".
3685 * r.readpartial(4096) # => "abc" "" ""
3686 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3687 *
3688 * # # Returned Buffer Content Pipe Content
3689 * r, w = IO.pipe #
3690 * w << 'abc' # "" "abc"
3691 * w.close # "" "abc" EOF
3692 * r.readpartial(4096) # => "abc" "" EOF
3693 * r.readpartial(4096) # raises EOFError
3694 *
3695 * # # Returned Buffer Content Pipe Content
3696 * r, w = IO.pipe #
3697 * w << "abc\ndef\n" # "" "abc\ndef\n"
3698 * r.gets # => "abc\n" "def\n" ""
3699 * w << "ghi\n" # "def\n" "ghi\n"
3700 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3701 * r.readpartial(4096) # => "ghi\n" "" ""
3702 *
3703 */
3704
3705static VALUE
3706io_readpartial(int argc, VALUE *argv, VALUE io)
3707{
3708 VALUE ret;
3709
3710 ret = io_getpartial(argc, argv, io, Qnil, 0);
3711 if (NIL_P(ret))
3712 rb_eof_error();
3713 return ret;
3714}
3715
3716static VALUE
3717io_nonblock_eof(int no_exception)
3718{
3719 if (!no_exception) {
3720 rb_eof_error();
3721 }
3722 return Qnil;
3723}
3724
3725/* :nodoc: */
3726static VALUE
3727io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3728{
3729 rb_io_t *fptr;
3730 long n, len;
3731 struct io_internal_read_struct iis;
3732 int shrinkable;
3733
3734 if ((len = NUM2LONG(length)) < 0) {
3735 rb_raise(rb_eArgError, "negative length %ld given", len);
3736 }
3737
3738 shrinkable = io_setstrbuf(&str, len);
3739 rb_bool_expected(ex, "exception", TRUE);
3740
3741 GetOpenFile(io, fptr);
3743
3744 if (len == 0) {
3745 io_set_read_length(str, 0, shrinkable);
3746 return str;
3747 }
3748
3749 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3750 if (n <= 0) {
3751 rb_fd_set_nonblock(fptr->fd);
3752 shrinkable |= io_setstrbuf(&str, len);
3753 iis.fptr = fptr;
3754 iis.nonblock = 1;
3755 iis.fd = fptr->fd;
3756 iis.buf = RSTRING_PTR(str);
3757 iis.capa = len;
3758 iis.timeout = NULL;
3759 n = io_read_memory_locktmp(str, &iis);
3760 if (n < 0) {
3761 int e = errno;
3762 if (io_again_p(e)) {
3763 if (!ex) return sym_wait_readable;
3764 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3765 e, "read would block");
3766 }
3767 rb_syserr_fail_path(e, fptr->pathv);
3768 }
3769 }
3770 io_set_read_length(str, n, shrinkable);
3771
3772 if (n == 0) {
3773 if (!ex) return Qnil;
3774 rb_eof_error();
3775 }
3776
3777 return str;
3778}
3779
3780/* :nodoc: */
3781static VALUE
3782io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3783{
3784 rb_io_t *fptr;
3785 long n;
3786
3787 if (!RB_TYPE_P(str, T_STRING))
3788 str = rb_obj_as_string(str);
3789 rb_bool_expected(ex, "exception", TRUE);
3790
3791 io = GetWriteIO(io);
3792 GetOpenFile(io, fptr);
3794
3795 if (io_fflush(fptr) < 0)
3796 rb_sys_fail_on_write(fptr);
3797
3798 rb_fd_set_nonblock(fptr->fd);
3799 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3800 RB_GC_GUARD(str);
3801
3802 if (n < 0) {
3803 int e = errno;
3804 if (io_again_p(e)) {
3805 if (!ex) {
3806 return sym_wait_writable;
3807 }
3808 else {
3809 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3810 }
3811 }
3812 rb_syserr_fail_path(e, fptr->pathv);
3813 }
3814
3815 return LONG2FIX(n);
3816}
3817
3818/*
3819 * call-seq:
3820 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3821 *
3822 * Reads bytes from the stream; the stream must be opened for reading
3823 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3824 *
3825 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3826 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3827 *
3828 * Returns a string (either a new string or the given +out_string+)
3829 * containing the bytes read.
3830 * The encoding of the string depends on both +maxLen+ and +out_string+:
3831 *
3832 * - +maxlen+ is +nil+: uses internal encoding of +self+
3833 * (regardless of whether +out_string+ was given).
3834 * - +maxlen+ not +nil+:
3835 *
3836 * - +out_string+ given: encoding of +out_string+ not modified.
3837 * - +out_string+ not given: ASCII-8BIT is used.
3838 *
3839 * <b>Without Argument +out_string+</b>
3840 *
3841 * When argument +out_string+ is omitted,
3842 * the returned value is a new string:
3843 *
3844 * f = File.new('t.txt')
3845 * f.read
3846 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3847 * f.rewind
3848 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3849 * f.read(30) # => "rth line\r\nFifth line\r\n"
3850 * f.read(30) # => nil
3851 * f.close
3852 *
3853 * If +maxlen+ is zero, returns an empty string.
3854 *
3855 * <b> With Argument +out_string+</b>
3856 *
3857 * When argument +out_string+ is given,
3858 * the returned value is +out_string+, whose content is replaced:
3859 *
3860 * f = File.new('t.txt')
3861 * s = 'foo' # => "foo"
3862 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3863 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3864 * f.rewind
3865 * s = 'bar'
3866 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3867 * s # => "First line\r\nSecond line\r\n\r\nFou"
3868 * s = 'baz'
3869 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3870 * s # => "rth line\r\nFifth line\r\n"
3871 * s = 'bat'
3872 * f.read(30, s) # => nil
3873 * s # => ""
3874 * f.close
3875 *
3876 * Note that this method behaves like the fread() function in C.
3877 * This means it retries to invoke read(2) system calls to read data
3878 * with the specified maxlen (or until EOF).
3879 *
3880 * This behavior is preserved even if the stream is in non-blocking mode.
3881 * (This method is non-blocking-flag insensitive as other methods.)
3882 *
3883 * If you need the behavior like a single read(2) system call,
3884 * consider #readpartial, #read_nonblock, and #sysread.
3885 *
3886 * Related: IO#write.
3887 */
3888
3889static VALUE
3890io_read(int argc, VALUE *argv, VALUE io)
3891{
3892 rb_io_t *fptr;
3893 long n, len;
3894 VALUE length, str;
3895 int shrinkable;
3896#if RUBY_CRLF_ENVIRONMENT
3897 int previous_mode;
3898#endif
3899
3900 rb_scan_args(argc, argv, "02", &length, &str);
3901
3902 if (NIL_P(length)) {
3903 GetOpenFile(io, fptr);
3905 return read_all(fptr, remain_size(fptr), str);
3906 }
3907 len = NUM2LONG(length);
3908 if (len < 0) {
3909 rb_raise(rb_eArgError, "negative length %ld given", len);
3910 }
3911
3912 shrinkable = io_setstrbuf(&str,len);
3913
3914 GetOpenFile(io, fptr);
3916 if (len == 0) {
3917 io_set_read_length(str, 0, shrinkable);
3918 return str;
3919 }
3920
3921 READ_CHECK(fptr);
3922#if RUBY_CRLF_ENVIRONMENT
3923 previous_mode = set_binary_mode_with_seek_cur(fptr);
3924#endif
3925 n = io_fread(str, 0, len, fptr);
3926 io_set_read_length(str, n, shrinkable);
3927#if RUBY_CRLF_ENVIRONMENT
3928 if (previous_mode == O_TEXT) {
3929 setmode(fptr->fd, O_TEXT);
3930 }
3931#endif
3932 if (n == 0) return Qnil;
3933
3934 return str;
3935}
3936
3937static void
3938rscheck(const char *rsptr, long rslen, VALUE rs)
3939{
3940 if (!rs) return;
3941 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3942 rb_raise(rb_eRuntimeError, "rs modified");
3943}
3944
3945static const char *
3946search_delim(const char *p, long len, int delim, rb_encoding *enc)
3947{
3948 if (rb_enc_mbminlen(enc) == 1) {
3949 p = memchr(p, delim, len);
3950 if (p) return p + 1;
3951 }
3952 else {
3953 const char *end = p + len;
3954 while (p < end) {
3955 int r = rb_enc_precise_mbclen(p, end, enc);
3956 if (!MBCLEN_CHARFOUND_P(r)) {
3957 p += rb_enc_mbminlen(enc);
3958 continue;
3959 }
3960 int n = MBCLEN_CHARFOUND_LEN(r);
3961 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3962 return p + n;
3963 }
3964 p += n;
3965 }
3966 }
3967 return NULL;
3968}
3969
3970static int
3971appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3972{
3973 VALUE str = *strp;
3974 long limit = *lp;
3975
3976 if (NEED_READCONV(fptr)) {
3977 SET_BINARY_MODE(fptr);
3978 make_readconv(fptr, 0);
3979 do {
3980 const char *p, *e;
3981 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3982 if (searchlen) {
3983 p = READ_CHAR_PENDING_PTR(fptr);
3984 if (0 < limit && limit < searchlen)
3985 searchlen = (int)limit;
3986 e = search_delim(p, searchlen, delim, enc);
3987 if (e) {
3988 int len = (int)(e-p);
3989 if (NIL_P(str))
3990 *strp = str = rb_str_new(p, len);
3991 else
3992 rb_str_buf_cat(str, p, len);
3993 fptr->cbuf.off += len;
3994 fptr->cbuf.len -= len;
3995 limit -= len;
3996 *lp = limit;
3997 return delim;
3998 }
3999
4000 if (NIL_P(str))
4001 *strp = str = rb_str_new(p, searchlen);
4002 else
4003 rb_str_buf_cat(str, p, searchlen);
4004 fptr->cbuf.off += searchlen;
4005 fptr->cbuf.len -= searchlen;
4006 limit -= searchlen;
4007
4008 if (limit == 0) {
4009 *lp = limit;
4010 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4011 }
4012 }
4013 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4014 clear_readconv(fptr);
4015 *lp = limit;
4016 return EOF;
4017 }
4018
4019 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4020 do {
4021 long pending = READ_DATA_PENDING_COUNT(fptr);
4022 if (pending > 0) {
4023 const char *p = READ_DATA_PENDING_PTR(fptr);
4024 const char *e;
4025 long last;
4026
4027 if (limit > 0 && pending > limit) pending = limit;
4028 e = search_delim(p, pending, delim, enc);
4029 if (e) pending = e - p;
4030 if (!NIL_P(str)) {
4031 last = RSTRING_LEN(str);
4032 rb_str_resize(str, last + pending);
4033 }
4034 else {
4035 last = 0;
4036 *strp = str = rb_str_buf_new(pending);
4037 rb_str_set_len(str, pending);
4038 }
4039 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
4040 limit -= pending;
4041 *lp = limit;
4042 if (e) return delim;
4043 if (limit == 0)
4044 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4045 }
4046 READ_CHECK(fptr);
4047 } while (io_fillbuf(fptr) >= 0);
4048 *lp = limit;
4049 return EOF;
4050}
4051
4052static inline int
4053swallow(rb_io_t *fptr, int term)
4054{
4055 if (NEED_READCONV(fptr)) {
4056 rb_encoding *enc = io_read_encoding(fptr);
4057 int needconv = rb_enc_mbminlen(enc) != 1;
4058 SET_BINARY_MODE(fptr);
4059 make_readconv(fptr, 0);
4060 do {
4061 size_t cnt;
4062 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4063 const char *p = READ_CHAR_PENDING_PTR(fptr);
4064 int i;
4065 if (!needconv) {
4066 if (*p != term) return TRUE;
4067 i = (int)cnt;
4068 while (--i && *++p == term);
4069 }
4070 else {
4071 const char *e = p + cnt;
4072 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
4073 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4074 i = (int)(e - p);
4075 }
4076 io_shift_cbuf(fptr, (int)cnt - i, NULL);
4077 }
4078 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4079 return FALSE;
4080 }
4081
4082 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4083 do {
4084 size_t cnt;
4085 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4086 char buf[1024];
4087 const char *p = READ_DATA_PENDING_PTR(fptr);
4088 int i;
4089 if (cnt > sizeof buf) cnt = sizeof buf;
4090 if (*p != term) return TRUE;
4091 i = (int)cnt;
4092 while (--i && *++p == term);
4093 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4094 rb_sys_fail_path(fptr->pathv);
4095 }
4096 READ_CHECK(fptr);
4097 } while (io_fillbuf(fptr) == 0);
4098 return FALSE;
4099}
4100
4101static VALUE
4102rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4103{
4104 VALUE str = Qnil;
4105 int len = 0;
4106 long pos = 0;
4107 int cr = 0;
4108
4109 do {
4110 int pending = READ_DATA_PENDING_COUNT(fptr);
4111
4112 if (pending > 0) {
4113 const char *p = READ_DATA_PENDING_PTR(fptr);
4114 const char *e;
4115 int chomplen = 0;
4116
4117 e = memchr(p, '\n', pending);
4118 if (e) {
4119 pending = (int)(e - p + 1);
4120 if (chomp) {
4121 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4122 }
4123 }
4124 if (NIL_P(str)) {
4125 str = rb_str_new(p, pending - chomplen);
4126 fptr->rbuf.off += pending;
4127 fptr->rbuf.len -= pending;
4128 }
4129 else {
4130 rb_str_resize(str, len + pending - chomplen);
4131 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4132 fptr->rbuf.off += chomplen;
4133 fptr->rbuf.len -= chomplen;
4134 if (pending == 1 && chomplen == 1 && len > 0) {
4135 if (RSTRING_PTR(str)[len-1] == '\r') {
4136 rb_str_resize(str, --len);
4137 break;
4138 }
4139 }
4140 }
4141 len += pending - chomplen;
4142 if (cr != ENC_CODERANGE_BROKEN)
4143 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4144 if (e) break;
4145 }
4146 READ_CHECK(fptr);
4147 } while (io_fillbuf(fptr) >= 0);
4148 if (NIL_P(str)) return Qnil;
4149
4150 str = io_enc_str(str, fptr);
4151 ENC_CODERANGE_SET(str, cr);
4152 fptr->lineno++;
4153
4154 return str;
4155}
4156
4158 VALUE io;
4159 VALUE rs;
4160 long limit;
4161 unsigned int chomp: 1;
4162};
4163
4164static void
4165extract_getline_opts(VALUE opts, struct getline_arg *args)
4166{
4167 int chomp = FALSE;
4168 if (!NIL_P(opts)) {
4169 static ID kwds[1];
4170 VALUE vchomp;
4171 if (!kwds[0]) {
4172 kwds[0] = rb_intern_const("chomp");
4173 }
4174 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4175 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4176 }
4177 args->chomp = chomp;
4178}
4179
4180static void
4181extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4182{
4183 VALUE rs = rb_rs, lim = Qnil;
4184
4185 if (argc == 1) {
4186 VALUE tmp = Qnil;
4187
4188 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4189 rs = tmp;
4190 }
4191 else {
4192 lim = argv[0];
4193 }
4194 }
4195 else if (2 <= argc) {
4196 rs = argv[0], lim = argv[1];
4197 if (!NIL_P(rs))
4198 StringValue(rs);
4199 }
4200 args->rs = rs;
4201 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4202}
4203
4204static void
4205check_getline_args(VALUE *rsp, long *limit, VALUE io)
4206{
4207 rb_io_t *fptr;
4208 VALUE rs = *rsp;
4209
4210 if (!NIL_P(rs)) {
4211 rb_encoding *enc_rs, *enc_io;
4212
4213 GetOpenFile(io, fptr);
4214 enc_rs = rb_enc_get(rs);
4215 enc_io = io_read_encoding(fptr);
4216 if (enc_io != enc_rs &&
4217 (!is_ascii_string(rs) ||
4218 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4219 if (rs == rb_default_rs) {
4220 rs = rb_enc_str_new(0, 0, enc_io);
4221 rb_str_buf_cat_ascii(rs, "\n");
4222 *rsp = rs;
4223 }
4224 else {
4225 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4226 rb_enc_name(enc_io),
4227 rb_enc_name(enc_rs));
4228 }
4229 }
4230 }
4231}
4232
4233static void
4234prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4235{
4236 VALUE opts;
4237 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4238 extract_getline_args(argc, argv, args);
4239 extract_getline_opts(opts, args);
4240 check_getline_args(&args->rs, &args->limit, io);
4241}
4242
4243static VALUE
4244rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4245{
4246 VALUE str = Qnil;
4247 int nolimit = 0;
4248 rb_encoding *enc;
4249
4251 if (NIL_P(rs) && limit < 0) {
4252 str = read_all(fptr, 0, Qnil);
4253 if (RSTRING_LEN(str) == 0) return Qnil;
4254 }
4255 else if (limit == 0) {
4256 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4257 }
4258 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4259 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4260 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4261 return rb_io_getline_fast(fptr, enc, chomp);
4262 }
4263 else {
4264 int c, newline = -1;
4265 const char *rsptr = 0;
4266 long rslen = 0;
4267 int rspara = 0;
4268 int extra_limit = 16;
4269 int chomp_cr = chomp;
4270
4271 SET_BINARY_MODE(fptr);
4272 enc = io_read_encoding(fptr);
4273
4274 if (!NIL_P(rs)) {
4275 rslen = RSTRING_LEN(rs);
4276 if (rslen == 0) {
4277 rsptr = "\n\n";
4278 rslen = 2;
4279 rspara = 1;
4280 swallow(fptr, '\n');
4281 rs = 0;
4282 if (!rb_enc_asciicompat(enc)) {
4283 rs = rb_usascii_str_new(rsptr, rslen);
4284 rs = rb_str_conv_enc(rs, 0, enc);
4285 OBJ_FREEZE(rs);
4286 rsptr = RSTRING_PTR(rs);
4287 rslen = RSTRING_LEN(rs);
4288 }
4289 newline = '\n';
4290 }
4291 else if (rb_enc_mbminlen(enc) == 1) {
4292 rsptr = RSTRING_PTR(rs);
4293 newline = (unsigned char)rsptr[rslen - 1];
4294 }
4295 else {
4296 rs = rb_str_conv_enc(rs, 0, enc);
4297 rsptr = RSTRING_PTR(rs);
4298 const char *e = rsptr + rslen;
4299 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4300 int n;
4301 newline = rb_enc_codepoint_len(last, e, &n, enc);
4302 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4303 }
4304 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4305 }
4306
4307 /* MS - Optimization */
4308 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4309 const char *s, *p, *pp, *e;
4310
4311 if (c == newline && RSTRING_LEN(str) >= rslen) {
4312 s = RSTRING_PTR(str);
4313 e = RSTRING_END(str);
4314 p = e - rslen;
4315 if (at_char_boundary(s, p, e, enc)) {
4316 if (!rspara) rscheck(rsptr, rslen, rs);
4317 if (memcmp(p, rsptr, rslen) == 0) {
4318 if (chomp) {
4319 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4320 rb_str_set_len(str, p - s);
4321 }
4322 break;
4323 }
4324 }
4325 }
4326 if (limit == 0) {
4327 s = RSTRING_PTR(str);
4328 p = RSTRING_END(str);
4329 pp = rb_enc_prev_char(s, p, p, enc);
4330 if (extra_limit && pp &&
4331 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4332 /* relax the limit while incomplete character.
4333 * extra_limit limits the relax length */
4334 limit = 1;
4335 extra_limit--;
4336 }
4337 else {
4338 nolimit = 1;
4339 break;
4340 }
4341 }
4342 }
4343
4344 if (rspara && c != EOF)
4345 swallow(fptr, '\n');
4346 if (!NIL_P(str))
4347 str = io_enc_str(str, fptr);
4348 }
4349
4350 if (!NIL_P(str) && !nolimit) {
4351 fptr->lineno++;
4352 }
4353
4354 return str;
4355}
4356
4357static VALUE
4358rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4359{
4360 rb_io_t *fptr;
4361 int old_lineno, new_lineno;
4362 VALUE str;
4363
4364 GetOpenFile(io, fptr);
4365 old_lineno = fptr->lineno;
4366 str = rb_io_getline_0(rs, limit, chomp, fptr);
4367 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4368 if (io == ARGF.current_file) {
4369 ARGF.lineno += new_lineno - old_lineno;
4370 ARGF.last_lineno = ARGF.lineno;
4371 }
4372 else {
4373 ARGF.last_lineno = new_lineno;
4374 }
4375 }
4376
4377 return str;
4378}
4379
4380static VALUE
4381rb_io_getline(int argc, VALUE *argv, VALUE io)
4382{
4383 struct getline_arg args;
4384
4385 prepare_getline_args(argc, argv, &args, io);
4386 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4387}
4388
4389VALUE
4391{
4392 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4393}
4394
4395VALUE
4396rb_io_gets_limit_internal(VALUE io, long limit)
4397{
4398 rb_io_t *fptr;
4399 GetOpenFile(io, fptr);
4400 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4401}
4402
4403VALUE
4404rb_io_gets_internal(VALUE io)
4405{
4406 return rb_io_gets_limit_internal(io, -1);
4407}
4408
4409/*
4410 * call-seq:
4411 * gets(sep = $/, chomp: false) -> string or nil
4412 * gets(limit, chomp: false) -> string or nil
4413 * gets(sep, limit, chomp: false) -> string or nil
4414 *
4415 * Reads and returns a line from the stream;
4416 * assigns the return value to <tt>$_</tt>.
4417 * See {Line IO}[rdoc-ref:IO@Line+IO].
4418 *
4419 * With no arguments given, returns the next line
4420 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4421 *
4422 * f = File.open('t.txt')
4423 * f.gets # => "First line\n"
4424 * $_ # => "First line\n"
4425 * f.gets # => "\n"
4426 * f.gets # => "Fourth line\n"
4427 * f.gets # => "Fifth line\n"
4428 * f.gets # => nil
4429 * f.close
4430 *
4431 * With only string argument +sep+ given,
4432 * returns the next line as determined by line separator +sep+,
4433 * or +nil+ if none;
4434 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4435 *
4436 * f = File.new('t.txt')
4437 * f.gets('l') # => "First l"
4438 * f.gets('li') # => "ine\nSecond li"
4439 * f.gets('lin') # => "ne\n\nFourth lin"
4440 * f.gets # => "e\n"
4441 * f.close
4442 *
4443 * The two special values for +sep+ are honored:
4444 *
4445 * f = File.new('t.txt')
4446 * # Get all.
4447 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4448 * f.rewind
4449 * # Get paragraph (up to two line separators).
4450 * f.gets('') # => "First line\nSecond line\n\n"
4451 * f.close
4452 *
4453 * With only integer argument +limit+ given,
4454 * limits the number of bytes in the line;
4455 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4456 *
4457 * # No more than one line.
4458 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4459 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4460 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4461 *
4462 * With arguments +sep+ and +limit+ given,
4463 * combines the two behaviors
4464 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4465 *
4466 * Optional keyword argument +chomp+ specifies whether line separators
4467 * are to be omitted:
4468 *
4469 * f = File.open('t.txt')
4470 * # Chomp the lines.
4471 * f.gets(chomp: true) # => "First line"
4472 * f.gets(chomp: true) # => "Second line"
4473 * f.gets(chomp: true) # => ""
4474 * f.gets(chomp: true) # => "Fourth line"
4475 * f.gets(chomp: true) # => "Fifth line"
4476 * f.gets(chomp: true) # => nil
4477 * f.close
4478 *
4479 */
4480
4481static VALUE
4482rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4483{
4484 VALUE str;
4485
4486 str = rb_io_getline(argc, argv, io);
4487 rb_lastline_set(str);
4488
4489 return str;
4490}
4491
4492/*
4493 * call-seq:
4494 * lineno -> integer
4495 *
4496 * Returns the current line number for the stream;
4497 * see {Line Number}[rdoc-ref:IO@Line+Number].
4498 *
4499 */
4500
4501static VALUE
4502rb_io_lineno(VALUE io)
4503{
4504 rb_io_t *fptr;
4505
4506 GetOpenFile(io, fptr);
4508 return INT2NUM(fptr->lineno);
4509}
4510
4511/*
4512 * call-seq:
4513 * lineno = integer -> integer
4514 *
4515 * Sets and returns the line number for the stream;
4516 * see {Line Number}[rdoc-ref:IO@Line+Number].
4517 *
4518 */
4519
4520static VALUE
4521rb_io_set_lineno(VALUE io, VALUE lineno)
4522{
4523 rb_io_t *fptr;
4524
4525 GetOpenFile(io, fptr);
4527 fptr->lineno = NUM2INT(lineno);
4528 return lineno;
4529}
4530
4531/* :nodoc: */
4532static VALUE
4533io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4534{
4535 long limit = -1;
4536 if (NIL_P(lim)) {
4537 VALUE tmp = Qnil;
4538 // If sep is specified, but it's not a string and not nil, then assume
4539 // it's the limit (it should be an integer)
4540 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4541 // If the user has specified a non-nil / non-string value
4542 // for the separator, we assume it's the limit and set the
4543 // separator to default: rb_rs.
4544 lim = sep;
4545 limit = NUM2LONG(lim);
4546 sep = rb_rs;
4547 }
4548 else {
4549 sep = tmp;
4550 }
4551 }
4552 else {
4553 if (!NIL_P(sep)) StringValue(sep);
4554 limit = NUM2LONG(lim);
4555 }
4556
4557 check_getline_args(&sep, &limit, io);
4558
4559 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4560 rb_lastline_set_up(line, 1);
4561
4562 if (NIL_P(line)) {
4563 rb_eof_error();
4564 }
4565 return line;
4566}
4567
4568static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4569
4570/*
4571 * call-seq:
4572 * readlines(sep = $/, chomp: false) -> array
4573 * readlines(limit, chomp: false) -> array
4574 * readlines(sep, limit, chomp: false) -> array
4575 *
4576 * Reads and returns all remaining line from the stream;
4577 * does not modify <tt>$_</tt>.
4578 * See {Line IO}[rdoc-ref:IO@Line+IO].
4579 *
4580 * With no arguments given, returns lines
4581 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4582 *
4583 * f = File.new('t.txt')
4584 * f.readlines
4585 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4586 * f.readlines # => []
4587 * f.close
4588 *
4589 * With only string argument +sep+ given,
4590 * returns lines as determined by line separator +sep+,
4591 * or +nil+ if none;
4592 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4593 *
4594 * f = File.new('t.txt')
4595 * f.readlines('li')
4596 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4597 * f.close
4598 *
4599 * The two special values for +sep+ are honored:
4600 *
4601 * f = File.new('t.txt')
4602 * # Get all into one string.
4603 * f.readlines(nil)
4604 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4605 * # Get paragraphs (up to two line separators).
4606 * f.rewind
4607 * f.readlines('')
4608 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4609 * f.close
4610 *
4611 * With only integer argument +limit+ given,
4612 * limits the number of bytes in each line;
4613 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4614 *
4615 * f = File.new('t.txt')
4616 * f.readlines(8)
4617 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4618 * f.close
4619 *
4620 * With arguments +sep+ and +limit+ given,
4621 * combines the two behaviors
4622 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4623 *
4624 * Optional keyword argument +chomp+ specifies whether line separators
4625 * are to be omitted:
4626 *
4627 * f = File.new('t.txt')
4628 * f.readlines(chomp: true)
4629 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4630 * f.close
4631 *
4632 */
4633
4634static VALUE
4635rb_io_readlines(int argc, VALUE *argv, VALUE io)
4636{
4637 struct getline_arg args;
4638
4639 prepare_getline_args(argc, argv, &args, io);
4640 return io_readlines(&args, io);
4641}
4642
4643static VALUE
4644io_readlines(const struct getline_arg *arg, VALUE io)
4645{
4646 VALUE line, ary;
4647
4648 if (arg->limit == 0)
4649 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4650 ary = rb_ary_new();
4651 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4652 rb_ary_push(ary, line);
4653 }
4654 return ary;
4655}
4656
4657/*
4658 * call-seq:
4659 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4660 * each_line(limit, chomp: false) {|line| ... } -> self
4661 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4662 * each_line -> enumerator
4663 *
4664 * Calls the block with each remaining line read from the stream;
4665 * returns +self+.
4666 * Does nothing if already at end-of-stream;
4667 * See {Line IO}[rdoc-ref:IO@Line+IO].
4668 *
4669 * With no arguments given, reads lines
4670 * as determined by line separator <tt>$/</tt>:
4671 *
4672 * f = File.new('t.txt')
4673 * f.each_line {|line| p line }
4674 * f.each_line {|line| fail 'Cannot happen' }
4675 * f.close
4676 *
4677 * Output:
4678 *
4679 * "First line\n"
4680 * "Second line\n"
4681 * "\n"
4682 * "Fourth line\n"
4683 * "Fifth line\n"
4684 *
4685 * With only string argument +sep+ given,
4686 * reads lines as determined by line separator +sep+;
4687 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4688 *
4689 * f = File.new('t.txt')
4690 * f.each_line('li') {|line| p line }
4691 * f.close
4692 *
4693 * Output:
4694 *
4695 * "First li"
4696 * "ne\nSecond li"
4697 * "ne\n\nFourth li"
4698 * "ne\nFifth li"
4699 * "ne\n"
4700 *
4701 * The two special values for +sep+ are honored:
4702 *
4703 * f = File.new('t.txt')
4704 * # Get all into one string.
4705 * f.each_line(nil) {|line| p line }
4706 * f.close
4707 *
4708 * Output:
4709 *
4710 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4711 *
4712 * f.rewind
4713 * # Get paragraphs (up to two line separators).
4714 * f.each_line('') {|line| p line }
4715 *
4716 * Output:
4717 *
4718 * "First line\nSecond line\n\n"
4719 * "Fourth line\nFifth line\n"
4720 *
4721 * With only integer argument +limit+ given,
4722 * limits the number of bytes in each line;
4723 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4724 *
4725 * f = File.new('t.txt')
4726 * f.each_line(8) {|line| p line }
4727 * f.close
4728 *
4729 * Output:
4730 *
4731 * "First li"
4732 * "ne\n"
4733 * "Second l"
4734 * "ine\n"
4735 * "\n"
4736 * "Fourth l"
4737 * "ine\n"
4738 * "Fifth li"
4739 * "ne\n"
4740 *
4741 * With arguments +sep+ and +limit+ given,
4742 * combines the two behaviors
4743 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4744 *
4745 * Optional keyword argument +chomp+ specifies whether line separators
4746 * are to be omitted:
4747 *
4748 * f = File.new('t.txt')
4749 * f.each_line(chomp: true) {|line| p line }
4750 * f.close
4751 *
4752 * Output:
4753 *
4754 * "First line"
4755 * "Second line"
4756 * ""
4757 * "Fourth line"
4758 * "Fifth line"
4759 *
4760 * Returns an Enumerator if no block is given.
4761 */
4762
4763static VALUE
4764rb_io_each_line(int argc, VALUE *argv, VALUE io)
4765{
4766 VALUE str;
4767 struct getline_arg args;
4768
4769 RETURN_ENUMERATOR(io, argc, argv);
4770 prepare_getline_args(argc, argv, &args, io);
4771 if (args.limit == 0)
4772 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4773 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4774 rb_yield(str);
4775 }
4776 return io;
4777}
4778
4779/*
4780 * call-seq:
4781 * each_byte {|byte| ... } -> self
4782 * each_byte -> enumerator
4783 *
4784 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4785 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4786 *
4787 * f = File.new('t.rus')
4788 * a = []
4789 * f.each_byte {|b| a << b }
4790 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4791 * f.close
4792 *
4793 * Returns an Enumerator if no block is given.
4794 *
4795 * Related: IO#each_char, IO#each_codepoint.
4796 *
4797 */
4798
4799static VALUE
4800rb_io_each_byte(VALUE io)
4801{
4802 rb_io_t *fptr;
4803
4804 RETURN_ENUMERATOR(io, 0, 0);
4805 GetOpenFile(io, fptr);
4806
4807 do {
4808 while (fptr->rbuf.len > 0) {
4809 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4810 fptr->rbuf.len--;
4811 rb_yield(INT2FIX(*p & 0xff));
4813 errno = 0;
4814 }
4815 READ_CHECK(fptr);
4816 } while (io_fillbuf(fptr) >= 0);
4817 return io;
4818}
4819
4820static VALUE
4821io_getc(rb_io_t *fptr, rb_encoding *enc)
4822{
4823 int r, n, cr = 0;
4824 VALUE str;
4825
4826 if (NEED_READCONV(fptr)) {
4827 rb_encoding *read_enc = io_read_encoding(fptr);
4828
4829 str = Qnil;
4830 SET_BINARY_MODE(fptr);
4831 make_readconv(fptr, 0);
4832
4833 while (1) {
4834 if (fptr->cbuf.len) {
4835 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4836 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4837 read_enc);
4838 if (!MBCLEN_NEEDMORE_P(r))
4839 break;
4840 if (fptr->cbuf.len == fptr->cbuf.capa) {
4841 rb_raise(rb_eIOError, "too long character");
4842 }
4843 }
4844
4845 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4846 if (fptr->cbuf.len == 0) {
4847 clear_readconv(fptr);
4848 return Qnil;
4849 }
4850 /* return an unit of an incomplete character just before EOF */
4851 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4852 fptr->cbuf.off += 1;
4853 fptr->cbuf.len -= 1;
4854 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4856 return str;
4857 }
4858 }
4859 if (MBCLEN_INVALID_P(r)) {
4860 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4861 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4862 read_enc);
4863 io_shift_cbuf(fptr, r, &str);
4865 }
4866 else {
4867 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4869 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4870 ISASCII(RSTRING_PTR(str)[0])) {
4871 cr = ENC_CODERANGE_7BIT;
4872 }
4873 }
4874 str = io_enc_str(str, fptr);
4875 ENC_CODERANGE_SET(str, cr);
4876 return str;
4877 }
4878
4879 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4880 if (io_fillbuf(fptr) < 0) {
4881 return Qnil;
4882 }
4883 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4884 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4885 fptr->rbuf.off += 1;
4886 fptr->rbuf.len -= 1;
4887 cr = ENC_CODERANGE_7BIT;
4888 }
4889 else {
4890 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4891 if (MBCLEN_CHARFOUND_P(r) &&
4892 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4893 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4894 fptr->rbuf.off += n;
4895 fptr->rbuf.len -= n;
4897 }
4898 else if (MBCLEN_NEEDMORE_P(r)) {
4899 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4900 fptr->rbuf.len = 0;
4901 getc_needmore:
4902 if (io_fillbuf(fptr) != -1) {
4903 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4904 fptr->rbuf.off++;
4905 fptr->rbuf.len--;
4906 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4907 if (MBCLEN_NEEDMORE_P(r)) {
4908 goto getc_needmore;
4909 }
4910 else if (MBCLEN_CHARFOUND_P(r)) {
4912 }
4913 }
4914 }
4915 else {
4916 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4917 fptr->rbuf.off++;
4918 fptr->rbuf.len--;
4919 }
4920 }
4921 if (!cr) cr = ENC_CODERANGE_BROKEN;
4922 str = io_enc_str(str, fptr);
4923 ENC_CODERANGE_SET(str, cr);
4924 return str;
4925}
4926
4927/*
4928 * call-seq:
4929 * each_char {|c| ... } -> self
4930 * each_char -> enumerator
4931 *
4932 * Calls the given block with each character in the stream; returns +self+.
4933 * See {Character IO}[rdoc-ref:IO@Character+IO].
4934 *
4935 * f = File.new('t.rus')
4936 * a = []
4937 * f.each_char {|c| a << c.ord }
4938 * a # => [1090, 1077, 1089, 1090]
4939 * f.close
4940 *
4941 * Returns an Enumerator if no block is given.
4942 *
4943 * Related: IO#each_byte, IO#each_codepoint.
4944 *
4945 */
4946
4947static VALUE
4948rb_io_each_char(VALUE io)
4949{
4950 rb_io_t *fptr;
4951 rb_encoding *enc;
4952 VALUE c;
4953
4954 RETURN_ENUMERATOR(io, 0, 0);
4955 GetOpenFile(io, fptr);
4957
4958 enc = io_input_encoding(fptr);
4959 READ_CHECK(fptr);
4960 while (!NIL_P(c = io_getc(fptr, enc))) {
4961 rb_yield(c);
4962 }
4963 return io;
4964}
4965
4966/*
4967 * call-seq:
4968 * each_codepoint {|c| ... } -> self
4969 * each_codepoint -> enumerator
4970 *
4971 * Calls the given block with each codepoint in the stream; returns +self+:
4972 *
4973 * f = File.new('t.rus')
4974 * a = []
4975 * f.each_codepoint {|c| a << c }
4976 * a # => [1090, 1077, 1089, 1090]
4977 * f.close
4978 *
4979 * Returns an Enumerator if no block is given.
4980 *
4981 * Related: IO#each_byte, IO#each_char.
4982 *
4983 */
4984
4985static VALUE
4986rb_io_each_codepoint(VALUE io)
4987{
4988 rb_io_t *fptr;
4989 rb_encoding *enc;
4990 unsigned int c;
4991 int r, n;
4992
4993 RETURN_ENUMERATOR(io, 0, 0);
4994 GetOpenFile(io, fptr);
4996
4997 READ_CHECK(fptr);
4998 enc = io_read_encoding(fptr);
4999 if (NEED_READCONV(fptr)) {
5000 SET_BINARY_MODE(fptr);
5001 r = 1; /* no invalid char yet */
5002 for (;;) {
5003 make_readconv(fptr, 0);
5004 for (;;) {
5005 if (fptr->cbuf.len) {
5006 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
5007 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5008 enc);
5009 if (!MBCLEN_NEEDMORE_P(r))
5010 break;
5011 if (fptr->cbuf.len == fptr->cbuf.capa) {
5012 rb_raise(rb_eIOError, "too long character");
5013 }
5014 }
5015 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5016 clear_readconv(fptr);
5017 if (!MBCLEN_CHARFOUND_P(r)) {
5018 goto invalid;
5019 }
5020 return io;
5021 }
5022 }
5023 if (MBCLEN_INVALID_P(r)) {
5024 goto invalid;
5025 }
5026 n = MBCLEN_CHARFOUND_LEN(r);
5027 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
5028 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5029 enc);
5030 fptr->cbuf.off += n;
5031 fptr->cbuf.len -= n;
5032 rb_yield(UINT2NUM(c));
5034 }
5035 }
5036 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5037 while (io_fillbuf(fptr) >= 0) {
5038 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
5039 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5040 if (MBCLEN_CHARFOUND_P(r) &&
5041 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
5042 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
5043 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5044 fptr->rbuf.off += n;
5045 fptr->rbuf.len -= n;
5046 rb_yield(UINT2NUM(c));
5047 }
5048 else if (MBCLEN_INVALID_P(r)) {
5049 goto invalid;
5050 }
5051 else if (MBCLEN_NEEDMORE_P(r)) {
5052 char cbuf[8], *p = cbuf;
5053 int more = MBCLEN_NEEDMORE_LEN(r);
5054 if (more > numberof(cbuf)) goto invalid;
5055 more += n = fptr->rbuf.len;
5056 if (more > numberof(cbuf)) goto invalid;
5057 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
5058 (p += n, (more -= n) > 0)) {
5059 if (io_fillbuf(fptr) < 0) goto invalid;
5060 if ((n = fptr->rbuf.len) > more) n = more;
5061 }
5062 r = rb_enc_precise_mbclen(cbuf, p, enc);
5063 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
5064 c = rb_enc_codepoint(cbuf, p, enc);
5065 rb_yield(UINT2NUM(c));
5066 }
5067 else {
5068 continue;
5069 }
5071 }
5072 return io;
5073
5074 invalid:
5075 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
5077}
5078
5079/*
5080 * call-seq:
5081 * getc -> character or nil
5082 *
5083 * Reads and returns the next 1-character string from the stream;
5084 * returns +nil+ if already at end-of-stream.
5085 * See {Character IO}[rdoc-ref:IO@Character+IO].
5086 *
5087 * f = File.open('t.txt')
5088 * f.getc # => "F"
5089 * f.close
5090 * f = File.open('t.rus')
5091 * f.getc.ord # => 1090
5092 * f.close
5093 *
5094 * Related: IO#readchar (may raise EOFError).
5095 *
5096 */
5097
5098static VALUE
5099rb_io_getc(VALUE io)
5100{
5101 rb_io_t *fptr;
5102 rb_encoding *enc;
5103
5104 GetOpenFile(io, fptr);
5106
5107 enc = io_input_encoding(fptr);
5108 READ_CHECK(fptr);
5109 return io_getc(fptr, enc);
5110}
5111
5112/*
5113 * call-seq:
5114 * readchar -> string
5115 *
5116 * Reads and returns the next 1-character string from the stream;
5117 * raises EOFError if already at end-of-stream.
5118 * See {Character IO}[rdoc-ref:IO@Character+IO].
5119 *
5120 * f = File.open('t.txt')
5121 * f.readchar # => "F"
5122 * f.close
5123 * f = File.open('t.rus')
5124 * f.readchar.ord # => 1090
5125 * f.close
5126 *
5127 * Related: IO#getc (will not raise EOFError).
5128 *
5129 */
5130
5131static VALUE
5132rb_io_readchar(VALUE io)
5133{
5134 VALUE c = rb_io_getc(io);
5135
5136 if (NIL_P(c)) {
5137 rb_eof_error();
5138 }
5139 return c;
5140}
5141
5142/*
5143 * call-seq:
5144 * getbyte -> integer or nil
5145 *
5146 * Reads and returns the next byte (in range 0..255) from the stream;
5147 * returns +nil+ if already at end-of-stream.
5148 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5149 *
5150 * f = File.open('t.txt')
5151 * f.getbyte # => 70
5152 * f.close
5153 * f = File.open('t.rus')
5154 * f.getbyte # => 209
5155 * f.close
5156 *
5157 * Related: IO#readbyte (may raise EOFError).
5158 */
5159
5160VALUE
5162{
5163 rb_io_t *fptr;
5164 int c;
5165
5166 GetOpenFile(io, fptr);
5168 READ_CHECK(fptr);
5169 VALUE r_stdout = rb_ractor_stdout();
5170 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5171 rb_io_t *ofp;
5172 GetOpenFile(r_stdout, ofp);
5173 if (ofp->mode & FMODE_TTY) {
5174 rb_io_flush(r_stdout);
5175 }
5176 }
5177 if (io_fillbuf(fptr) < 0) {
5178 return Qnil;
5179 }
5180 fptr->rbuf.off++;
5181 fptr->rbuf.len--;
5182 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5183 return INT2FIX(c & 0xff);
5184}
5185
5186/*
5187 * call-seq:
5188 * readbyte -> integer
5189 *
5190 * Reads and returns the next byte (in range 0..255) from the stream;
5191 * raises EOFError if already at end-of-stream.
5192 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5193 *
5194 * f = File.open('t.txt')
5195 * f.readbyte # => 70
5196 * f.close
5197 * f = File.open('t.rus')
5198 * f.readbyte # => 209
5199 * f.close
5200 *
5201 * Related: IO#getbyte (will not raise EOFError).
5202 *
5203 */
5204
5205static VALUE
5206rb_io_readbyte(VALUE io)
5207{
5208 VALUE c = rb_io_getbyte(io);
5209
5210 if (NIL_P(c)) {
5211 rb_eof_error();
5212 }
5213 return c;
5214}
5215
5216/*
5217 * call-seq:
5218 * ungetbyte(integer) -> nil
5219 * ungetbyte(string) -> nil
5220 *
5221 * Pushes back ("unshifts") the given data onto the stream's buffer,
5222 * placing the data so that it is next to be read; returns +nil+.
5223 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5224 *
5225 * Note that:
5226 *
5227 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5228 * - Calling #rewind on the stream discards the pushed-back data.
5229 *
5230 * When argument +integer+ is given, uses only its low-order byte:
5231 *
5232 * File.write('t.tmp', '012')
5233 * f = File.open('t.tmp')
5234 * f.ungetbyte(0x41) # => nil
5235 * f.read # => "A012"
5236 * f.rewind
5237 * f.ungetbyte(0x4243) # => nil
5238 * f.read # => "C012"
5239 * f.close
5240 *
5241 * When argument +string+ is given, uses all bytes:
5242 *
5243 * File.write('t.tmp', '012')
5244 * f = File.open('t.tmp')
5245 * f.ungetbyte('A') # => nil
5246 * f.read # => "A012"
5247 * f.rewind
5248 * f.ungetbyte('BCDE') # => nil
5249 * f.read # => "BCDE012"
5250 * f.close
5251 *
5252 */
5253
5254VALUE
5256{
5257 rb_io_t *fptr;
5258
5259 GetOpenFile(io, fptr);
5261 switch (TYPE(b)) {
5262 case T_NIL:
5263 return Qnil;
5264 case T_FIXNUM:
5265 case T_BIGNUM: ;
5266 VALUE v = rb_int_modulo(b, INT2FIX(256));
5267 unsigned char c = NUM2INT(v) & 0xFF;
5268 b = rb_str_new((const char *)&c, 1);
5269 break;
5270 default:
5271 StringValue(b);
5272 }
5273 io_ungetbyte(b, fptr);
5274 return Qnil;
5275}
5276
5277/*
5278 * call-seq:
5279 * ungetc(integer) -> nil
5280 * ungetc(string) -> nil
5281 *
5282 * Pushes back ("unshifts") the given data onto the stream's buffer,
5283 * placing the data so that it is next to be read; returns +nil+.
5284 * See {Character IO}[rdoc-ref:IO@Character+IO].
5285 *
5286 * Note that:
5287 *
5288 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5289 * - Calling #rewind on the stream discards the pushed-back data.
5290 *
5291 * When argument +integer+ is given, interprets the integer as a character:
5292 *
5293 * File.write('t.tmp', '012')
5294 * f = File.open('t.tmp')
5295 * f.ungetc(0x41) # => nil
5296 * f.read # => "A012"
5297 * f.rewind
5298 * f.ungetc(0x0442) # => nil
5299 * f.getc.ord # => 1090
5300 * f.close
5301 *
5302 * When argument +string+ is given, uses all characters:
5303 *
5304 * File.write('t.tmp', '012')
5305 * f = File.open('t.tmp')
5306 * f.ungetc('A') # => nil
5307 * f.read # => "A012"
5308 * f.rewind
5309 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5310 * f.getc.ord # => 1090
5311 * f.getc.ord # => 1077
5312 * f.getc.ord # => 1089
5313 * f.getc.ord # => 1090
5314 * f.close
5315 *
5316 */
5317
5318VALUE
5320{
5321 rb_io_t *fptr;
5322 long len;
5323
5324 GetOpenFile(io, fptr);
5326 if (FIXNUM_P(c)) {
5327 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5328 }
5329 else if (RB_BIGNUM_TYPE_P(c)) {
5330 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5331 }
5332 else {
5333 StringValue(c);
5334 }
5335 if (NEED_READCONV(fptr)) {
5336 SET_BINARY_MODE(fptr);
5337 len = RSTRING_LEN(c);
5338#if SIZEOF_LONG > SIZEOF_INT
5339 if (len > INT_MAX)
5340 rb_raise(rb_eIOError, "ungetc failed");
5341#endif
5342 make_readconv(fptr, (int)len);
5343 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5344 rb_raise(rb_eIOError, "ungetc failed");
5345 if (fptr->cbuf.off < len) {
5346 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5347 fptr->cbuf.ptr+fptr->cbuf.off,
5348 char, fptr->cbuf.len);
5349 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5350 }
5351 fptr->cbuf.off -= (int)len;
5352 fptr->cbuf.len += (int)len;
5353 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5354 }
5355 else {
5356 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5357 io_ungetbyte(c, fptr);
5358 }
5359 return Qnil;
5360}
5361
5362/*
5363 * call-seq:
5364 * isatty -> true or false
5365 *
5366 * Returns +true+ if the stream is associated with a terminal device (tty),
5367 * +false+ otherwise:
5368 *
5369 * f = File.new('t.txt').isatty #=> false
5370 * f.close
5371 * f = File.new('/dev/tty').isatty #=> true
5372 * f.close
5373 *
5374 */
5375
5376static VALUE
5377rb_io_isatty(VALUE io)
5378{
5379 rb_io_t *fptr;
5380
5381 GetOpenFile(io, fptr);
5382 return RBOOL(isatty(fptr->fd) != 0);
5383}
5384
5385#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5386/*
5387 * call-seq:
5388 * close_on_exec? -> true or false
5389 *
5390 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5391 *
5392 * f = File.open('t.txt')
5393 * f.close_on_exec? # => true
5394 * f.close_on_exec = false
5395 * f.close_on_exec? # => false
5396 * f.close
5397 *
5398 */
5399
5400static VALUE
5401rb_io_close_on_exec_p(VALUE io)
5402{
5403 rb_io_t *fptr;
5404 VALUE write_io;
5405 int fd, ret;
5406
5407 write_io = GetWriteIO(io);
5408 if (io != write_io) {
5409 GetOpenFile(write_io, fptr);
5410 if (fptr && 0 <= (fd = fptr->fd)) {
5411 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5412 if (!(ret & FD_CLOEXEC)) return Qfalse;
5413 }
5414 }
5415
5416 GetOpenFile(io, fptr);
5417 if (fptr && 0 <= (fd = fptr->fd)) {
5418 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5419 if (!(ret & FD_CLOEXEC)) return Qfalse;
5420 }
5421 return Qtrue;
5422}
5423#else
5424#define rb_io_close_on_exec_p rb_f_notimplement
5425#endif
5426
5427#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5428/*
5429 * call-seq:
5430 * self.close_on_exec = bool -> true or false
5431 *
5432 * Sets a close-on-exec flag.
5433 *
5434 * f = File.open(File::NULL)
5435 * f.close_on_exec = true
5436 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5437 * f.closed? #=> false
5438 *
5439 * Ruby sets close-on-exec flags of all file descriptors by default
5440 * since Ruby 2.0.0.
5441 * So you don't need to set by yourself.
5442 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5443 * if another thread use fork() and exec() (via system() method for example).
5444 * If you really needs file descriptor inheritance to child process,
5445 * use spawn()'s argument such as fd=>fd.
5446 */
5447
5448static VALUE
5449rb_io_set_close_on_exec(VALUE io, VALUE arg)
5450{
5451 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5452 rb_io_t *fptr;
5453 VALUE write_io;
5454 int fd, ret;
5455
5456 write_io = GetWriteIO(io);
5457 if (io != write_io) {
5458 GetOpenFile(write_io, fptr);
5459 if (fptr && 0 <= (fd = fptr->fd)) {
5460 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5461 if ((ret & FD_CLOEXEC) != flag) {
5462 ret = (ret & ~FD_CLOEXEC) | flag;
5463 ret = fcntl(fd, F_SETFD, ret);
5464 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5465 }
5466 }
5467
5468 }
5469
5470 GetOpenFile(io, fptr);
5471 if (fptr && 0 <= (fd = fptr->fd)) {
5472 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5473 if ((ret & FD_CLOEXEC) != flag) {
5474 ret = (ret & ~FD_CLOEXEC) | flag;
5475 ret = fcntl(fd, F_SETFD, ret);
5476 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5477 }
5478 }
5479 return Qnil;
5480}
5481#else
5482#define rb_io_set_close_on_exec rb_f_notimplement
5483#endif
5484
5485#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5486#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5487
5488static VALUE
5489finish_writeconv(rb_io_t *fptr, int noalloc)
5490{
5491 unsigned char *ds, *dp, *de;
5493
5494 if (!fptr->wbuf.ptr) {
5495 unsigned char buf[1024];
5496
5498 while (res == econv_destination_buffer_full) {
5499 ds = dp = buf;
5500 de = buf + sizeof(buf);
5501 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5502 while (dp-ds) {
5503 size_t remaining = dp-ds;
5504 long result = rb_io_write_memory(fptr, ds, remaining);
5505
5506 if (result > 0) {
5507 ds += result;
5508 if ((size_t)result == remaining) break;
5509 }
5510 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5511 if (fptr->fd < 0)
5512 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5513 }
5514 else {
5515 return noalloc ? Qtrue : INT2NUM(errno);
5516 }
5517 }
5518 if (res == econv_invalid_byte_sequence ||
5519 res == econv_incomplete_input ||
5521 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5522 }
5523 }
5524
5525 return Qnil;
5526 }
5527
5529 while (res == econv_destination_buffer_full) {
5530 if (fptr->wbuf.len == fptr->wbuf.capa) {
5531 if (io_fflush(fptr) < 0) {
5532 return noalloc ? Qtrue : INT2NUM(errno);
5533 }
5534 }
5535
5536 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5537 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5538 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5539 fptr->wbuf.len += (int)(dp - ds);
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 return Qnil;
5547}
5548
5550 rb_io_t *fptr;
5551 int noalloc;
5552};
5553
5554static VALUE
5555finish_writeconv_sync(VALUE arg)
5556{
5557 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5558 return finish_writeconv(p->fptr, p->noalloc);
5559}
5560
5561static void*
5562nogvl_close(void *ptr)
5563{
5564 int *fd = ptr;
5565
5566 return (void*)(intptr_t)close(*fd);
5567}
5568
5569static int
5570maygvl_close(int fd, int keepgvl)
5571{
5572 if (keepgvl)
5573 return close(fd);
5574
5575 /*
5576 * close() may block for certain file types (NFS, SO_LINGER sockets,
5577 * inotify), so let other threads run.
5578 */
5579 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5580}
5581
5582static void*
5583nogvl_fclose(void *ptr)
5584{
5585 FILE *file = ptr;
5586
5587 return (void*)(intptr_t)fclose(file);
5588}
5589
5590static int
5591maygvl_fclose(FILE *file, int keepgvl)
5592{
5593 if (keepgvl)
5594 return fclose(file);
5595
5596 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5597}
5598
5599static void free_io_buffer(rb_io_buffer_t *buf);
5600
5601static void
5602fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5603{
5604 VALUE error = Qnil;
5605 int fd = fptr->fd;
5606 FILE *stdio_file = fptr->stdio_file;
5607 int mode = fptr->mode;
5608
5609 if (fptr->writeconv) {
5610 if (!NIL_P(fptr->write_lock) && !noraise) {
5611 struct finish_writeconv_arg arg;
5612 arg.fptr = fptr;
5613 arg.noalloc = noraise;
5614 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5615 }
5616 else {
5617 error = finish_writeconv(fptr, noraise);
5618 }
5619 }
5620 if (fptr->wbuf.len) {
5621 if (noraise) {
5622 io_flush_buffer_sync(fptr);
5623 }
5624 else {
5625 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5626 error = INT2NUM(errno);
5627 }
5628 }
5629 }
5630
5631 int done = 0;
5632
5633 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5634 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5635 done = 1;
5636 }
5637
5638 fptr->fd = -1;
5639 fptr->stdio_file = 0;
5641
5642 // Wait for blocking operations to ensure they do not hit EBADF:
5643 rb_thread_io_close_wait(fptr);
5644
5645 if (!done && stdio_file) {
5646 // stdio_file is deallocated anyway even if fclose failed.
5647 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5648 if (!noraise) {
5649 error = INT2NUM(errno);
5650 }
5651 }
5652
5653 done = 1;
5654 }
5655
5656 VALUE scheduler = rb_fiber_scheduler_current();
5657 if (!done && fd >= 0 && scheduler != Qnil) {
5658 VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
5659
5660 if (!UNDEF_P(result)) {
5661 done = RTEST(result);
5662 }
5663 }
5664
5665 if (!done && fd >= 0) {
5666 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5667 // We assumes it is closed.
5668
5669 keepgvl |= !(mode & FMODE_WRITABLE);
5670 keepgvl |= noraise;
5671 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5672 if (!noraise) {
5673 error = INT2NUM(errno);
5674 }
5675 }
5676
5677 done = 1;
5678 }
5679
5680 if (!NIL_P(error) && !noraise) {
5681 if (RB_INTEGER_TYPE_P(error))
5682 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5683 else
5684 rb_exc_raise(error);
5685 }
5686}
5687
5688static void
5689fptr_finalize(rb_io_t *fptr, int noraise)
5690{
5691 fptr_finalize_flush(fptr, noraise, FALSE);
5692 free_io_buffer(&fptr->rbuf);
5693 free_io_buffer(&fptr->wbuf);
5694 clear_codeconv(fptr);
5695}
5696
5697static void
5698rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5699{
5700 if (fptr->finalize) {
5701 (*fptr->finalize)(fptr, noraise);
5702 }
5703 else {
5704 fptr_finalize(fptr, noraise);
5705 }
5706}
5707
5708static void
5709free_io_buffer(rb_io_buffer_t *buf)
5710{
5711 if (buf->ptr) {
5712 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5713 buf->ptr = NULL;
5714 }
5715}
5716
5717static void
5718clear_readconv(rb_io_t *fptr)
5719{
5720 if (fptr->readconv) {
5721 rb_econv_close(fptr->readconv);
5722 fptr->readconv = NULL;
5723 }
5724 free_io_buffer(&fptr->cbuf);
5725}
5726
5727static void
5728clear_writeconv(rb_io_t *fptr)
5729{
5730 if (fptr->writeconv) {
5732 fptr->writeconv = NULL;
5733 }
5734 fptr->writeconv_initialized = 0;
5735}
5736
5737static void
5738clear_codeconv(rb_io_t *fptr)
5739{
5740 clear_readconv(fptr);
5741 clear_writeconv(fptr);
5742}
5743
5744static void
5745rb_io_fptr_cleanup_all(rb_io_t *fptr)
5746{
5747 fptr->pathv = Qnil;
5748 if (0 <= fptr->fd)
5749 rb_io_fptr_cleanup(fptr, TRUE);
5750 fptr->write_lock = Qnil;
5751 free_io_buffer(&fptr->rbuf);
5752 free_io_buffer(&fptr->wbuf);
5753 clear_codeconv(fptr);
5754}
5755
5756int
5758{
5759 if (!io) return 0;
5760 rb_io_fptr_cleanup_all(io);
5761 free(io);
5762
5763 return 1;
5764}
5765
5766size_t
5767rb_io_memsize(const rb_io_t *io)
5768{
5769 size_t size = sizeof(rb_io_t);
5770 size += io->rbuf.capa;
5771 size += io->wbuf.capa;
5772 size += io->cbuf.capa;
5773 if (io->readconv) size += rb_econv_memsize(io->readconv);
5774 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5775
5776 struct rb_io_blocking_operation *blocking_operation = 0;
5777
5778 // 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.
5779 rb_serial_t fork_generation = GET_VM()->fork_gen;
5780 if (io->fork_generation == fork_generation) {
5781 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5782 size += sizeof(struct rb_io_blocking_operation);
5783 }
5784 }
5785
5786 return size;
5787}
5788
5789#ifdef _WIN32
5790/* keep GVL while closing to prevent crash on Windows */
5791# define KEEPGVL TRUE
5792#else
5793# define KEEPGVL FALSE
5794#endif
5795
5796static rb_io_t *
5797io_close_fptr(VALUE io)
5798{
5799 rb_io_t *fptr;
5800 VALUE write_io;
5801 rb_io_t *write_fptr;
5802
5803 write_io = GetWriteIO(io);
5804 if (io != write_io) {
5805 write_fptr = RFILE(write_io)->fptr;
5806 if (write_fptr && 0 <= write_fptr->fd) {
5807 rb_io_fptr_cleanup(write_fptr, TRUE);
5808 }
5809 }
5810
5811 fptr = RFILE(io)->fptr;
5812 if (!fptr) return 0;
5813 if (fptr->fd < 0) return 0;
5814
5815 // This guards against multiple threads closing the same IO object:
5816 if (rb_thread_io_close_interrupt(fptr)) {
5817 /* calls close(fptr->fd): */
5818 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5819 }
5820
5821 rb_io_fptr_cleanup(fptr, FALSE);
5822 return fptr;
5823}
5824
5825static void
5826fptr_waitpid(rb_io_t *fptr, int nohang)
5827{
5828 int status;
5829 if (fptr->pid) {
5830 rb_last_status_clear();
5831 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5832 fptr->pid = 0;
5833 }
5834}
5835
5836VALUE
5838{
5839 rb_io_t *fptr = io_close_fptr(io);
5840 if (fptr) fptr_waitpid(fptr, 0);
5841 return Qnil;
5842}
5843
5844/*
5845 * call-seq:
5846 * close -> nil
5847 *
5848 * Closes the stream for both reading and writing
5849 * if open for either or both; returns +nil+.
5850 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5851 *
5852 * If the stream is open for writing, flushes any buffered writes
5853 * to the operating system before closing.
5854 *
5855 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5856 * (child exit status).
5857 *
5858 * It is not an error to close an IO object that has already been closed.
5859 * It just returns nil.
5860 *
5861 * Example:
5862 *
5863 * IO.popen('ruby', 'r+') do |pipe|
5864 * puts pipe.closed?
5865 * pipe.close
5866 * puts $?
5867 * puts pipe.closed?
5868 * end
5869 *
5870 * Output:
5871 *
5872 * false
5873 * pid 13760 exit 0
5874 * true
5875 *
5876 * Related: IO#close_read, IO#close_write, IO#closed?.
5877 */
5878
5879static VALUE
5880rb_io_close_m(VALUE io)
5881{
5882 rb_io_t *fptr = rb_io_get_fptr(io);
5883 if (fptr->fd < 0) {
5884 return Qnil;
5885 }
5886 rb_io_close(io);
5887 return Qnil;
5888}
5889
5890static VALUE
5891io_call_close(VALUE io)
5892{
5893 rb_check_funcall(io, rb_intern("close"), 0, 0);
5894 return io;
5895}
5896
5897static VALUE
5898ignore_closed_stream(VALUE io, VALUE exc)
5899{
5900 enum {mesg_len = sizeof(closed_stream)-1};
5901 VALUE mesg = rb_attr_get(exc, idMesg);
5902 if (!RB_TYPE_P(mesg, T_STRING) ||
5903 RSTRING_LEN(mesg) != mesg_len ||
5904 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5905 rb_exc_raise(exc);
5906 }
5907 return io;
5908}
5909
5910static VALUE
5911io_close(VALUE io)
5912{
5913 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5914 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5915 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5916 rb_eIOError, (VALUE)0);
5917 return io;
5918}
5919
5920/*
5921 * call-seq:
5922 * closed? -> true or false
5923 *
5924 * Returns +true+ if the stream is closed for both reading and writing,
5925 * +false+ otherwise.
5926 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5927 *
5928 * IO.popen('ruby', 'r+') do |pipe|
5929 * puts pipe.closed?
5930 * pipe.close_read
5931 * puts pipe.closed?
5932 * pipe.close_write
5933 * puts pipe.closed?
5934 * end
5935 *
5936 * Output:
5937 *
5938 * false
5939 * false
5940 * true
5941 *
5942 * Related: IO#close_read, IO#close_write, IO#close.
5943 */
5944VALUE
5946{
5947 rb_io_t *fptr;
5948 VALUE write_io;
5949 rb_io_t *write_fptr;
5950
5951 write_io = GetWriteIO(io);
5952 if (io != write_io) {
5953 write_fptr = RFILE(write_io)->fptr;
5954 if (write_fptr && 0 <= write_fptr->fd) {
5955 return Qfalse;
5956 }
5957 }
5958
5959 fptr = rb_io_get_fptr(io);
5960 return RBOOL(0 > fptr->fd);
5961}
5962
5963/*
5964 * call-seq:
5965 * close_read -> nil
5966 *
5967 * Closes the stream for reading if open for reading;
5968 * returns +nil+.
5969 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5970 *
5971 * If the stream was opened by IO.popen and is also closed for writing,
5972 * sets global variable <tt>$?</tt> (child exit status).
5973 *
5974 * Example:
5975 *
5976 * IO.popen('ruby', 'r+') do |pipe|
5977 * puts pipe.closed?
5978 * pipe.close_write
5979 * puts pipe.closed?
5980 * pipe.close_read
5981 * puts $?
5982 * puts pipe.closed?
5983 * end
5984 *
5985 * Output:
5986 *
5987 * false
5988 * false
5989 * pid 14748 exit 0
5990 * true
5991 *
5992 * Related: IO#close, IO#close_write, IO#closed?.
5993 */
5994
5995static VALUE
5996rb_io_close_read(VALUE io)
5997{
5998 rb_io_t *fptr;
5999 VALUE write_io;
6000
6001 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6002 if (fptr->fd < 0) return Qnil;
6003 if (is_socket(fptr->fd, fptr->pathv)) {
6004#ifndef SHUT_RD
6005# define SHUT_RD 0
6006#endif
6007 if (shutdown(fptr->fd, SHUT_RD) < 0)
6008 rb_sys_fail_path(fptr->pathv);
6009 fptr->mode &= ~FMODE_READABLE;
6010 if (!(fptr->mode & FMODE_WRITABLE))
6011 return rb_io_close(io);
6012 return Qnil;
6013 }
6014
6015 write_io = GetWriteIO(io);
6016 if (io != write_io) {
6017 rb_io_t *wfptr;
6018 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6019 wfptr->pid = fptr->pid;
6020 fptr->pid = 0;
6021 RFILE(io)->fptr = wfptr;
6022 /* bind to write_io temporarily to get rid of memory/fd leak */
6023 fptr->tied_io_for_writing = 0;
6024 RFILE(write_io)->fptr = fptr;
6025 rb_io_fptr_cleanup(fptr, FALSE);
6026 /* should not finalize fptr because another thread may be reading it */
6027 return Qnil;
6028 }
6029
6030 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
6031 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
6032 }
6033 return rb_io_close(io);
6034}
6035
6036/*
6037 * call-seq:
6038 * close_write -> nil
6039 *
6040 * Closes the stream for writing if open for writing;
6041 * returns +nil+.
6042 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6043 *
6044 * Flushes any buffered writes to the operating system before closing.
6045 *
6046 * If the stream was opened by IO.popen and is also closed for reading,
6047 * sets global variable <tt>$?</tt> (child exit status).
6048 *
6049 * IO.popen('ruby', 'r+') do |pipe|
6050 * puts pipe.closed?
6051 * pipe.close_read
6052 * puts pipe.closed?
6053 * pipe.close_write
6054 * puts $?
6055 * puts pipe.closed?
6056 * end
6057 *
6058 * Output:
6059 *
6060 * false
6061 * false
6062 * pid 15044 exit 0
6063 * true
6064 *
6065 * Related: IO#close, IO#close_read, IO#closed?.
6066 */
6067
6068static VALUE
6069rb_io_close_write(VALUE io)
6070{
6071 rb_io_t *fptr;
6072 VALUE write_io;
6073
6074 write_io = GetWriteIO(io);
6075 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6076 if (fptr->fd < 0) return Qnil;
6077 if (is_socket(fptr->fd, fptr->pathv)) {
6078#ifndef SHUT_WR
6079# define SHUT_WR 1
6080#endif
6081 if (shutdown(fptr->fd, SHUT_WR) < 0)
6082 rb_sys_fail_path(fptr->pathv);
6083 fptr->mode &= ~FMODE_WRITABLE;
6084 if (!(fptr->mode & FMODE_READABLE))
6085 return rb_io_close(write_io);
6086 return Qnil;
6087 }
6088
6089 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6090 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6091 }
6092
6093 if (io != write_io) {
6094 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6095 fptr->tied_io_for_writing = 0;
6096 }
6097 rb_io_close(write_io);
6098 return Qnil;
6099}
6100
6101/*
6102 * call-seq:
6103 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6104 *
6105 * Behaves like IO#seek, except that it:
6106 *
6107 * - Uses low-level system functions.
6108 * - Returns the new position.
6109 *
6110 */
6111
6112static VALUE
6113rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6114{
6115 VALUE offset, ptrname;
6116 int whence = SEEK_SET;
6117 rb_io_t *fptr;
6118 rb_off_t pos;
6119
6120 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6121 whence = interpret_seek_whence(ptrname);
6122 }
6123 pos = NUM2OFFT(offset);
6124 GetOpenFile(io, fptr);
6125 if ((fptr->mode & FMODE_READABLE) &&
6126 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6127 rb_raise(rb_eIOError, "sysseek for buffered IO");
6128 }
6129 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6130 rb_warn("sysseek for buffered IO");
6131 }
6132 errno = 0;
6133 pos = lseek(fptr->fd, pos, whence);
6134 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6135
6136 return OFFT2NUM(pos);
6137}
6138
6139/*
6140 * call-seq:
6141 * syswrite(object) -> integer
6142 *
6143 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6144 * returns the number bytes written.
6145 * If +object+ is not a string is converted via method to_s:
6146 *
6147 * f = File.new('t.tmp', 'w')
6148 * f.syswrite('foo') # => 3
6149 * f.syswrite(30) # => 2
6150 * f.syswrite(:foo) # => 3
6151 * f.close
6152 *
6153 * This methods should not be used with other stream-writer methods.
6154 *
6155 */
6156
6157static VALUE
6158rb_io_syswrite(VALUE io, VALUE str)
6159{
6160 VALUE tmp;
6161 rb_io_t *fptr;
6162 long n, len;
6163 const char *ptr;
6164
6165 if (!RB_TYPE_P(str, T_STRING))
6166 str = rb_obj_as_string(str);
6167
6168 io = GetWriteIO(io);
6169 GetOpenFile(io, fptr);
6171
6172 if (fptr->wbuf.len) {
6173 rb_warn("syswrite for buffered IO");
6174 }
6175
6176 tmp = rb_str_tmp_frozen_acquire(str);
6177 RSTRING_GETMEM(tmp, ptr, len);
6178 n = rb_io_write_memory(fptr, ptr, len);
6179 if (n < 0) rb_sys_fail_path(fptr->pathv);
6180 rb_str_tmp_frozen_release(str, tmp);
6181
6182 return LONG2FIX(n);
6183}
6184
6185/*
6186 * call-seq:
6187 * sysread(maxlen) -> string
6188 * sysread(maxlen, out_string) -> string
6189 *
6190 * Behaves like IO#readpartial, except that it uses low-level system functions.
6191 *
6192 * This method should not be used with other stream-reader methods.
6193 *
6194 */
6195
6196static VALUE
6197rb_io_sysread(int argc, VALUE *argv, VALUE io)
6198{
6199 VALUE len, str;
6200 rb_io_t *fptr;
6201 long n, ilen;
6202 struct io_internal_read_struct iis;
6203 int shrinkable;
6204
6205 rb_scan_args(argc, argv, "11", &len, &str);
6206 ilen = NUM2LONG(len);
6207
6208 shrinkable = io_setstrbuf(&str, ilen);
6209 if (ilen == 0) return str;
6210
6211 GetOpenFile(io, fptr);
6213
6214 if (READ_DATA_BUFFERED(fptr)) {
6215 rb_raise(rb_eIOError, "sysread for buffered IO");
6216 }
6217
6218 rb_io_check_closed(fptr);
6219
6220 io_setstrbuf(&str, ilen);
6221 iis.th = rb_thread_current();
6222 iis.fptr = fptr;
6223 iis.nonblock = 0;
6224 iis.fd = fptr->fd;
6225 iis.buf = RSTRING_PTR(str);
6226 iis.capa = ilen;
6227 iis.timeout = NULL;
6228 n = io_read_memory_locktmp(str, &iis);
6229
6230 if (n < 0) {
6231 rb_sys_fail_path(fptr->pathv);
6232 }
6233
6234 io_set_read_length(str, n, shrinkable);
6235
6236 if (n == 0 && ilen > 0) {
6237 rb_eof_error();
6238 }
6239
6240 return str;
6241}
6242
6244 struct rb_io *io;
6245 int fd;
6246 void *buf;
6247 size_t count;
6248 rb_off_t offset;
6249};
6250
6251static VALUE
6252internal_pread_func(void *_arg)
6253{
6254 struct prdwr_internal_arg *arg = _arg;
6255
6256 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6257}
6258
6259static VALUE
6260pread_internal_call(VALUE _arg)
6261{
6262 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6263
6264 VALUE scheduler = rb_fiber_scheduler_current();
6265 if (scheduler != Qnil) {
6266 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6267
6268 if (!UNDEF_P(result)) {
6269 return rb_fiber_scheduler_io_result_apply(result);
6270 }
6271 }
6272
6273 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6274}
6275
6276/*
6277 * call-seq:
6278 * pread(maxlen, offset) -> string
6279 * pread(maxlen, offset, out_string) -> string
6280 *
6281 * Behaves like IO#readpartial, except that it:
6282 *
6283 * - Reads at the given +offset+ (in bytes).
6284 * - Disregards, and does not modify, the stream's position
6285 * (see {Position}[rdoc-ref:IO@Position]).
6286 * - Bypasses any user space buffering in the stream.
6287 *
6288 * Because this method does not disturb the stream's state
6289 * (its position, in particular), +pread+ allows multiple threads and processes
6290 * to use the same \IO object for reading at various offsets.
6291 *
6292 * f = File.open('t.txt')
6293 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6294 * f.pos # => 52
6295 * # Read 12 bytes at offset 0.
6296 * f.pread(12, 0) # => "First line\n"
6297 * # Read 9 bytes at offset 8.
6298 * f.pread(9, 8) # => "ne\nSecon"
6299 * f.close
6300 *
6301 * Not available on some platforms.
6302 *
6303 */
6304static VALUE
6305rb_io_pread(int argc, VALUE *argv, VALUE io)
6306{
6307 VALUE len, offset, str;
6308 rb_io_t *fptr;
6309 ssize_t n;
6310 struct prdwr_internal_arg arg;
6311 int shrinkable;
6312
6313 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6314 arg.count = NUM2SIZET(len);
6315 arg.offset = NUM2OFFT(offset);
6316
6317 shrinkable = io_setstrbuf(&str, (long)arg.count);
6318 if (arg.count == 0) return str;
6319 arg.buf = RSTRING_PTR(str);
6320
6321 GetOpenFile(io, fptr);
6323
6324 arg.io = fptr;
6325 arg.fd = fptr->fd;
6326 rb_io_check_closed(fptr);
6327
6328 rb_str_locktmp(str);
6329 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6330
6331 if (n < 0) {
6332 rb_sys_fail_path(fptr->pathv);
6333 }
6334 io_set_read_length(str, n, shrinkable);
6335 if (n == 0 && arg.count > 0) {
6336 rb_eof_error();
6337 }
6338
6339 return str;
6340}
6341
6342static VALUE
6343internal_pwrite_func(void *_arg)
6344{
6345 struct prdwr_internal_arg *arg = _arg;
6346
6347 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6348}
6349
6350static VALUE
6351pwrite_internal_call(VALUE _arg)
6352{
6353 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6354
6355 VALUE scheduler = rb_fiber_scheduler_current();
6356 if (scheduler != Qnil) {
6357 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6358
6359 if (!UNDEF_P(result)) {
6360 return rb_fiber_scheduler_io_result_apply(result);
6361 }
6362 }
6363
6364 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
6365}
6366
6367/*
6368 * call-seq:
6369 * pwrite(object, offset) -> integer
6370 *
6371 * Behaves like IO#write, except that it:
6372 *
6373 * - Writes at the given +offset+ (in bytes).
6374 * - Disregards, and does not modify, the stream's position
6375 * (see {Position}[rdoc-ref:IO@Position]).
6376 * - Bypasses any user space buffering in the stream.
6377 *
6378 * Because this method does not disturb the stream's state
6379 * (its position, in particular), +pwrite+ allows multiple threads and processes
6380 * to use the same \IO object for writing at various offsets.
6381 *
6382 * f = File.open('t.tmp', 'w+')
6383 * # Write 6 bytes at offset 3.
6384 * f.pwrite('ABCDEF', 3) # => 6
6385 * f.rewind
6386 * f.read # => "\u0000\u0000\u0000ABCDEF"
6387 * f.close
6388 *
6389 * Not available on some platforms.
6390 *
6391 */
6392static VALUE
6393rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6394{
6395 rb_io_t *fptr;
6396 ssize_t n;
6397 struct prdwr_internal_arg arg;
6398 VALUE tmp;
6399
6400 if (!RB_TYPE_P(str, T_STRING))
6401 str = rb_obj_as_string(str);
6402
6403 arg.offset = NUM2OFFT(offset);
6404
6405 io = GetWriteIO(io);
6406 GetOpenFile(io, fptr);
6408
6409 arg.io = fptr;
6410 arg.fd = fptr->fd;
6411
6412 tmp = rb_str_tmp_frozen_acquire(str);
6413 arg.buf = RSTRING_PTR(tmp);
6414 arg.count = (size_t)RSTRING_LEN(tmp);
6415
6416 n = (ssize_t)pwrite_internal_call((VALUE)&arg);
6417 if (n < 0) rb_sys_fail_path(fptr->pathv);
6418 rb_str_tmp_frozen_release(str, tmp);
6419
6420 return SSIZET2NUM(n);
6421}
6422
6423VALUE
6425{
6426 rb_io_t *fptr;
6427
6428 GetOpenFile(io, fptr);
6429 if (fptr->readconv)
6431 if (fptr->writeconv)
6433 fptr->mode |= FMODE_BINMODE;
6434 fptr->mode &= ~FMODE_TEXTMODE;
6436#ifdef O_BINARY
6437 if (!fptr->readconv) {
6438 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6439 }
6440 else {
6441 setmode(fptr->fd, O_BINARY);
6442 }
6443#endif
6444 return io;
6445}
6446
6447static void
6448io_ascii8bit_binmode(rb_io_t *fptr)
6449{
6450 if (fptr->readconv) {
6451 rb_econv_close(fptr->readconv);
6452 fptr->readconv = NULL;
6453 }
6454 if (fptr->writeconv) {
6456 fptr->writeconv = NULL;
6457 }
6458 fptr->mode |= FMODE_BINMODE;
6459 fptr->mode &= ~FMODE_TEXTMODE;
6460 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6461
6462 fptr->encs.enc = rb_ascii8bit_encoding();
6463 fptr->encs.enc2 = NULL;
6464 fptr->encs.ecflags = 0;
6465 fptr->encs.ecopts = Qnil;
6466 clear_codeconv(fptr);
6467}
6468
6469VALUE
6471{
6472 rb_io_t *fptr;
6473
6474 GetOpenFile(io, fptr);
6475 io_ascii8bit_binmode(fptr);
6476
6477 return io;
6478}
6479
6480/*
6481 * call-seq:
6482 * binmode -> self
6483 *
6484 * Sets the stream's data mode as binary
6485 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6486 *
6487 * A stream's data mode may not be changed from binary to text.
6488 *
6489 */
6490
6491static VALUE
6492rb_io_binmode_m(VALUE io)
6493{
6494 VALUE write_io;
6495
6497
6498 write_io = GetWriteIO(io);
6499 if (write_io != io)
6500 rb_io_ascii8bit_binmode(write_io);
6501 return io;
6502}
6503
6504/*
6505 * call-seq:
6506 * binmode? -> true or false
6507 *
6508 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6509 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6510 *
6511 */
6512static VALUE
6513rb_io_binmode_p(VALUE io)
6514{
6515 rb_io_t *fptr;
6516 GetOpenFile(io, fptr);
6517 return RBOOL(fptr->mode & FMODE_BINMODE);
6518}
6519
6520static const char*
6521rb_io_fmode_modestr(enum rb_io_mode fmode)
6522{
6523 if (fmode & FMODE_APPEND) {
6524 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6525 return MODE_BTMODE("a+", "ab+", "at+");
6526 }
6527 return MODE_BTMODE("a", "ab", "at");
6528 }
6529 switch (fmode & FMODE_READWRITE) {
6530 default:
6531 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6532 case FMODE_READABLE:
6533 return MODE_BTMODE("r", "rb", "rt");
6534 case FMODE_WRITABLE:
6535 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6536 case FMODE_READWRITE:
6537 if (fmode & FMODE_CREATE) {
6538 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6539 }
6540 return MODE_BTMODE("r+", "rb+", "rt+");
6541 }
6542}
6543
6544static const char bom_prefix[] = "bom|";
6545static const char utf_prefix[] = "utf-";
6546enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6547enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6548
6549static int
6550io_encname_bom_p(const char *name, long len)
6551{
6552 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6553}
6554
6555enum rb_io_mode
6556rb_io_modestr_fmode(const char *modestr)
6557{
6558 enum rb_io_mode fmode = 0;
6559 const char *m = modestr, *p = NULL;
6560
6561 switch (*m++) {
6562 case 'r':
6563 fmode |= FMODE_READABLE;
6564 break;
6565 case 'w':
6567 break;
6568 case 'a':
6570 break;
6571 default:
6572 goto error;
6573 }
6574
6575 while (*m) {
6576 switch (*m++) {
6577 case 'b':
6578 fmode |= FMODE_BINMODE;
6579 break;
6580 case 't':
6581 fmode |= FMODE_TEXTMODE;
6582 break;
6583 case '+':
6584 fmode |= FMODE_READWRITE;
6585 break;
6586 case 'x':
6587 if (modestr[0] != 'w')
6588 goto error;
6589 fmode |= FMODE_EXCL;
6590 break;
6591 default:
6592 goto error;
6593 case ':':
6594 p = strchr(m, ':');
6595 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6596 fmode |= FMODE_SETENC_BY_BOM;
6597 goto finished;
6598 }
6599 }
6600
6601 finished:
6602 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6603 goto error;
6604
6605 return fmode;
6606
6607 error:
6608 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6610}
6611
6612int
6614{
6615 enum rb_io_mode fmode = 0;
6616
6617 switch (oflags & O_ACCMODE) {
6618 case O_RDONLY:
6619 fmode = FMODE_READABLE;
6620 break;
6621 case O_WRONLY:
6622 fmode = FMODE_WRITABLE;
6623 break;
6624 case O_RDWR:
6625 fmode = FMODE_READWRITE;
6626 break;
6627 }
6628
6629 if (oflags & O_APPEND) {
6630 fmode |= FMODE_APPEND;
6631 }
6632 if (oflags & O_TRUNC) {
6633 fmode |= FMODE_TRUNC;
6634 }
6635 if (oflags & O_CREAT) {
6636 fmode |= FMODE_CREATE;
6637 }
6638 if (oflags & O_EXCL) {
6639 fmode |= FMODE_EXCL;
6640 }
6641#ifdef O_BINARY
6642 if (oflags & O_BINARY) {
6643 fmode |= FMODE_BINMODE;
6644 }
6645#endif
6646
6647 return fmode;
6648}
6649
6650static int
6651rb_io_fmode_oflags(enum rb_io_mode fmode)
6652{
6653 int oflags = 0;
6654
6655 switch (fmode & FMODE_READWRITE) {
6656 case FMODE_READABLE:
6657 oflags |= O_RDONLY;
6658 break;
6659 case FMODE_WRITABLE:
6660 oflags |= O_WRONLY;
6661 break;
6662 case FMODE_READWRITE:
6663 oflags |= O_RDWR;
6664 break;
6665 }
6666
6667 if (fmode & FMODE_APPEND) {
6668 oflags |= O_APPEND;
6669 }
6670 if (fmode & FMODE_TRUNC) {
6671 oflags |= O_TRUNC;
6672 }
6673 if (fmode & FMODE_CREATE) {
6674 oflags |= O_CREAT;
6675 }
6676 if (fmode & FMODE_EXCL) {
6677 oflags |= O_EXCL;
6678 }
6679#ifdef O_BINARY
6680 if (fmode & FMODE_BINMODE) {
6681 oflags |= O_BINARY;
6682 }
6683#endif
6684
6685 return oflags;
6686}
6687
6688int
6689rb_io_modestr_oflags(const char *modestr)
6690{
6691 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6692}
6693
6694static const char*
6695rb_io_oflags_modestr(int oflags)
6696{
6697#ifdef O_BINARY
6698# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6699#else
6700# define MODE_BINARY(a,b) (a)
6701#endif
6702 int accmode;
6703 if (oflags & O_EXCL) {
6704 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6705 }
6706 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6707 if (oflags & O_APPEND) {
6708 if (accmode == O_WRONLY) {
6709 return MODE_BINARY("a", "ab");
6710 }
6711 if (accmode == O_RDWR) {
6712 return MODE_BINARY("a+", "ab+");
6713 }
6714 }
6715 switch (accmode) {
6716 default:
6717 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6718 case O_RDONLY:
6719 return MODE_BINARY("r", "rb");
6720 case O_WRONLY:
6721 return MODE_BINARY("w", "wb");
6722 case O_RDWR:
6723 if (oflags & O_TRUNC) {
6724 return MODE_BINARY("w+", "wb+");
6725 }
6726 return MODE_BINARY("r+", "rb+");
6727 }
6728}
6729
6730/*
6731 * Convert external/internal encodings to enc/enc2
6732 * NULL => use default encoding
6733 * Qnil => no encoding specified (internal only)
6734 */
6735static void
6736rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6737{
6738 int default_ext = 0;
6739
6740 if (ext == NULL) {
6741 ext = rb_default_external_encoding();
6742 default_ext = 1;
6743 }
6744 if (rb_is_ascii8bit_enc(ext)) {
6745 /* If external is ASCII-8BIT, no transcoding */
6746 intern = NULL;
6747 }
6748 else if (intern == NULL) {
6749 intern = rb_default_internal_encoding();
6750 }
6751 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6752 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6753 /* No internal encoding => use external + no transcoding */
6754 *enc = (default_ext && intern != ext) ? NULL : ext;
6755 *enc2 = NULL;
6756 }
6757 else {
6758 *enc = intern;
6759 *enc2 = ext;
6760 }
6761}
6762
6763static void
6764unsupported_encoding(const char *name, rb_encoding *enc)
6765{
6766 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6767}
6768
6769static void
6770parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6771 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6772{
6773 const char *p;
6774 char encname[ENCODING_MAXNAMELEN+1];
6775 int idx, idx2;
6776 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6777 rb_encoding *ext_enc, *int_enc;
6778 long len;
6779
6780 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6781
6782 p = strrchr(estr, ':');
6783 len = p ? (p++ - estr) : (long)strlen(estr);
6784 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6785 estr += bom_prefix_len;
6786 len -= bom_prefix_len;
6787 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6788 fmode |= FMODE_SETENC_BY_BOM;
6789 }
6790 else {
6791 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6792 fmode &= ~FMODE_SETENC_BY_BOM;
6793 }
6794 }
6795 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6796 idx = -1;
6797 }
6798 else {
6799 if (p) {
6800 memcpy(encname, estr, len);
6801 encname[len] = '\0';
6802 estr = encname;
6803 }
6804 idx = rb_enc_find_index(estr);
6805 }
6806 if (fmode_p) *fmode_p = fmode;
6807
6808 if (idx >= 0)
6809 ext_enc = rb_enc_from_index(idx);
6810 else {
6811 if (idx != -2)
6812 unsupported_encoding(estr, estr_enc);
6813 ext_enc = NULL;
6814 }
6815
6816 int_enc = NULL;
6817 if (p) {
6818 if (*p == '-' && *(p+1) == '\0') {
6819 /* Special case - "-" => no transcoding */
6820 int_enc = (rb_encoding *)Qnil;
6821 }
6822 else {
6823 idx2 = rb_enc_find_index(p);
6824 if (idx2 < 0)
6825 unsupported_encoding(p, estr_enc);
6826 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6827 int_enc = (rb_encoding *)Qnil;
6828 }
6829 else
6830 int_enc = rb_enc_from_index(idx2);
6831 }
6832 }
6833
6834 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6835}
6836
6837int
6838rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6839{
6840 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6841 int extracted = 0;
6842 rb_encoding *extencoding = NULL;
6843 rb_encoding *intencoding = NULL;
6844
6845 if (!NIL_P(opt)) {
6846 VALUE v;
6847 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6848 if (v != Qnil) encoding = v;
6849 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6850 if (v != Qnil) extenc = v;
6851 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6852 if (!UNDEF_P(v)) intenc = v;
6853 }
6854 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6855 if (!NIL_P(ruby_verbose)) {
6856 int idx = rb_to_encoding_index(encoding);
6857 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6858 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6859 encoding, UNDEF_P(extenc) ? "internal" : "external");
6860 }
6861 encoding = Qnil;
6862 }
6863 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6864 extencoding = rb_to_encoding(extenc);
6865 }
6866 if (!UNDEF_P(intenc)) {
6867 if (NIL_P(intenc)) {
6868 /* internal_encoding: nil => no transcoding */
6869 intencoding = (rb_encoding *)Qnil;
6870 }
6871 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6872 char *p = StringValueCStr(tmp);
6873
6874 if (*p == '-' && *(p+1) == '\0') {
6875 /* Special case - "-" => no transcoding */
6876 intencoding = (rb_encoding *)Qnil;
6877 }
6878 else {
6879 intencoding = rb_to_encoding(intenc);
6880 }
6881 }
6882 else {
6883 intencoding = rb_to_encoding(intenc);
6884 }
6885 if (extencoding == intencoding) {
6886 intencoding = (rb_encoding *)Qnil;
6887 }
6888 }
6889 if (!NIL_P(encoding)) {
6890 extracted = 1;
6891 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6892 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6893 enc_p, enc2_p, fmode_p);
6894 }
6895 else {
6896 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6897 }
6898 }
6899 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6900 extracted = 1;
6901 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6902 }
6903 return extracted;
6904}
6905
6906static void
6907validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6908{
6909 enum rb_io_mode fmode = *fmode_p;
6910
6911 if ((fmode & FMODE_READABLE) &&
6912 !enc2 &&
6913 !(fmode & FMODE_BINMODE) &&
6914 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6915 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6916
6917 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6918 rb_raise(rb_eArgError, "newline decorator with binary mode");
6919 }
6920 if (!(fmode & FMODE_BINMODE) &&
6921 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6922 fmode |= FMODE_TEXTMODE;
6923 *fmode_p = fmode;
6924 }
6925#if !DEFAULT_TEXTMODE
6926 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6927 fmode &= ~FMODE_TEXTMODE;
6928 *fmode_p = fmode;
6929 }
6930#endif
6931}
6932
6933static void
6934extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
6935{
6936 if (!NIL_P(opthash)) {
6937 VALUE v;
6938 v = rb_hash_aref(opthash, sym_textmode);
6939 if (!NIL_P(v)) {
6940 if (*fmode & FMODE_TEXTMODE)
6941 rb_raise(rb_eArgError, "textmode specified twice");
6942 if (*fmode & FMODE_BINMODE)
6943 rb_raise(rb_eArgError, "both textmode and binmode specified");
6944 if (RTEST(v))
6945 *fmode |= FMODE_TEXTMODE;
6946 }
6947 v = rb_hash_aref(opthash, sym_binmode);
6948 if (!NIL_P(v)) {
6949 if (*fmode & FMODE_BINMODE)
6950 rb_raise(rb_eArgError, "binmode specified twice");
6951 if (*fmode & FMODE_TEXTMODE)
6952 rb_raise(rb_eArgError, "both textmode and binmode specified");
6953 if (RTEST(v))
6954 *fmode |= FMODE_BINMODE;
6955 }
6956
6957 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6958 rb_raise(rb_eArgError, "both textmode and binmode specified");
6959 }
6960}
6961
6962void
6963rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6964 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
6965{
6966 VALUE vmode;
6967 int oflags;
6968 enum rb_io_mode fmode;
6969 rb_encoding *enc, *enc2;
6970 int ecflags;
6971 VALUE ecopts;
6972 int has_enc = 0, has_vmode = 0;
6973 VALUE intmode;
6974
6975 vmode = *vmode_p;
6976
6977 /* Set to defaults */
6978 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6979
6980 vmode_handle:
6981 if (NIL_P(vmode)) {
6982 fmode = FMODE_READABLE;
6983 oflags = O_RDONLY;
6984 }
6985 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6986 vmode = intmode;
6987 oflags = NUM2INT(intmode);
6988 fmode = rb_io_oflags_fmode(oflags);
6989 }
6990 else {
6991 const char *p;
6992
6993 StringValue(vmode);
6994 p = StringValueCStr(vmode);
6995 fmode = rb_io_modestr_fmode(p);
6996 oflags = rb_io_fmode_oflags(fmode);
6997 p = strchr(p, ':');
6998 if (p) {
6999 has_enc = 1;
7000 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
7001 }
7002 else {
7003 rb_encoding *e;
7004
7005 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7006 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
7007 }
7008 }
7009
7010 if (NIL_P(opthash)) {
7011 ecflags = (fmode & FMODE_READABLE) ?
7014#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7015 ecflags |= (fmode & FMODE_WRITABLE) ?
7016 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7017 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7018#endif
7019 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7020 ecopts = Qnil;
7021 if (fmode & FMODE_BINMODE) {
7022#ifdef O_BINARY
7023 oflags |= O_BINARY;
7024#endif
7025 if (!has_enc)
7026 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7027 }
7028#if DEFAULT_TEXTMODE
7029 else if (NIL_P(vmode)) {
7030 fmode |= DEFAULT_TEXTMODE;
7031 }
7032#endif
7033 }
7034 else {
7035 VALUE v;
7036 if (!has_vmode) {
7037 v = rb_hash_aref(opthash, sym_mode);
7038 if (!NIL_P(v)) {
7039 if (!NIL_P(vmode)) {
7040 rb_raise(rb_eArgError, "mode specified twice");
7041 }
7042 has_vmode = 1;
7043 vmode = v;
7044 goto vmode_handle;
7045 }
7046 }
7047 v = rb_hash_aref(opthash, sym_flags);
7048 if (!NIL_P(v)) {
7049 v = rb_to_int(v);
7050 oflags |= NUM2INT(v);
7051 vmode = INT2NUM(oflags);
7052 fmode = rb_io_oflags_fmode(oflags);
7053 }
7054 extract_binmode(opthash, &fmode);
7055 if (fmode & FMODE_BINMODE) {
7056#ifdef O_BINARY
7057 oflags |= O_BINARY;
7058#endif
7059 if (!has_enc)
7060 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7061 }
7062#if DEFAULT_TEXTMODE
7063 else if (NIL_P(vmode)) {
7064 fmode |= DEFAULT_TEXTMODE;
7065 }
7066#endif
7067 v = rb_hash_aref(opthash, sym_perm);
7068 if (!NIL_P(v)) {
7069 if (vperm_p) {
7070 if (!NIL_P(*vperm_p)) {
7071 rb_raise(rb_eArgError, "perm specified twice");
7072 }
7073 *vperm_p = v;
7074 }
7075 else {
7076 /* perm no use, just ignore */
7077 }
7078 }
7079 ecflags = (fmode & FMODE_READABLE) ?
7082#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7083 ecflags |= (fmode & FMODE_WRITABLE) ?
7084 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7085 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7086#endif
7087
7088 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7089 if (has_enc) {
7090 rb_raise(rb_eArgError, "encoding specified twice");
7091 }
7092 }
7093 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7094 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7095 }
7096
7097 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7098
7099 *vmode_p = vmode;
7100
7101 *oflags_p = oflags;
7102 *fmode_p = fmode;
7103 convconfig_p->enc = enc;
7104 convconfig_p->enc2 = enc2;
7105 convconfig_p->ecflags = ecflags;
7106 convconfig_p->ecopts = ecopts;
7107}
7108
7110 VALUE fname;
7111 int oflags;
7112 mode_t perm;
7113};
7114
7115static void *
7116sysopen_func(void *ptr)
7117{
7118 const struct sysopen_struct *data = ptr;
7119 const char *fname = RSTRING_PTR(data->fname);
7120 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7121}
7122
7123static inline int
7124rb_sysopen_internal(struct sysopen_struct *data)
7125{
7126 int fd;
7127 do {
7128 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7129 } while (fd < 0 && errno == EINTR);
7130 if (0 <= fd)
7131 rb_update_max_fd(fd);
7132 return fd;
7133}
7134
7135static int
7136rb_sysopen(VALUE fname, int oflags, mode_t perm)
7137{
7138 int fd = -1;
7139 struct sysopen_struct data;
7140
7141 data.fname = rb_str_encode_ospath(fname);
7142 StringValueCStr(data.fname);
7143 data.oflags = oflags;
7144 data.perm = perm;
7145
7146 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7147 rb_syserr_fail_path(first_errno, fname);
7148 }
7149 return fd;
7150}
7151
7152static inline FILE *
7153fdopen_internal(int fd, const char *modestr)
7154{
7155 FILE *file;
7156
7157#if defined(__sun)
7158 errno = 0;
7159#endif
7160 file = fdopen(fd, modestr);
7161 if (!file) {
7162#ifdef _WIN32
7163 if (errno == 0) errno = EINVAL;
7164#elif defined(__sun)
7165 if (errno == 0) errno = EMFILE;
7166#endif
7167 }
7168 return file;
7169}
7170
7171FILE *
7172rb_fdopen(int fd, const char *modestr)
7173{
7174 FILE *file = 0;
7175
7176 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7177 rb_syserr_fail(first_errno, 0);
7178 }
7179
7180 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7181#ifdef USE_SETVBUF
7182 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7183 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7184#endif
7185 return file;
7186}
7187
7188static int
7189io_check_tty(rb_io_t *fptr)
7190{
7191 int t = isatty(fptr->fd);
7192 if (t)
7193 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7194 return t;
7195}
7196
7197static VALUE rb_io_internal_encoding(VALUE);
7198static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7199
7200static int
7201io_strip_bom(VALUE io)
7202{
7203 VALUE b1, b2, b3, b4;
7204 rb_io_t *fptr;
7205
7206 GetOpenFile(io, fptr);
7207 if (!(fptr->mode & FMODE_READABLE)) return 0;
7208 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7209 switch (b1) {
7210 case INT2FIX(0xEF):
7211 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7212 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7213 if (b3 == INT2FIX(0xBF)) {
7214 return rb_utf8_encindex();
7215 }
7216 rb_io_ungetbyte(io, b3);
7217 }
7218 rb_io_ungetbyte(io, b2);
7219 break;
7220
7221 case INT2FIX(0xFE):
7222 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7223 if (b2 == INT2FIX(0xFF)) {
7224 return ENCINDEX_UTF_16BE;
7225 }
7226 rb_io_ungetbyte(io, b2);
7227 break;
7228
7229 case INT2FIX(0xFF):
7230 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7231 if (b2 == INT2FIX(0xFE)) {
7232 b3 = rb_io_getbyte(io);
7233 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7234 if (b4 == INT2FIX(0)) {
7235 return ENCINDEX_UTF_32LE;
7236 }
7237 rb_io_ungetbyte(io, b4);
7238 }
7239 rb_io_ungetbyte(io, b3);
7240 return ENCINDEX_UTF_16LE;
7241 }
7242 rb_io_ungetbyte(io, b2);
7243 break;
7244
7245 case INT2FIX(0):
7246 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7247 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7248 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7249 if (b4 == INT2FIX(0xFF)) {
7250 return ENCINDEX_UTF_32BE;
7251 }
7252 rb_io_ungetbyte(io, b4);
7253 }
7254 rb_io_ungetbyte(io, b3);
7255 }
7256 rb_io_ungetbyte(io, b2);
7257 break;
7258 }
7259 rb_io_ungetbyte(io, b1);
7260 return 0;
7261}
7262
7263static rb_encoding *
7264io_set_encoding_by_bom(VALUE io)
7265{
7266 int idx = io_strip_bom(io);
7267 rb_io_t *fptr;
7268 rb_encoding *extenc = NULL;
7269
7270 GetOpenFile(io, fptr);
7271 if (idx) {
7272 extenc = rb_enc_from_index(idx);
7273 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7274 rb_io_internal_encoding(io), Qnil);
7275 }
7276 else {
7277 fptr->encs.enc2 = NULL;
7278 }
7279 return extenc;
7280}
7281
7282static VALUE
7283rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7284 const struct rb_io_encoding *convconfig, mode_t perm)
7285{
7286 VALUE pathv;
7287 rb_io_t *fptr;
7288 struct rb_io_encoding cc;
7289 if (!convconfig) {
7290 /* Set to default encodings */
7291 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7292 cc.ecflags = 0;
7293 cc.ecopts = Qnil;
7294 convconfig = &cc;
7295 }
7296 validate_enc_binmode(&fmode, convconfig->ecflags,
7297 convconfig->enc, convconfig->enc2);
7298
7299 MakeOpenFile(io, fptr);
7300 fptr->mode = fmode;
7301 fptr->encs = *convconfig;
7302 pathv = rb_str_new_frozen(filename);
7303#ifdef O_TMPFILE
7304 if (!(oflags & O_TMPFILE)) {
7305 fptr->pathv = pathv;
7306 }
7307#else
7308 fptr->pathv = pathv;
7309#endif
7310 fptr->fd = rb_sysopen(pathv, oflags, perm);
7311 io_check_tty(fptr);
7312 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7313
7314 return io;
7315}
7316
7317static VALUE
7318rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7319{
7320 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7321 const char *p = strchr(modestr, ':');
7322 struct rb_io_encoding convconfig;
7323
7324 if (p) {
7325 parse_mode_enc(p+1, rb_usascii_encoding(),
7326 &convconfig.enc, &convconfig.enc2, &fmode);
7327 }
7328 else {
7329 rb_encoding *e;
7330 /* Set to default encodings */
7331
7332 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7333 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7334 }
7335
7336 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7339#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7340 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7341 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7342 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7343#endif
7344 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7345 convconfig.ecopts = Qnil;
7346
7347 return rb_file_open_generic(io, filename,
7348 rb_io_fmode_oflags(fmode),
7349 fmode,
7350 &convconfig,
7351 0666);
7352}
7353
7354VALUE
7355rb_file_open_str(VALUE fname, const char *modestr)
7356{
7357 FilePathValue(fname);
7358 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7359}
7360
7361VALUE
7362rb_file_open(const char *fname, const char *modestr)
7363{
7364 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7365}
7366
7367#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7368static struct pipe_list {
7369 rb_io_t *fptr;
7370 struct pipe_list *next;
7371} *pipe_list;
7372
7373static void
7374pipe_add_fptr(rb_io_t *fptr)
7375{
7376 struct pipe_list *list;
7377
7378 list = ALLOC(struct pipe_list);
7379 list->fptr = fptr;
7380 list->next = pipe_list;
7381 pipe_list = list;
7382}
7383
7384static void
7385pipe_del_fptr(rb_io_t *fptr)
7386{
7387 struct pipe_list **prev = &pipe_list;
7388 struct pipe_list *tmp;
7389
7390 while ((tmp = *prev) != 0) {
7391 if (tmp->fptr == fptr) {
7392 *prev = tmp->next;
7393 free(tmp);
7394 return;
7395 }
7396 prev = &tmp->next;
7397 }
7398}
7399
7400#if defined (_WIN32) || defined(__CYGWIN__)
7401static void
7402pipe_atexit(void)
7403{
7404 struct pipe_list *list = pipe_list;
7405 struct pipe_list *tmp;
7406
7407 while (list) {
7408 tmp = list->next;
7409 rb_io_fptr_finalize(list->fptr);
7410 list = tmp;
7411 }
7412}
7413#endif
7414
7415static void
7416pipe_finalize(rb_io_t *fptr, int noraise)
7417{
7418#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7419 int status = 0;
7420 if (fptr->stdio_file) {
7421 status = pclose(fptr->stdio_file);
7422 }
7423 fptr->fd = -1;
7424 fptr->stdio_file = 0;
7425 rb_last_status_set(status, fptr->pid);
7426#else
7427 fptr_finalize(fptr, noraise);
7428#endif
7429 pipe_del_fptr(fptr);
7430}
7431#endif
7432
7433static void
7434fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7435{
7436#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7437 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7438
7439 if (old_finalize == orig->finalize) return;
7440#endif
7441
7442 fptr->finalize = orig->finalize;
7443
7444#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7445 if (old_finalize != pipe_finalize) {
7446 struct pipe_list *list;
7447 for (list = pipe_list; list; list = list->next) {
7448 if (list->fptr == fptr) break;
7449 }
7450 if (!list) pipe_add_fptr(fptr);
7451 }
7452 else {
7453 pipe_del_fptr(fptr);
7454 }
7455#endif
7456}
7457
7458void
7460{
7462 fptr->mode |= FMODE_SYNC;
7463}
7464
7465void
7466rb_io_unbuffered(rb_io_t *fptr)
7467{
7468 rb_io_synchronized(fptr);
7469}
7470
7471int
7472rb_pipe(int *pipes)
7473{
7474 int ret;
7475 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7476 if (ret == 0) {
7477 rb_update_max_fd(pipes[0]);
7478 rb_update_max_fd(pipes[1]);
7479 }
7480 return ret;
7481}
7482
7483#ifdef _WIN32
7484#define HAVE_SPAWNV 1
7485#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7486#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7487#endif
7488
7489#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7490struct popen_arg {
7491 VALUE execarg_obj;
7492 struct rb_execarg *eargp;
7493 int modef;
7494 int pair[2];
7495 int write_pair[2];
7496};
7497#endif
7498
7499#ifdef HAVE_WORKING_FORK
7500# ifndef __EMSCRIPTEN__
7501static void
7502popen_redirect(struct popen_arg *p)
7503{
7504 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7505 close(p->write_pair[1]);
7506 if (p->write_pair[0] != 0) {
7507 dup2(p->write_pair[0], 0);
7508 close(p->write_pair[0]);
7509 }
7510 close(p->pair[0]);
7511 if (p->pair[1] != 1) {
7512 dup2(p->pair[1], 1);
7513 close(p->pair[1]);
7514 }
7515 }
7516 else if (p->modef & FMODE_READABLE) {
7517 close(p->pair[0]);
7518 if (p->pair[1] != 1) {
7519 dup2(p->pair[1], 1);
7520 close(p->pair[1]);
7521 }
7522 }
7523 else {
7524 close(p->pair[1]);
7525 if (p->pair[0] != 0) {
7526 dup2(p->pair[0], 0);
7527 close(p->pair[0]);
7528 }
7529 }
7530}
7531# endif
7532
7533#if defined(__linux__)
7534/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7535 * Since /proc may not be available, linux_get_maxfd is just a hint.
7536 * This function, linux_get_maxfd, must be async-signal-safe.
7537 * I.e. opendir() is not usable.
7538 *
7539 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7540 * However they are easy to re-implement in async-signal-safe manner.
7541 * (Also note that there is missing/memcmp.c.)
7542 */
7543static int
7544linux_get_maxfd(void)
7545{
7546 int fd;
7547 char buf[4096], *p, *np, *e;
7548 ssize_t ss;
7549 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7550 if (fd < 0) return fd;
7551 ss = read(fd, buf, sizeof(buf));
7552 if (ss < 0) goto err;
7553 p = buf;
7554 e = buf + ss;
7555 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7556 (np = memchr(p, '\n', e-p)) != NULL) {
7557 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7558 int fdsize;
7559 p += sizeof("FDSize:")-1;
7560 *np = '\0';
7561 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7562 close(fd);
7563 return fdsize;
7564 }
7565 p = np+1;
7566 }
7567 /* fall through */
7568
7569 err:
7570 close(fd);
7571 return (int)ss;
7572}
7573#endif
7574
7575/* This function should be async-signal-safe. */
7576void
7577rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7578{
7579#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7580 int fd, ret;
7581 int max = (int)max_file_descriptor;
7582# ifdef F_MAXFD
7583 /* F_MAXFD is available since NetBSD 2.0. */
7584 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7585 if (ret != -1)
7586 maxhint = max = ret;
7587# elif defined(__linux__)
7588 ret = linux_get_maxfd();
7589 if (maxhint < ret)
7590 maxhint = ret;
7591 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7592# endif
7593 if (max < maxhint)
7594 max = maxhint;
7595 for (fd = lowfd; fd <= max; fd++) {
7596 if (!NIL_P(noclose_fds) &&
7597 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7598 continue;
7599 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7600 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7601 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7602 }
7603# define CONTIGUOUS_CLOSED_FDS 20
7604 if (ret != -1) {
7605 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7606 max = fd + CONTIGUOUS_CLOSED_FDS;
7607 }
7608 }
7609#endif
7610}
7611
7612# ifndef __EMSCRIPTEN__
7613static int
7614popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7615{
7616 struct popen_arg *p = (struct popen_arg*)pp;
7617
7618 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7619}
7620# endif
7621#endif
7622
7623#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7624static VALUE
7625rb_execarg_fixup_v(VALUE execarg_obj)
7626{
7627 rb_execarg_parent_start(execarg_obj);
7628 return Qnil;
7629}
7630#else
7631char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7632#endif
7633
7634#ifndef __EMSCRIPTEN__
7635static VALUE
7636pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7637 const struct rb_io_encoding *convconfig)
7638{
7639 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7640 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7641 rb_pid_t pid = 0;
7642 rb_io_t *fptr;
7643 VALUE port;
7644 rb_io_t *write_fptr;
7645 VALUE write_port;
7646#if defined(HAVE_WORKING_FORK)
7647 int status;
7648 char errmsg[80] = { '\0' };
7649#endif
7650#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7651 int state;
7652 struct popen_arg arg;
7653#endif
7654 int e = 0;
7655#if defined(HAVE_SPAWNV)
7656# if defined(HAVE_SPAWNVE)
7657# define DO_SPAWN(cmd, args, envp) ((args) ? \
7658 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7659 spawne(P_NOWAIT, (cmd), (envp)))
7660# else
7661# define DO_SPAWN(cmd, args, envp) ((args) ? \
7662 spawnv(P_NOWAIT, (cmd), (args)) : \
7663 spawn(P_NOWAIT, (cmd)))
7664# endif
7665# if !defined(HAVE_WORKING_FORK)
7666 char **args = NULL;
7667# if defined(HAVE_SPAWNVE)
7668 char **envp = NULL;
7669# endif
7670# endif
7671#endif
7672#if !defined(HAVE_WORKING_FORK)
7673 struct rb_execarg sarg, *sargp = &sarg;
7674#endif
7675 FILE *fp = 0;
7676 int fd = -1;
7677 int write_fd = -1;
7678#if !defined(HAVE_WORKING_FORK)
7679 const char *cmd = 0;
7680
7681 if (prog)
7682 cmd = StringValueCStr(prog);
7683#endif
7684
7685#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7686 arg.execarg_obj = execarg_obj;
7687 arg.eargp = eargp;
7688 arg.modef = fmode;
7689 arg.pair[0] = arg.pair[1] = -1;
7690 arg.write_pair[0] = arg.write_pair[1] = -1;
7691# if !defined(HAVE_WORKING_FORK)
7692 if (eargp && !eargp->use_shell) {
7693 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7694 }
7695# endif
7696 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7698 if (rb_pipe(arg.write_pair) < 0)
7699 rb_sys_fail_str(prog);
7700 if (rb_pipe(arg.pair) < 0) {
7701 e = errno;
7702 close(arg.write_pair[0]);
7703 close(arg.write_pair[1]);
7704 rb_syserr_fail_str(e, prog);
7705 }
7706 if (eargp) {
7707 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7708 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7709 }
7710 break;
7711 case FMODE_READABLE:
7712 if (rb_pipe(arg.pair) < 0)
7713 rb_sys_fail_str(prog);
7714 if (eargp)
7715 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7716 break;
7717 case FMODE_WRITABLE:
7718 if (rb_pipe(arg.pair) < 0)
7719 rb_sys_fail_str(prog);
7720 if (eargp)
7721 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7722 break;
7723 default:
7724 rb_sys_fail_str(prog);
7725 }
7726 if (!NIL_P(execarg_obj)) {
7727 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7728 if (state) {
7729 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7730 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7731 if (0 <= arg.pair[0]) close(arg.pair[0]);
7732 if (0 <= arg.pair[1]) close(arg.pair[1]);
7733 rb_execarg_parent_end(execarg_obj);
7734 rb_jump_tag(state);
7735 }
7736
7737# if defined(HAVE_WORKING_FORK)
7738 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7739# else
7740 rb_execarg_run_options(eargp, sargp, NULL, 0);
7741# if defined(HAVE_SPAWNVE)
7742 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7743# endif
7744 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7745 /* exec failed */
7746 switch (e = errno) {
7747 case EAGAIN:
7748# if EWOULDBLOCK != EAGAIN
7749 case EWOULDBLOCK:
7750# endif
7751 rb_thread_sleep(1);
7752 continue;
7753 }
7754 break;
7755 }
7756 if (eargp)
7757 rb_execarg_run_options(sargp, NULL, NULL, 0);
7758# endif
7759 rb_execarg_parent_end(execarg_obj);
7760 }
7761 else {
7762# if defined(HAVE_WORKING_FORK)
7763 pid = rb_call_proc__fork();
7764 if (pid == 0) { /* child */
7765 popen_redirect(&arg);
7766 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7767 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7768 return Qnil;
7769 }
7770# else
7772# endif
7773 }
7774
7775 /* parent */
7776 if (pid < 0) {
7777# if defined(HAVE_WORKING_FORK)
7778 e = errno;
7779# endif
7780 close(arg.pair[0]);
7781 close(arg.pair[1]);
7783 close(arg.write_pair[0]);
7784 close(arg.write_pair[1]);
7785 }
7786# if defined(HAVE_WORKING_FORK)
7787 if (errmsg[0])
7788 rb_syserr_fail(e, errmsg);
7789# endif
7790 rb_syserr_fail_str(e, prog);
7791 }
7792 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7793 close(arg.pair[1]);
7794 fd = arg.pair[0];
7795 close(arg.write_pair[0]);
7796 write_fd = arg.write_pair[1];
7797 }
7798 else if (fmode & FMODE_READABLE) {
7799 close(arg.pair[1]);
7800 fd = arg.pair[0];
7801 }
7802 else {
7803 close(arg.pair[0]);
7804 fd = arg.pair[1];
7805 }
7806#else
7807 cmd = rb_execarg_commandline(eargp, &prog);
7808 if (!NIL_P(execarg_obj)) {
7809 rb_execarg_parent_start(execarg_obj);
7810 rb_execarg_run_options(eargp, sargp, NULL, 0);
7811 }
7812 fp = popen(cmd, modestr);
7813 e = errno;
7814 if (eargp) {
7815 rb_execarg_parent_end(execarg_obj);
7816 rb_execarg_run_options(sargp, NULL, NULL, 0);
7817 }
7818 if (!fp) rb_syserr_fail_path(e, prog);
7819 fd = fileno(fp);
7820#endif
7821
7822 port = io_alloc(rb_cIO);
7823 MakeOpenFile(port, fptr);
7824 fptr->fd = fd;
7825 fptr->stdio_file = fp;
7826 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7827 if (convconfig) {
7828 fptr->encs = *convconfig;
7829#if RUBY_CRLF_ENVIRONMENT
7832 }
7833#endif
7834 }
7835 else {
7836 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7838 }
7839#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7840 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7841 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7842 }
7843#endif
7844 }
7845 fptr->pid = pid;
7846
7847 if (0 <= write_fd) {
7848 write_port = io_alloc(rb_cIO);
7849 MakeOpenFile(write_port, write_fptr);
7850 write_fptr->fd = write_fd;
7851 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7852 fptr->mode &= ~FMODE_WRITABLE;
7853 fptr->tied_io_for_writing = write_port;
7854 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7855 }
7856
7857#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7858 fptr->finalize = pipe_finalize;
7859 pipe_add_fptr(fptr);
7860#endif
7861 return port;
7862}
7863#else
7864static VALUE
7865pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7866 const struct rb_io_encoding *convconfig)
7867{
7868 rb_raise(rb_eNotImpError, "popen() is not available");
7869}
7870#endif
7871
7872static int
7873is_popen_fork(VALUE prog)
7874{
7875 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7876#if !defined(HAVE_WORKING_FORK)
7877 rb_raise(rb_eNotImpError,
7878 "fork() function is unimplemented on this machine");
7879#else
7880 return TRUE;
7881#endif
7882 }
7883 return FALSE;
7884}
7885
7886static VALUE
7887pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
7888 const struct rb_io_encoding *convconfig)
7889{
7890 int argc = 1;
7891 VALUE *argv = &prog;
7892 VALUE execarg_obj = Qnil;
7893
7894 if (!is_popen_fork(prog))
7895 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7896 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7897}
7898
7899static VALUE
7900pipe_close(VALUE io)
7901{
7902 rb_io_t *fptr = io_close_fptr(io);
7903 if (fptr) {
7904 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7905 }
7906 return Qnil;
7907}
7908
7909static VALUE popen_finish(VALUE port, VALUE klass);
7910
7911/*
7912 * call-seq:
7913 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7914 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7915 *
7916 * Executes the given command +cmd+ as a subprocess
7917 * whose $stdin and $stdout are connected to a new stream +io+.
7918 *
7919 * This method has potential security vulnerabilities if called with untrusted input;
7920 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
7921 *
7922 * If no block is given, returns the new stream,
7923 * which depending on given +mode+ may be open for reading, writing, or both.
7924 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7925 *
7926 * If a block is given, the stream is passed to the block
7927 * (again, open for reading, writing, or both);
7928 * when the block exits, the stream is closed,
7929 * the block's value is returned,
7930 * and the global variable <tt>$?</tt> is set to the child's exit status.
7931 *
7932 * Optional argument +mode+ may be any valid \IO mode.
7933 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7934 *
7935 * Required argument +cmd+ determines which of the following occurs:
7936 *
7937 * - The process forks.
7938 * - A specified program runs in a shell.
7939 * - A specified program runs with specified arguments.
7940 * - A specified program runs with specified arguments and a specified +argv0+.
7941 *
7942 * Each of these is detailed below.
7943 *
7944 * The optional hash argument +env+ specifies name/value pairs that are to be added
7945 * to the environment variables for the subprocess:
7946 *
7947 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7948 * pipe.puts 'puts ENV["FOO"]'
7949 * pipe.close_write
7950 * pipe.gets
7951 * end => "bar\n"
7952 *
7953 * Optional keyword arguments +opts+ specify:
7954 *
7955 * - {Open options}[rdoc-ref:IO@Open+Options].
7956 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7957 * - Options for Kernel#spawn.
7958 *
7959 * <b>Forked Process</b>
7960 *
7961 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7962 * IO.popen('-') do |pipe|
7963 * if pipe
7964 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7965 * else
7966 * $stderr.puts "In child, pid is #{$$}\n"
7967 * end
7968 * end
7969 *
7970 * Output:
7971 *
7972 * In parent, child pid is 26253
7973 * In child, pid is 26253
7974 *
7975 * Note that this is not supported on all platforms.
7976 *
7977 * <b>Shell Subprocess</b>
7978 *
7979 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7980 * the program named +cmd+ is run as a shell command:
7981 *
7982 * IO.popen('uname') do |pipe|
7983 * pipe.readlines
7984 * end
7985 *
7986 * Output:
7987 *
7988 * ["Linux\n"]
7989 *
7990 * Another example:
7991 *
7992 * IO.popen('/bin/sh', 'r+') do |pipe|
7993 * pipe.puts('ls')
7994 * pipe.close_write
7995 * $stderr.puts pipe.readlines.size
7996 * end
7997 *
7998 * Output:
7999 *
8000 * 213
8001 *
8002 * <b>Program Subprocess</b>
8003 *
8004 * When argument +cmd+ is an array of strings,
8005 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
8006 *
8007 * IO.popen(['du', '..', '.']) do |pipe|
8008 * $stderr.puts pipe.readlines.size
8009 * end
8010 *
8011 * Output:
8012 *
8013 * 1111
8014 *
8015 * <b>Program Subprocess with <tt>argv0</tt></b>
8016 *
8017 * When argument +cmd+ is an array whose first element is a 2-element string array
8018 * and whose remaining elements (if any) are strings:
8019 *
8020 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
8021 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
8022 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
8023 *
8024 * Example (sets <tt>$0</tt> to 'foo'):
8025 *
8026 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
8027 *
8028 * <b>Some Special Examples</b>
8029 *
8030 * # Set IO encoding.
8031 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
8032 * euc_jp_string = nkf_io.read
8033 * }
8034 *
8035 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
8036 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
8037 * ls_result_with_error = io.read
8038 * end
8039 *
8040 * # Use mixture of spawn options and IO options.
8041 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
8042 * ls_result_with_error = io.read
8043 * end
8044 *
8045 * f = IO.popen("uname")
8046 * p f.readlines
8047 * f.close
8048 * puts "Parent is #{Process.pid}"
8049 * IO.popen("date") {|f| puts f.gets }
8050 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
8051 * p $?
8052 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
8053 * f.puts "bar"; f.close_write; puts f.gets
8054 * }
8055 *
8056 * Output (from last section):
8057 *
8058 * ["Linux\n"]
8059 * Parent is 21346
8060 * Thu Jan 15 22:41:19 JST 2009
8061 * 21346 is here, f is #<IO:fd 3>
8062 * 21352 is here, f is nil
8063 * #<Process::Status: pid 21352 exit 0>
8064 * <foo>bar;zot;
8065 *
8066 * Raises exceptions that IO.pipe and Kernel.spawn raise.
8067 *
8068 */
8069
8070static VALUE
8071rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
8072{
8073 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
8074
8075 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8076 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8077 switch (argc) {
8078 case 2:
8079 pmode = argv[1];
8080 case 1:
8081 pname = argv[0];
8082 break;
8083 default:
8084 {
8085 int ex = !NIL_P(opt);
8086 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8087 }
8088 }
8089 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8090}
8091
8092VALUE
8093rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8094{
8095 const char *modestr;
8096 VALUE tmp, execarg_obj = Qnil;
8097 int oflags;
8098 enum rb_io_mode fmode;
8099 struct rb_io_encoding convconfig;
8100
8101 tmp = rb_check_array_type(pname);
8102 if (!NIL_P(tmp)) {
8103 long len = RARRAY_LEN(tmp);
8104#if SIZEOF_LONG > SIZEOF_INT
8105 if (len > INT_MAX) {
8106 rb_raise(rb_eArgError, "too many arguments");
8107 }
8108#endif
8109 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8110 RB_GC_GUARD(tmp);
8111 }
8112 else {
8113 StringValue(pname);
8114 execarg_obj = Qnil;
8115 if (!is_popen_fork(pname))
8116 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8117 }
8118 if (!NIL_P(execarg_obj)) {
8119 if (!NIL_P(opt))
8120 opt = rb_execarg_extract_options(execarg_obj, opt);
8121 if (!NIL_P(env))
8122 rb_execarg_setenv(execarg_obj, env);
8123 }
8124 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8125 modestr = rb_io_oflags_modestr(oflags);
8126
8127 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8128}
8129
8130static VALUE
8131popen_finish(VALUE port, VALUE klass)
8132{
8133 if (NIL_P(port)) {
8134 /* child */
8135 if (rb_block_given_p()) {
8136 rb_protect(rb_yield, Qnil, NULL);
8137 rb_io_flush(rb_ractor_stdout());
8138 rb_io_flush(rb_ractor_stderr());
8139 _exit(0);
8140 }
8141 return Qnil;
8142 }
8143 RBASIC_SET_CLASS(port, klass);
8144 if (rb_block_given_p()) {
8145 return rb_ensure(rb_yield, port, pipe_close, port);
8146 }
8147 return port;
8148}
8149
8150#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8151struct popen_writer_arg {
8152 char *const *argv;
8153 struct popen_arg popen;
8154};
8155
8156static int
8157exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8158{
8159 struct popen_writer_arg *pw = arg;
8160 pw->popen.modef = FMODE_WRITABLE;
8161 popen_redirect(&pw->popen);
8162 execv(pw->argv[0], pw->argv);
8163 strlcpy(errmsg, strerror(errno), buflen);
8164 return -1;
8165}
8166#endif
8167
8168FILE *
8169ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8170{
8171#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8172# ifdef HAVE_WORKING_FORK
8173 struct popen_writer_arg pw;
8174 int *const write_pair = pw.popen.pair;
8175# else
8176 int write_pair[2];
8177# endif
8178
8179 *pid = -1;
8180 if (cloexec_pipe(write_pair, 0, false) == 0) {
8181# ifdef HAVE_WORKING_FORK
8182 pw.argv = argv;
8183 int status;
8184 char errmsg[80] = {'\0'};
8185 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8186# else
8187 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8188 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8189# endif
8190 close(write_pair[0]);
8191 if (*pid < 0) {
8192 close(write_pair[1]);
8193 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8194 }
8195 else {
8196 return fdopen(write_pair[1], "w");
8197 }
8198 }
8199#endif
8200 return NULL;
8201}
8202
8203static VALUE
8204rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8205{
8206 int oflags;
8207 enum rb_io_mode fmode;
8208 struct rb_io_encoding convconfig;
8209 mode_t perm;
8210
8211 FilePathValue(fname);
8212
8213 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8214 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8215
8216 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8217
8218 return io;
8219}
8220
8221/*
8222 * Document-method: File::open
8223 *
8224 * call-seq:
8225 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8226 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8227 *
8228 * Creates a new File object, via File.new with the given arguments.
8229 *
8230 * With no block given, returns the File object.
8231 *
8232 * With a block given, calls the block with the File object
8233 * and returns the block's value.
8234 *
8235 */
8236
8237/*
8238 * Document-method: IO::open
8239 *
8240 * call-seq:
8241 * IO.open(fd, mode = 'r', **opts) -> io
8242 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8243 *
8244 * Creates a new \IO object, via IO.new with the given arguments.
8245 *
8246 * With no block given, returns the \IO object.
8247 *
8248 * With a block given, calls the block with the \IO object
8249 * and returns the block's value.
8250 *
8251 */
8252
8253static VALUE
8254rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8255{
8257
8258 if (rb_block_given_p()) {
8259 return rb_ensure(rb_yield, io, io_close, io);
8260 }
8261
8262 return io;
8263}
8264
8265/*
8266 * call-seq:
8267 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8268 *
8269 * Opens the file at the given path with the given mode and permissions;
8270 * returns the integer file descriptor.
8271 *
8272 * If the file is to be readable, it must exist;
8273 * if the file is to be writable and does not exist,
8274 * it is created with the given permissions:
8275 *
8276 * File.write('t.tmp', '') # => 0
8277 * IO.sysopen('t.tmp') # => 8
8278 * IO.sysopen('t.tmp', 'w') # => 9
8279 *
8280 *
8281 */
8282
8283static VALUE
8284rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8285{
8286 VALUE fname, vmode, vperm;
8287 VALUE intmode;
8288 int oflags, fd;
8289 mode_t perm;
8290
8291 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8292 FilePathValue(fname);
8293
8294 if (NIL_P(vmode))
8295 oflags = O_RDONLY;
8296 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8297 oflags = NUM2INT(intmode);
8298 else {
8299 StringValue(vmode);
8300 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8301 }
8302 if (NIL_P(vperm)) perm = 0666;
8303 else perm = NUM2MODET(vperm);
8304
8305 RB_GC_GUARD(fname) = rb_str_new4(fname);
8306 fd = rb_sysopen(fname, oflags, perm);
8307 return INT2NUM(fd);
8308}
8309
8310/*
8311 * call-seq:
8312 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8313 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8314 *
8315 * Creates an IO object connected to the given file.
8316 *
8317 * With no block given, file stream is returned:
8318 *
8319 * open('t.txt') # => #<File:t.txt>
8320 *
8321 * With a block given, calls the block with the open file stream,
8322 * then closes the stream:
8323 *
8324 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8325 *
8326 * Output:
8327 *
8328 * #<File:t.txt>
8329 *
8330 * See File.open for details.
8331 *
8332 */
8333
8334static VALUE
8335rb_f_open(int argc, VALUE *argv, VALUE _)
8336{
8337 ID to_open = 0;
8338 int redirect = FALSE;
8339
8340 if (argc >= 1) {
8341 CONST_ID(to_open, "to_open");
8342 if (rb_respond_to(argv[0], to_open)) {
8343 redirect = TRUE;
8344 }
8345 else {
8346 VALUE tmp = argv[0];
8347 FilePathValue(tmp);
8348 if (NIL_P(tmp)) {
8349 redirect = TRUE;
8350 }
8351 else {
8352 argv[0] = tmp;
8353 }
8354 }
8355 }
8356 if (redirect) {
8357 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8358
8359 if (rb_block_given_p()) {
8360 return rb_ensure(rb_yield, io, io_close, io);
8361 }
8362 return io;
8363 }
8364 return rb_io_s_open(argc, argv, rb_cFile);
8365}
8366
8367static VALUE
8368rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8369 const struct rb_io_encoding *convconfig, mode_t perm)
8370{
8371 return rb_file_open_generic(io_alloc(klass), filename,
8372 oflags, fmode, convconfig, perm);
8373}
8374
8375static VALUE
8376rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8377{
8378 int oflags;
8379 enum rb_io_mode fmode;
8380 struct rb_io_encoding convconfig;
8381 mode_t perm;
8382
8383 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8384 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8385 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8386}
8387
8388static VALUE
8389io_reopen(VALUE io, VALUE nfile)
8390{
8391 rb_io_t *fptr, *orig;
8392 int fd, fd2;
8393 rb_off_t pos = 0;
8394
8395 nfile = rb_io_get_io(nfile);
8396 GetOpenFile(io, fptr);
8397 GetOpenFile(nfile, orig);
8398
8399 if (fptr == orig) return io;
8400 if (RUBY_IO_EXTERNAL_P(fptr)) {
8401 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8402 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8403 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8404 rb_raise(rb_eArgError,
8405 "%s can't change access mode from \"%s\" to \"%s\"",
8406 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8407 rb_io_fmode_modestr(orig->mode));
8408 }
8409 }
8410 if (fptr->mode & FMODE_WRITABLE) {
8411 if (io_fflush(fptr) < 0)
8412 rb_sys_fail_on_write(fptr);
8413 }
8414 else {
8415 flush_before_seek(fptr, true);
8416 }
8417 if (orig->mode & FMODE_READABLE) {
8418 pos = io_tell(orig);
8419 }
8420 if (orig->mode & FMODE_WRITABLE) {
8421 if (io_fflush(orig) < 0)
8422 rb_sys_fail_on_write(fptr);
8423 }
8424
8425 /* copy rb_io_t structure */
8426 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8427 fptr->encs = orig->encs;
8428 fptr->pid = orig->pid;
8429 fptr->lineno = orig->lineno;
8430 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8431 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8432 fptr_copy_finalizer(fptr, orig);
8433
8434 fd = fptr->fd;
8435 fd2 = orig->fd;
8436 if (fd != fd2) {
8437 // Interrupt all usage of the old file descriptor:
8438 rb_thread_io_close_interrupt(fptr);
8439 rb_thread_io_close_wait(fptr);
8440
8441 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8442 /* need to keep FILE objects of stdin, stdout and stderr */
8443 if (rb_cloexec_dup2(fd2, fd) < 0)
8444 rb_sys_fail_path(orig->pathv);
8445 rb_update_max_fd(fd);
8446 }
8447 else {
8448 fclose(fptr->stdio_file);
8449 fptr->stdio_file = 0;
8450 fptr->fd = -1;
8451 if (rb_cloexec_dup2(fd2, fd) < 0)
8452 rb_sys_fail_path(orig->pathv);
8453 rb_update_max_fd(fd);
8454 fptr->fd = fd;
8455 }
8456
8457 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8458 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8459 rb_sys_fail_path(fptr->pathv);
8460 }
8461 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8462 rb_sys_fail_path(orig->pathv);
8463 }
8464 }
8465 }
8466
8467 if (fptr->mode & FMODE_BINMODE) {
8468 rb_io_binmode(io);
8469 }
8470
8471 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8472 return io;
8473}
8474
8475#ifdef _WIN32
8476int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8477#else
8478static int
8479rb_freopen(VALUE fname, const char *mode, FILE *fp)
8480{
8481 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8482 RB_GC_GUARD(fname);
8483 return errno;
8484 }
8485 return 0;
8486}
8487#endif
8488
8489/*
8490 * call-seq:
8491 * reopen(other_io) -> self
8492 * reopen(path, mode = 'r', **opts) -> self
8493 *
8494 * Reassociates the stream with another stream,
8495 * which may be of a different class.
8496 * This method may be used to redirect an existing stream
8497 * to a new destination.
8498 *
8499 * With argument +other_io+ given, reassociates with that stream:
8500 *
8501 * # Redirect $stdin from a file.
8502 * f = File.open('t.txt')
8503 * $stdin.reopen(f)
8504 * f.close
8505 *
8506 * # Redirect $stdout to a file.
8507 * f = File.open('t.tmp', 'w')
8508 * $stdout.reopen(f)
8509 * f.close
8510 *
8511 * With argument +path+ given, reassociates with a new stream to that file path:
8512 *
8513 * $stdin.reopen('t.txt')
8514 * $stdout.reopen('t.tmp', 'w')
8515 *
8516 * Optional keyword arguments +opts+ specify:
8517 *
8518 * - {Open Options}[rdoc-ref:IO@Open+Options].
8519 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8520 *
8521 */
8522
8523static VALUE
8524rb_io_reopen(int argc, VALUE *argv, VALUE file)
8525{
8526 VALUE fname, nmode, opt;
8527 int oflags;
8528 rb_io_t *fptr;
8529
8530 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8531 VALUE tmp = rb_io_check_io(fname);
8532 if (!NIL_P(tmp)) {
8533 return io_reopen(file, tmp);
8534 }
8535 }
8536
8537 FilePathValue(fname);
8538 rb_io_taint_check(file);
8539 fptr = RFILE(file)->fptr;
8540 if (!fptr) {
8541 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8542 }
8543
8544 if (!NIL_P(nmode) || !NIL_P(opt)) {
8545 enum rb_io_mode fmode;
8546 struct rb_io_encoding convconfig;
8547
8548 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8549 if (RUBY_IO_EXTERNAL_P(fptr) &&
8550 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8551 (fptr->mode & FMODE_READWRITE)) {
8552 rb_raise(rb_eArgError,
8553 "%s can't change access mode from \"%s\" to \"%s\"",
8554 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8555 rb_io_fmode_modestr(fmode));
8556 }
8557 fptr->mode = fmode;
8558 fptr->encs = convconfig;
8559 }
8560 else {
8561 oflags = rb_io_fmode_oflags(fptr->mode);
8562 }
8563
8564 fptr->pathv = fname;
8565 if (fptr->fd < 0) {
8566 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8567 fptr->stdio_file = 0;
8568 return file;
8569 }
8570
8571 if (fptr->mode & FMODE_WRITABLE) {
8572 if (io_fflush(fptr) < 0)
8573 rb_sys_fail_on_write(fptr);
8574 }
8575 fptr->rbuf.off = fptr->rbuf.len = 0;
8576
8577 if (fptr->stdio_file) {
8578 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8579 rb_io_oflags_modestr(oflags),
8580 fptr->stdio_file);
8581 if (e) rb_syserr_fail_path(e, fptr->pathv);
8582 fptr->fd = fileno(fptr->stdio_file);
8583 rb_fd_fix_cloexec(fptr->fd);
8584#ifdef USE_SETVBUF
8585 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8586 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8587#endif
8588 if (fptr->stdio_file == stderr) {
8589 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8590 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8591 }
8592 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8593 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8594 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8595 }
8596 }
8597 else {
8598 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8599 int err = 0;
8600 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8601 err = errno;
8602 (void)close(tmpfd);
8603 if (err) {
8604 rb_syserr_fail_path(err, fptr->pathv);
8605 }
8606 }
8607
8608 return file;
8609}
8610
8611/* :nodoc: */
8612static VALUE
8613rb_io_init_copy(VALUE dest, VALUE io)
8614{
8615 rb_io_t *fptr, *orig;
8616 int fd;
8617 VALUE write_io;
8618 rb_off_t pos;
8619
8620 io = rb_io_get_io(io);
8621 if (!OBJ_INIT_COPY(dest, io)) return dest;
8622 GetOpenFile(io, orig);
8623 MakeOpenFile(dest, fptr);
8624
8625 rb_io_flush(io);
8626
8627 /* copy rb_io_t structure */
8628 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8629 fptr->encs = orig->encs;
8630 fptr->pid = orig->pid;
8631 fptr->lineno = orig->lineno;
8632 fptr->timeout = orig->timeout;
8633
8634 ccan_list_head_init(&fptr->blocking_operations);
8635 fptr->closing_ec = NULL;
8636 fptr->wakeup_mutex = Qnil;
8637 fptr->fork_generation = GET_VM()->fork_gen;
8638
8639 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8640 fptr_copy_finalizer(fptr, orig);
8641
8642 fd = ruby_dup(orig->fd);
8643 fptr->fd = fd;
8644 pos = io_tell(orig);
8645 if (0 <= pos)
8646 io_seek(fptr, pos, SEEK_SET);
8647 if (fptr->mode & FMODE_BINMODE) {
8648 rb_io_binmode(dest);
8649 }
8650
8651 write_io = GetWriteIO(io);
8652 if (io != write_io) {
8653 write_io = rb_obj_dup(write_io);
8654 fptr->tied_io_for_writing = write_io;
8655 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8656 }
8657
8658 return dest;
8659}
8660
8661/*
8662 * call-seq:
8663 * printf(format_string, *objects) -> nil
8664 *
8665 * Formats and writes +objects+ to the stream.
8666 *
8667 * For details on +format_string+, see
8668 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8669 *
8670 */
8671
8672VALUE
8673rb_io_printf(int argc, const VALUE *argv, VALUE out)
8674{
8675 rb_io_write(out, rb_f_sprintf(argc, argv));
8676 return Qnil;
8677}
8678
8679/*
8680 * call-seq:
8681 * printf(format_string, *objects) -> nil
8682 * printf(io, format_string, *objects) -> nil
8683 *
8684 * Equivalent to:
8685 *
8686 * io.write(sprintf(format_string, *objects))
8687 *
8688 * For details on +format_string+, see
8689 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8690 *
8691 * With the single argument +format_string+, formats +objects+ into the string,
8692 * then writes the formatted string to $stdout:
8693 *
8694 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8695 *
8696 * Output (on $stdout):
8697 *
8698 * 0024 24 24.00#
8699 *
8700 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8701 * then writes the formatted string to +io+:
8702 *
8703 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8704 *
8705 * Output (on $stderr):
8706 *
8707 * 0024 24 24.00# => nil
8708 *
8709 * With no arguments, does nothing.
8710 *
8711 */
8712
8713static VALUE
8714rb_f_printf(int argc, VALUE *argv, VALUE _)
8715{
8716 VALUE out;
8717
8718 if (argc == 0) return Qnil;
8719 if (RB_TYPE_P(argv[0], T_STRING)) {
8720 out = rb_ractor_stdout();
8721 }
8722 else {
8723 out = argv[0];
8724 argv++;
8725 argc--;
8726 }
8727 rb_io_write(out, rb_f_sprintf(argc, argv));
8728
8729 return Qnil;
8730}
8731
8732extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
8733
8734static void
8735deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8736{
8737 rb_deprecated_str_setter(val, id, &val);
8738 if (!NIL_P(val)) {
8739 if (rb_str_equal(val, rb_default_rs)) {
8740 val = rb_default_rs;
8741 }
8742 else {
8743 val = rb_str_frozen_bare_string(val);
8744 }
8745 }
8746 *var = val;
8747}
8748
8749/*
8750 * call-seq:
8751 * print(*objects) -> nil
8752 *
8753 * Writes the given objects to the stream; returns +nil+.
8754 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8755 * (<tt>$\</tt>), if it is not +nil+.
8756 * See {Line IO}[rdoc-ref:IO@Line+IO].
8757 *
8758 * With argument +objects+ given, for each object:
8759 *
8760 * - Converts via its method +to_s+ if not a string.
8761 * - Writes to the stream.
8762 * - If not the last object, writes the output field separator
8763 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8764 *
8765 * With default separators:
8766 *
8767 * f = File.open('t.tmp', 'w+')
8768 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8769 * p $OUTPUT_RECORD_SEPARATOR
8770 * p $OUTPUT_FIELD_SEPARATOR
8771 * f.print(*objects)
8772 * f.rewind
8773 * p f.read
8774 * f.close
8775 *
8776 * Output:
8777 *
8778 * nil
8779 * nil
8780 * "00.00/10+0izerozero"
8781 *
8782 * With specified separators:
8783 *
8784 * $\ = "\n"
8785 * $, = ','
8786 * f.rewind
8787 * f.print(*objects)
8788 * f.rewind
8789 * p f.read
8790 *
8791 * Output:
8792 *
8793 * "0,0.0,0/1,0+0i,zero,zero\n"
8794 *
8795 * With no argument given, writes the content of <tt>$_</tt>
8796 * (which is usually the most recent user input):
8797 *
8798 * f = File.open('t.tmp', 'w+')
8799 * gets # Sets $_ to the most recent user input.
8800 * f.print
8801 * f.close
8802 *
8803 */
8804
8805VALUE
8806rb_io_print(int argc, const VALUE *argv, VALUE out)
8807{
8808 int i;
8809 VALUE line;
8810
8811 /* if no argument given, print `$_' */
8812 if (argc == 0) {
8813 argc = 1;
8814 line = rb_lastline_get();
8815 argv = &line;
8816 }
8817 if (argc > 1 && !NIL_P(rb_output_fs)) {
8818 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8819 }
8820 for (i=0; i<argc; i++) {
8821 if (!NIL_P(rb_output_fs) && i>0) {
8822 rb_io_write(out, rb_output_fs);
8823 }
8824 rb_io_write(out, argv[i]);
8825 }
8826 if (argc > 0 && !NIL_P(rb_output_rs)) {
8827 rb_io_write(out, rb_output_rs);
8828 }
8829
8830 return Qnil;
8831}
8832
8833/*
8834 * call-seq:
8835 * print(*objects) -> nil
8836 *
8837 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8838 * this method is the straightforward way to write to <tt>$stdout</tt>.
8839 *
8840 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8841 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8842 * <tt>$\</tt>), if it is not +nil+.
8843 *
8844 * With argument +objects+ given, for each object:
8845 *
8846 * - Converts via its method +to_s+ if not a string.
8847 * - Writes to <tt>stdout</tt>.
8848 * - If not the last object, writes the output field separator
8849 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8850 *
8851 * With default separators:
8852 *
8853 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8854 * $OUTPUT_RECORD_SEPARATOR
8855 * $OUTPUT_FIELD_SEPARATOR
8856 * print(*objects)
8857 *
8858 * Output:
8859 *
8860 * nil
8861 * nil
8862 * 00.00/10+0izerozero
8863 *
8864 * With specified separators:
8865 *
8866 * $OUTPUT_RECORD_SEPARATOR = "\n"
8867 * $OUTPUT_FIELD_SEPARATOR = ','
8868 * print(*objects)
8869 *
8870 * Output:
8871 *
8872 * 0,0.0,0/1,0+0i,zero,zero
8873 *
8874 * With no argument given, writes the content of <tt>$_</tt>
8875 * (which is usually the most recent user input):
8876 *
8877 * gets # Sets $_ to the most recent user input.
8878 * print # Prints $_.
8879 *
8880 */
8881
8882static VALUE
8883rb_f_print(int argc, const VALUE *argv, VALUE _)
8884{
8885 rb_io_print(argc, argv, rb_ractor_stdout());
8886 return Qnil;
8887}
8888
8889/*
8890 * call-seq:
8891 * putc(object) -> object
8892 *
8893 * Writes a character to the stream.
8894 * See {Character IO}[rdoc-ref:IO@Character+IO].
8895 *
8896 * If +object+ is numeric, converts to integer if necessary,
8897 * then writes the character whose code is the
8898 * least significant byte;
8899 * if +object+ is a string, writes the first character:
8900 *
8901 * $stdout.putc "A"
8902 * $stdout.putc 65
8903 *
8904 * Output:
8905 *
8906 * AA
8907 *
8908 */
8909
8910static VALUE
8911rb_io_putc(VALUE io, VALUE ch)
8912{
8913 VALUE str;
8914 if (RB_TYPE_P(ch, T_STRING)) {
8915 str = rb_str_substr(ch, 0, 1);
8916 }
8917 else {
8918 char c = NUM2CHR(ch);
8919 str = rb_str_new(&c, 1);
8920 }
8921 rb_io_write(io, str);
8922 return ch;
8923}
8924
8925#define forward(obj, id, argc, argv) \
8926 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8927#define forward_public(obj, id, argc, argv) \
8928 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8929#define forward_current(id, argc, argv) \
8930 forward_public(ARGF.current_file, id, argc, argv)
8931
8932/*
8933 * call-seq:
8934 * putc(int) -> int
8935 *
8936 * Equivalent to:
8937 *
8938 * $stdout.putc(int)
8939 *
8940 * See IO#putc for important information regarding multi-byte characters.
8941 *
8942 */
8943
8944static VALUE
8945rb_f_putc(VALUE recv, VALUE ch)
8946{
8947 VALUE r_stdout = rb_ractor_stdout();
8948 if (recv == r_stdout) {
8949 return rb_io_putc(recv, ch);
8950 }
8951 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8952}
8953
8954
8955int
8956rb_str_end_with_asciichar(VALUE str, int c)
8957{
8958 long len = RSTRING_LEN(str);
8959 const char *ptr = RSTRING_PTR(str);
8960 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8961 int n;
8962
8963 if (len == 0) return 0;
8964 if ((n = rb_enc_mbminlen(enc)) == 1) {
8965 return ptr[len - 1] == c;
8966 }
8967 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8968}
8969
8970static VALUE
8971io_puts_ary(VALUE ary, VALUE out, int recur)
8972{
8973 VALUE tmp;
8974 long i;
8975
8976 if (recur) {
8977 tmp = rb_str_new2("[...]");
8978 rb_io_puts(1, &tmp, out);
8979 return Qtrue;
8980 }
8981 ary = rb_check_array_type(ary);
8982 if (NIL_P(ary)) return Qfalse;
8983 for (i=0; i<RARRAY_LEN(ary); i++) {
8984 tmp = RARRAY_AREF(ary, i);
8985 rb_io_puts(1, &tmp, out);
8986 }
8987 return Qtrue;
8988}
8989
8990/*
8991 * call-seq:
8992 * puts(*objects) -> nil
8993 *
8994 * Writes the given +objects+ to the stream, which must be open for writing;
8995 * returns +nil+.\
8996 * Writes a newline after each that does not already end with a newline sequence.
8997 * If called without arguments, writes a newline.
8998 * See {Line IO}[rdoc-ref:IO@Line+IO].
8999 *
9000 * Note that each added newline is the character <tt>"\n"<//tt>,
9001 * not the output record separator (<tt>$\</tt>).
9002 *
9003 * Treatment for each object:
9004 *
9005 * - String: writes the string.
9006 * - Neither string nor array: writes <tt>object.to_s</tt>.
9007 * - Array: writes each element of the array; arrays may be nested.
9008 *
9009 * To keep these examples brief, we define this helper method:
9010 *
9011 * def show(*objects)
9012 * # Puts objects to file.
9013 * f = File.new('t.tmp', 'w+')
9014 * f.puts(objects)
9015 * # Return file content.
9016 * f.rewind
9017 * p f.read
9018 * f.close
9019 * end
9020 *
9021 * # Strings without newlines.
9022 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
9023 * # Strings, some with newlines.
9024 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
9025 *
9026 * # Neither strings nor arrays:
9027 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
9028 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
9029 *
9030 * # Array of strings.
9031 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
9032 * # Nested arrays.
9033 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
9034 *
9035 */
9036
9037VALUE
9038rb_io_puts(int argc, const VALUE *argv, VALUE out)
9039{
9040 VALUE line, args[2];
9041
9042 /* if no argument given, print newline. */
9043 if (argc == 0) {
9044 rb_io_write(out, rb_default_rs);
9045 return Qnil;
9046 }
9047 for (int i = 0; i < argc; i++) {
9048 // Convert the argument to a string:
9049 if (RB_TYPE_P(argv[i], T_STRING)) {
9050 line = argv[i];
9051 }
9052 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9053 continue;
9054 }
9055 else {
9056 line = rb_obj_as_string(argv[i]);
9057 }
9058
9059 // Write the line:
9060 int n = 0;
9061 if (RSTRING_LEN(line) == 0) {
9062 args[n++] = rb_default_rs;
9063 }
9064 else {
9065 args[n++] = line;
9066 if (!rb_str_end_with_asciichar(line, '\n')) {
9067 args[n++] = rb_default_rs;
9068 }
9069 }
9070
9071 rb_io_writev(out, n, args);
9072 }
9073
9074 return Qnil;
9075}
9076
9077/*
9078 * call-seq:
9079 * puts(*objects) -> nil
9080 *
9081 * Equivalent to
9082 *
9083 * $stdout.puts(objects)
9084 */
9085
9086static VALUE
9087rb_f_puts(int argc, VALUE *argv, VALUE recv)
9088{
9089 VALUE r_stdout = rb_ractor_stdout();
9090 if (recv == r_stdout) {
9091 return rb_io_puts(argc, argv, recv);
9092 }
9093 return forward(r_stdout, rb_intern("puts"), argc, argv);
9094}
9095
9096static VALUE
9097rb_p_write(VALUE str)
9098{
9099 VALUE args[2];
9100 args[0] = str;
9101 args[1] = rb_default_rs;
9102 VALUE r_stdout = rb_ractor_stdout();
9103 if (RB_TYPE_P(r_stdout, T_FILE) &&
9104 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9105 io_writev(2, args, r_stdout);
9106 }
9107 else {
9108 rb_io_writev(r_stdout, 2, args);
9109 }
9110 return Qnil;
9111}
9112
9113void
9114rb_p(VALUE obj) /* for debug print within C code */
9115{
9116 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9117}
9118
9119static VALUE
9120rb_p_result(int argc, const VALUE *argv)
9121{
9122 VALUE ret = Qnil;
9123
9124 if (argc == 1) {
9125 ret = argv[0];
9126 }
9127 else if (argc > 1) {
9128 ret = rb_ary_new4(argc, argv);
9129 }
9130 VALUE r_stdout = rb_ractor_stdout();
9131 if (RB_TYPE_P(r_stdout, T_FILE)) {
9132 rb_uninterruptible(rb_io_flush, r_stdout);
9133 }
9134 return ret;
9135}
9136
9137/*
9138 * call-seq:
9139 * p(object) -> obj
9140 * p(*objects) -> array of objects
9141 * p -> nil
9142 *
9143 * For each object +obj+, executes:
9144 *
9145 * $stdout.write(obj.inspect, "\n")
9146 *
9147 * With one object given, returns the object;
9148 * with multiple objects given, returns an array containing the objects;
9149 * with no object given, returns +nil+.
9150 *
9151 * Examples:
9152 *
9153 * r = Range.new(0, 4)
9154 * p r # => 0..4
9155 * p [r, r, r] # => [0..4, 0..4, 0..4]
9156 * p # => nil
9157 *
9158 * Output:
9159 *
9160 * 0..4
9161 * [0..4, 0..4, 0..4]
9162 *
9163 * Kernel#p is designed for debugging purposes.
9164 * Ruby implementations may define Kernel#p to be uninterruptible
9165 * in whole or in part.
9166 * On CRuby, Kernel#p's writing of data is uninterruptible.
9167 */
9168
9169static VALUE
9170rb_f_p(int argc, VALUE *argv, VALUE self)
9171{
9172 int i;
9173 for (i=0; i<argc; i++) {
9174 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9175 rb_uninterruptible(rb_p_write, inspected);
9176 }
9177 return rb_p_result(argc, argv);
9178}
9179
9180/*
9181 * call-seq:
9182 * display(port = $>) -> nil
9183 *
9184 * Writes +self+ on the given port:
9185 *
9186 * 1.display
9187 * "cat".display
9188 * [ 4, 5, 6 ].display
9189 * puts
9190 *
9191 * Output:
9192 *
9193 * 1cat[4, 5, 6]
9194 *
9195 */
9196
9197static VALUE
9198rb_obj_display(int argc, VALUE *argv, VALUE self)
9199{
9200 VALUE out;
9201
9202 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9203 rb_io_write(out, self);
9204
9205 return Qnil;
9206}
9207
9208static int
9209rb_stderr_to_original_p(VALUE err)
9210{
9211 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9212}
9213
9214void
9215rb_write_error2(const char *mesg, long len)
9216{
9217 VALUE out = rb_ractor_stderr();
9218 if (rb_stderr_to_original_p(out)) {
9219#ifdef _WIN32
9220 if (isatty(fileno(stderr))) {
9221 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9222 }
9223#endif
9224 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9225 /* failed to write to stderr, what can we do? */
9226 return;
9227 }
9228 }
9229 else {
9230 rb_io_write(out, rb_str_new(mesg, len));
9231 }
9232}
9233
9234void
9235rb_write_error(const char *mesg)
9236{
9237 rb_write_error2(mesg, strlen(mesg));
9238}
9239
9240void
9241rb_write_error_str(VALUE mesg)
9242{
9243 VALUE out = rb_ractor_stderr();
9244 /* a stopgap measure for the time being */
9245 if (rb_stderr_to_original_p(out)) {
9246 size_t len = (size_t)RSTRING_LEN(mesg);
9247#ifdef _WIN32
9248 if (isatty(fileno(stderr))) {
9249 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9250 }
9251#endif
9252 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9253 RB_GC_GUARD(mesg);
9254 return;
9255 }
9256 }
9257 else {
9258 /* may unlock GVL, and */
9259 rb_io_write(out, mesg);
9260 }
9261}
9262
9263int
9264rb_stderr_tty_p(void)
9265{
9266 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9267 return isatty(fileno(stderr));
9268 return 0;
9269}
9270
9271static void
9272must_respond_to(ID mid, VALUE val, ID id)
9273{
9274 if (!rb_respond_to(val, mid)) {
9275 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9276 rb_id2str(id), rb_id2str(mid),
9277 rb_obj_class(val));
9278 }
9279}
9280
9281static void
9282stdin_setter(VALUE val, ID id, VALUE *ptr)
9283{
9285}
9286
9287static VALUE
9288stdin_getter(ID id, VALUE *ptr)
9289{
9290 return rb_ractor_stdin();
9291}
9292
9293static void
9294stdout_setter(VALUE val, ID id, VALUE *ptr)
9295{
9296 must_respond_to(id_write, val, id);
9298}
9299
9300static VALUE
9301stdout_getter(ID id, VALUE *ptr)
9302{
9303 return rb_ractor_stdout();
9304}
9305
9306static void
9307stderr_setter(VALUE val, ID id, VALUE *ptr)
9308{
9309 must_respond_to(id_write, val, id);
9311}
9312
9313static VALUE
9314stderr_getter(ID id, VALUE *ptr)
9315{
9316 return rb_ractor_stderr();
9317}
9318
9319static VALUE
9320allocate_and_open_new_file(VALUE klass)
9321{
9322 VALUE self = io_alloc(klass);
9323 rb_io_make_open_file(self);
9324 return self;
9325}
9326
9327VALUE
9328rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9329{
9330 int state;
9331 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9332 if (state) {
9333 /* if we raised an exception allocating an IO object, but the caller
9334 intended to transfer ownership of this FD to us, close the fd before
9335 raising the exception. Otherwise, we would leak a FD - the caller
9336 expects GC to close the file, but we never got around to assigning
9337 it to a rb_io. */
9338 if (!(mode & FMODE_EXTERNAL)) {
9339 maygvl_close(descriptor, 0);
9340 }
9341 rb_jump_tag(state);
9342 }
9343
9344
9345 rb_io_t *io = RFILE(self)->fptr;
9346 io->self = self;
9347 io->fd = descriptor;
9348 io->mode = mode;
9349
9350 /* At this point, Ruby fully owns the descriptor, and will close it when
9351 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9352 in the rest of this method. */
9353
9354 if (NIL_P(path)) {
9355 io->pathv = Qnil;
9356 }
9357 else {
9358 StringValue(path);
9359 io->pathv = rb_str_new_frozen(path);
9360 }
9361
9362 io->timeout = timeout;
9363
9364 ccan_list_head_init(&io->blocking_operations);
9365 io->closing_ec = NULL;
9366 io->wakeup_mutex = Qnil;
9367 io->fork_generation = GET_VM()->fork_gen;
9368
9369 if (encoding) {
9370 io->encs = *encoding;
9371 }
9372
9373 rb_update_max_fd(descriptor);
9374
9375 return self;
9376}
9377
9378static VALUE
9379prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9380{
9381 VALUE path_value = Qnil;
9382 rb_encoding *e;
9383 struct rb_io_encoding convconfig;
9384
9385 if (path) {
9386 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9387 }
9388
9389 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9390 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9391 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9394#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9395 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9396 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9397 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9398#endif
9399 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9400 convconfig.ecopts = Qnil;
9401
9402 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9403 rb_io_t*io = RFILE(self)->fptr;
9404
9405 if (!io_check_tty(io)) {
9406#ifdef __CYGWIN__
9407 io->mode |= FMODE_BINMODE;
9408 setmode(fd, O_BINARY);
9409#endif
9410 }
9411
9412 return self;
9413}
9414
9415VALUE
9416rb_io_fdopen(int fd, int oflags, const char *path)
9417{
9418 VALUE klass = rb_cIO;
9419
9420 if (path && strcmp(path, "-")) klass = rb_cFile;
9421 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9422}
9423
9424static VALUE
9425prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9426{
9427 rb_io_t *fptr;
9428 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9429
9430 GetOpenFile(io, fptr);
9432#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9433 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9434 if (fmode & FMODE_READABLE) {
9436 }
9437#endif
9438 fptr->stdio_file = f;
9439
9440 return io;
9441}
9442
9443VALUE
9444rb_io_prep_stdin(void)
9445{
9446 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9447}
9448
9449VALUE
9450rb_io_prep_stdout(void)
9451{
9452 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9453}
9454
9455VALUE
9456rb_io_prep_stderr(void)
9457{
9458 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9459}
9460
9461FILE *
9462rb_io_stdio_file(rb_io_t *fptr)
9463{
9464 if (!fptr->stdio_file) {
9465 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9466 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9467 }
9468 return fptr->stdio_file;
9469}
9470
9471static inline void
9472rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9473{
9474 buf->ptr = NULL;
9475 buf->off = 0;
9476 buf->len = 0;
9477 buf->capa = 0;
9478}
9479
9480static inline rb_io_t *
9481rb_io_fptr_new(void)
9482{
9483 rb_io_t *fp = ALLOC(rb_io_t);
9484 fp->self = Qnil;
9485 fp->fd = -1;
9486 fp->stdio_file = NULL;
9487 fp->mode = 0;
9488 fp->pid = 0;
9489 fp->lineno = 0;
9490 fp->pathv = Qnil;
9491 fp->finalize = 0;
9492 rb_io_buffer_init(&fp->wbuf);
9493 rb_io_buffer_init(&fp->rbuf);
9494 rb_io_buffer_init(&fp->cbuf);
9495 fp->readconv = NULL;
9496 fp->writeconv = NULL;
9498 fp->writeconv_pre_ecflags = 0;
9500 fp->writeconv_initialized = 0;
9501 fp->tied_io_for_writing = 0;
9502 fp->encs.enc = NULL;
9503 fp->encs.enc2 = NULL;
9504 fp->encs.ecflags = 0;
9505 fp->encs.ecopts = Qnil;
9506 fp->write_lock = Qnil;
9507 fp->timeout = Qnil;
9508 ccan_list_head_init(&fp->blocking_operations);
9509 fp->closing_ec = NULL;
9510 fp->wakeup_mutex = Qnil;
9511 fp->fork_generation = GET_VM()->fork_gen;
9512 return fp;
9513}
9514
9515rb_io_t *
9516rb_io_make_open_file(VALUE obj)
9517{
9518 rb_io_t *fp = 0;
9519
9520 Check_Type(obj, T_FILE);
9521 if (RFILE(obj)->fptr) {
9522 rb_io_close(obj);
9523 rb_io_fptr_finalize(RFILE(obj)->fptr);
9524 RFILE(obj)->fptr = 0;
9525 }
9526 fp = rb_io_fptr_new();
9527 fp->self = obj;
9528 RFILE(obj)->fptr = fp;
9529 return fp;
9530}
9531
9532static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9533
9534/*
9535 * call-seq:
9536 * IO.new(fd, mode = 'r', **opts) -> io
9537 *
9538 * Creates and returns a new \IO object (file stream) from a file descriptor.
9539 *
9540 * \IO.new may be useful for interaction with low-level libraries.
9541 * For higher-level interactions, it may be simpler to create
9542 * the file stream using File.open.
9543 *
9544 * Argument +fd+ must be a valid file descriptor (integer):
9545 *
9546 * path = 't.tmp'
9547 * fd = IO.sysopen(path) # => 3
9548 * IO.new(fd) # => #<IO:fd 3>
9549 *
9550 * The new \IO object does not inherit encoding
9551 * (because the integer file descriptor does not have an encoding):
9552 *
9553 * fd = IO.sysopen('t.rus', 'rb')
9554 * io = IO.new(fd)
9555 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9556 *
9557 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9558 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9559 *
9560 * IO.new(fd, 'w') # => #<IO:fd 3>
9561 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9562 *
9563 * Optional keyword arguments +opts+ specify:
9564 *
9565 * - {Open Options}[rdoc-ref:IO@Open+Options].
9566 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9567 *
9568 * Examples:
9569 *
9570 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9571 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9572 *
9573 */
9574
9575static VALUE
9576rb_io_initialize(int argc, VALUE *argv, VALUE io)
9577{
9578 VALUE fnum, vmode;
9579 VALUE opt;
9580
9581 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9582 return io_initialize(io, fnum, vmode, opt);
9583}
9584
9585static VALUE
9586io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9587{
9588 rb_io_t *fp;
9589 int fd, oflags = O_RDONLY;
9590 enum rb_io_mode fmode;
9591 struct rb_io_encoding convconfig;
9592#if defined(HAVE_FCNTL) && defined(F_GETFL)
9593 int ofmode;
9594#else
9595 struct stat st;
9596#endif
9597
9598 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9599
9600 fd = NUM2INT(fnum);
9601 if (rb_reserved_fd_p(fd)) {
9602 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9603 }
9604#if defined(HAVE_FCNTL) && defined(F_GETFL)
9605 oflags = fcntl(fd, F_GETFL);
9606 if (oflags == -1) rb_sys_fail(0);
9607#else
9608 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9609#endif
9610 rb_update_max_fd(fd);
9611#if defined(HAVE_FCNTL) && defined(F_GETFL)
9612 ofmode = rb_io_oflags_fmode(oflags);
9613 if (NIL_P(vmode)) {
9614 fmode = ofmode;
9615 }
9616 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9617 VALUE error = INT2FIX(EINVAL);
9619 }
9620#endif
9621 VALUE path = Qnil;
9622
9623 if (!NIL_P(opt)) {
9624 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9625 fmode |= FMODE_EXTERNAL;
9626 }
9627
9628 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9629 if (!NIL_P(path)) {
9630 StringValue(path);
9631 path = rb_str_new_frozen(path);
9632 }
9633 }
9634
9635 MakeOpenFile(io, fp);
9636 fp->self = io;
9637 fp->fd = fd;
9638 fp->mode = fmode;
9639 fp->encs = convconfig;
9640 fp->pathv = path;
9641 fp->timeout = Qnil;
9642 ccan_list_head_init(&fp->blocking_operations);
9643 fp->closing_ec = NULL;
9644 fp->wakeup_mutex = Qnil;
9645 fp->fork_generation = GET_VM()->fork_gen;
9646 clear_codeconv(fp);
9647 io_check_tty(fp);
9648 if (fileno(stdin) == fd)
9649 fp->stdio_file = stdin;
9650 else if (fileno(stdout) == fd)
9651 fp->stdio_file = stdout;
9652 else if (fileno(stderr) == fd)
9653 fp->stdio_file = stderr;
9654
9655 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9656 return io;
9657}
9658
9659/*
9660 * call-seq:
9661 * set_encoding_by_bom -> encoding or nil
9662 *
9663 * If the stream begins with a BOM
9664 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9665 * consumes the BOM and sets the external encoding accordingly;
9666 * returns the result encoding if found, or +nil+ otherwise:
9667 *
9668 * File.write('t.tmp', "\u{FEFF}abc")
9669 * io = File.open('t.tmp', 'rb')
9670 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9671 * io.close
9672 *
9673 * File.write('t.tmp', 'abc')
9674 * io = File.open('t.tmp', 'rb')
9675 * io.set_encoding_by_bom # => nil
9676 * io.close
9677 *
9678 * Raises an exception if the stream is not binmode
9679 * or its encoding has already been set.
9680 *
9681 */
9682
9683static VALUE
9684rb_io_set_encoding_by_bom(VALUE io)
9685{
9686 rb_io_t *fptr;
9687
9688 GetOpenFile(io, fptr);
9689 if (!(fptr->mode & FMODE_BINMODE)) {
9690 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9691 }
9692 if (fptr->encs.enc2) {
9693 rb_raise(rb_eArgError, "encoding conversion is set");
9694 }
9695 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9696 rb_raise(rb_eArgError, "encoding is set to %s already",
9697 rb_enc_name(fptr->encs.enc));
9698 }
9699 if (!io_set_encoding_by_bom(io)) return Qnil;
9700 return rb_enc_from_encoding(fptr->encs.enc);
9701}
9702
9703/*
9704 * call-seq:
9705 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9706 *
9707 * Opens the file at the given +path+ according to the given +mode+;
9708 * creates and returns a new File object for that file.
9709 *
9710 * The new File object is buffered mode (or non-sync mode), unless
9711 * +filename+ is a tty.
9712 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9713 *
9714 * Argument +path+ must be a valid file path:
9715 *
9716 * f = File.new('/etc/fstab')
9717 * f.close
9718 * f = File.new('t.txt')
9719 * f.close
9720 *
9721 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9722 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9723 *
9724 * f = File.new('t.tmp', 'w')
9725 * f.close
9726 * f = File.new('t.tmp', File::RDONLY)
9727 * f.close
9728 *
9729 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9730 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9731 *
9732 * f = File.new('t.tmp', File::CREAT, 0644)
9733 * f.close
9734 * f = File.new('t.tmp', File::CREAT, 0444)
9735 * f.close
9736 *
9737 * Optional keyword arguments +opts+ specify:
9738 *
9739 * - {Open Options}[rdoc-ref:IO@Open+Options].
9740 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9741 *
9742 */
9743
9744static VALUE
9745rb_file_initialize(int argc, VALUE *argv, VALUE io)
9746{
9747 if (RFILE(io)->fptr) {
9748 rb_raise(rb_eRuntimeError, "reinitializing File");
9749 }
9750 VALUE fname, vmode, vperm, opt;
9751 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9752 if (posargc < 3) { /* perm is File only */
9753 VALUE fd = rb_check_to_int(fname);
9754
9755 if (!NIL_P(fd)) {
9756 return io_initialize(io, fd, vmode, opt);
9757 }
9758 }
9759 return rb_open_file(io, fname, vmode, vperm, opt);
9760}
9761
9762/* :nodoc: */
9763static VALUE
9764rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9765{
9766 if (rb_block_given_p()) {
9767 VALUE cname = rb_obj_as_string(klass);
9768
9769 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9770 cname, cname);
9771 }
9772 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9773}
9774
9775
9776/*
9777 * call-seq:
9778 * IO.for_fd(fd, mode = 'r', **opts) -> io
9779 *
9780 * Synonym for IO.new.
9781 *
9782 */
9783
9784static VALUE
9785rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9786{
9787 VALUE io = rb_obj_alloc(klass);
9788 rb_io_initialize(argc, argv, io);
9789 return io;
9790}
9791
9792/*
9793 * call-seq:
9794 * ios.autoclose? -> true or false
9795 *
9796 * Returns +true+ if the underlying file descriptor of _ios_ will be
9797 * closed at its finalization or at calling #close, otherwise +false+.
9798 */
9799
9800static VALUE
9801rb_io_autoclose_p(VALUE io)
9802{
9803 rb_io_t *fptr = RFILE(io)->fptr;
9804 rb_io_check_closed(fptr);
9805 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9806}
9807
9808/*
9809 * call-seq:
9810 * io.autoclose = bool -> true or false
9811 *
9812 * Sets auto-close flag.
9813 *
9814 * f = File.open(File::NULL)
9815 * IO.for_fd(f.fileno).close
9816 * f.gets # raises Errno::EBADF
9817 *
9818 * f = File.open(File::NULL)
9819 * g = IO.for_fd(f.fileno)
9820 * g.autoclose = false
9821 * g.close
9822 * f.gets # won't cause Errno::EBADF
9823 */
9824
9825static VALUE
9826rb_io_set_autoclose(VALUE io, VALUE autoclose)
9827{
9828 rb_io_t *fptr;
9829 GetOpenFile(io, fptr);
9830 if (!RTEST(autoclose))
9831 fptr->mode |= FMODE_EXTERNAL;
9832 else
9833 fptr->mode &= ~FMODE_EXTERNAL;
9834 return autoclose;
9835}
9836
9837static VALUE
9838io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9839{
9840 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9841
9842 if (!RB_TEST(result)) {
9843 return Qnil;
9844 }
9845
9846 int mask = RB_NUM2INT(result);
9847
9848 if (mask & event) {
9849 if (return_io)
9850 return io;
9851 else
9852 return result;
9853 }
9854 else {
9855 return Qfalse;
9856 }
9857}
9858
9859/*
9860 * call-seq:
9861 * io.wait_readable -> truthy or falsy
9862 * io.wait_readable(timeout) -> truthy or falsy
9863 *
9864 * Waits until IO is readable and returns a truthy value, or a falsy
9865 * value when times out. Returns a truthy value immediately when
9866 * buffered data is available.
9867 */
9868
9869static VALUE
9870io_wait_readable(int argc, VALUE *argv, VALUE io)
9871{
9872 rb_io_t *fptr;
9873
9874 RB_IO_POINTER(io, fptr);
9876
9877 if (rb_io_read_pending(fptr)) return Qtrue;
9878
9879 rb_check_arity(argc, 0, 1);
9880 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9881
9882 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9883}
9884
9885/*
9886 * call-seq:
9887 * io.wait_writable -> truthy or falsy
9888 * io.wait_writable(timeout) -> truthy or falsy
9889 *
9890 * Waits until IO is writable and returns a truthy value or a falsy
9891 * value when times out.
9892 */
9893static VALUE
9894io_wait_writable(int argc, VALUE *argv, VALUE io)
9895{
9896 rb_io_t *fptr;
9897
9898 RB_IO_POINTER(io, fptr);
9900
9901 rb_check_arity(argc, 0, 1);
9902 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9903
9904 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9905}
9906
9907/*
9908 * call-seq:
9909 * io.wait_priority -> truthy or falsy
9910 * io.wait_priority(timeout) -> truthy or falsy
9911 *
9912 * Waits until IO is priority and returns a truthy value or a falsy
9913 * value when times out. Priority data is sent and received using
9914 * the Socket::MSG_OOB flag and is typically limited to streams.
9915 */
9916static VALUE
9917io_wait_priority(int argc, VALUE *argv, VALUE io)
9918{
9919 rb_io_t *fptr = NULL;
9920
9921 RB_IO_POINTER(io, fptr);
9923
9924 if (rb_io_read_pending(fptr)) return Qtrue;
9925
9926 rb_check_arity(argc, 0, 1);
9927 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9928
9929 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9930}
9931
9932static int
9933wait_mode_sym(VALUE mode)
9934{
9935 if (mode == ID2SYM(rb_intern("r"))) {
9936 return RB_WAITFD_IN;
9937 }
9938 if (mode == ID2SYM(rb_intern("read"))) {
9939 return RB_WAITFD_IN;
9940 }
9941 if (mode == ID2SYM(rb_intern("readable"))) {
9942 return RB_WAITFD_IN;
9943 }
9944 if (mode == ID2SYM(rb_intern("w"))) {
9945 return RB_WAITFD_OUT;
9946 }
9947 if (mode == ID2SYM(rb_intern("write"))) {
9948 return RB_WAITFD_OUT;
9949 }
9950 if (mode == ID2SYM(rb_intern("writable"))) {
9951 return RB_WAITFD_OUT;
9952 }
9953 if (mode == ID2SYM(rb_intern("rw"))) {
9954 return RB_WAITFD_IN|RB_WAITFD_OUT;
9955 }
9956 if (mode == ID2SYM(rb_intern("read_write"))) {
9957 return RB_WAITFD_IN|RB_WAITFD_OUT;
9958 }
9959 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9960 return RB_WAITFD_IN|RB_WAITFD_OUT;
9961 }
9962
9963 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9964}
9965
9966static inline enum rb_io_event
9967io_event_from_value(VALUE value)
9968{
9969 int events = RB_NUM2INT(value);
9970
9971 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9972
9973 return events;
9974}
9975
9976/*
9977 * call-seq:
9978 * io.wait(events, timeout) -> event mask, false or nil
9979 * io.wait(*event_symbols[, timeout]) -> self, true, or false
9980 *
9981 * Waits until the IO becomes ready for the specified events and returns the
9982 * subset of events that become ready, or a falsy value when times out.
9983 *
9984 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9985 * +IO::PRIORITY+.
9986 *
9987 * Returns an event mask (truthy value) immediately when buffered data is
9988 * available.
9989 *
9990 * The second form: if one or more event symbols (+:read+, +:write+, or
9991 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
9992 * corresponding to those symbols. In this form, +timeout+ is optional, the
9993 * order of the arguments is arbitrary, and returns +io+ if any of the
9994 * events is ready.
9995 */
9996
9997static VALUE
9998io_wait(int argc, VALUE *argv, VALUE io)
9999{
10000 VALUE timeout = Qundef;
10001 enum rb_io_event events = 0;
10002 int return_io = 0;
10003
10004 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
10005 // We'd prefer to return the actual mask, but this form would return the io itself:
10006 return_io = 1;
10007
10008 // Slow/messy path:
10009 for (int i = 0; i < argc; i += 1) {
10010 if (RB_SYMBOL_P(argv[i])) {
10011 events |= wait_mode_sym(argv[i]);
10012 }
10013 else if (UNDEF_P(timeout)) {
10014 rb_time_interval(timeout = argv[i]);
10015 }
10016 else {
10017 rb_raise(rb_eArgError, "timeout given more than once");
10018 }
10019 }
10020
10021 if (UNDEF_P(timeout)) timeout = Qnil;
10022
10023 if (events == 0) {
10024 events = RUBY_IO_READABLE;
10025 }
10026 }
10027 else /* argc == 2 and neither are symbols */ {
10028 // This is the fast path:
10029 events = io_event_from_value(argv[0]);
10030 timeout = argv[1];
10031 }
10032
10033 if (events & RUBY_IO_READABLE) {
10034 rb_io_t *fptr = NULL;
10035 RB_IO_POINTER(io, fptr);
10036
10037 if (rb_io_read_pending(fptr)) {
10038 // This was the original behaviour:
10039 if (return_io) return Qtrue;
10040 // New behaviour always returns an event mask:
10041 else return RB_INT2NUM(RUBY_IO_READABLE);
10042 }
10043 }
10044
10045 return io_wait_event(io, events, timeout, return_io);
10046}
10047
10048static void
10049argf_mark_and_move(void *ptr)
10050{
10051 struct argf *p = ptr;
10052 rb_gc_mark_and_move(&p->filename);
10053 rb_gc_mark_and_move(&p->current_file);
10054 rb_gc_mark_and_move(&p->argv);
10055 rb_gc_mark_and_move(&p->inplace);
10056 rb_gc_mark_and_move(&p->encs.ecopts);
10057}
10058
10059static size_t
10060argf_memsize(const void *ptr)
10061{
10062 const struct argf *p = ptr;
10063 size_t size = sizeof(*p);
10064 return size;
10065}
10066
10067static const rb_data_type_t argf_type = {
10068 "ARGF",
10069 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10070 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
10071};
10072
10073static inline void
10074argf_init(struct argf *p, VALUE v)
10075{
10076 p->filename = Qnil;
10077 p->current_file = Qnil;
10078 p->lineno = 0;
10079 p->argv = v;
10080}
10081
10082static VALUE
10083argf_alloc(VALUE klass)
10084{
10085 struct argf *p;
10086 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10087
10088 argf_init(p, Qnil);
10089 return argf;
10090}
10091
10092#undef rb_argv
10093
10094/* :nodoc: */
10095static VALUE
10096argf_initialize(VALUE argf, VALUE argv)
10097{
10098 memset(&ARGF, 0, sizeof(ARGF));
10099 argf_init(&ARGF, argv);
10100
10101 return argf;
10102}
10103
10104/* :nodoc: */
10105static VALUE
10106argf_initialize_copy(VALUE argf, VALUE orig)
10107{
10108 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10109 ARGF = argf_of(orig);
10110 ARGF.argv = rb_obj_dup(ARGF.argv);
10111 return argf;
10112}
10113
10114/*
10115 * call-seq:
10116 * ARGF.lineno = integer -> integer
10117 *
10118 * Sets the line number of ARGF as a whole to the given Integer.
10119 *
10120 * ARGF sets the line number automatically as you read data, so normally
10121 * you will not need to set it explicitly. To access the current line number
10122 * use ARGF.lineno.
10123 *
10124 * For example:
10125 *
10126 * ARGF.lineno #=> 0
10127 * ARGF.readline #=> "This is line 1\n"
10128 * ARGF.lineno #=> 1
10129 * ARGF.lineno = 0 #=> 0
10130 * ARGF.lineno #=> 0
10131 */
10132static VALUE
10133argf_set_lineno(VALUE argf, VALUE val)
10134{
10135 ARGF.lineno = NUM2INT(val);
10136 ARGF.last_lineno = ARGF.lineno;
10137 return val;
10138}
10139
10140/*
10141 * call-seq:
10142 * ARGF.lineno -> integer
10143 *
10144 * Returns the current line number of ARGF as a whole. This value
10145 * can be set manually with ARGF.lineno=.
10146 *
10147 * For example:
10148 *
10149 * ARGF.lineno #=> 0
10150 * ARGF.readline #=> "This is line 1\n"
10151 * ARGF.lineno #=> 1
10152 */
10153static VALUE
10154argf_lineno(VALUE argf)
10155{
10156 return INT2FIX(ARGF.lineno);
10157}
10158
10159static VALUE
10160argf_forward(int argc, VALUE *argv, VALUE argf)
10161{
10162 return forward_current(rb_frame_this_func(), argc, argv);
10163}
10164
10165#define next_argv() argf_next_argv(argf)
10166#define ARGF_GENERIC_INPUT_P() \
10167 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10168#define ARGF_FORWARD(argc, argv) do {\
10169 if (ARGF_GENERIC_INPUT_P())\
10170 return argf_forward((argc), (argv), argf);\
10171} while (0)
10172#define NEXT_ARGF_FORWARD(argc, argv) do {\
10173 if (!next_argv()) return Qnil;\
10174 ARGF_FORWARD((argc), (argv));\
10175} while (0)
10176
10177static void
10178argf_close(VALUE argf)
10179{
10180 VALUE file = ARGF.current_file;
10181 if (file == rb_stdin) return;
10182 if (RB_TYPE_P(file, T_FILE)) {
10183 rb_io_set_write_io(file, Qnil);
10184 }
10185 io_close(file);
10186 ARGF.init_p = -1;
10187}
10188
10189static int
10190argf_next_argv(VALUE argf)
10191{
10192 char *fn;
10193 rb_io_t *fptr;
10194 int stdout_binmode = 0;
10195 enum rb_io_mode fmode;
10196
10197 VALUE r_stdout = rb_ractor_stdout();
10198
10199 if (RB_TYPE_P(r_stdout, T_FILE)) {
10200 GetOpenFile(r_stdout, fptr);
10201 if (fptr->mode & FMODE_BINMODE)
10202 stdout_binmode = 1;
10203 }
10204
10205 if (ARGF.init_p == 0) {
10206 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10207 ARGF.next_p = 1;
10208 }
10209 else {
10210 ARGF.next_p = -1;
10211 }
10212 ARGF.init_p = 1;
10213 }
10214 else {
10215 if (NIL_P(ARGF.argv)) {
10216 ARGF.next_p = -1;
10217 }
10218 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10219 ARGF.next_p = 1;
10220 }
10221 }
10222
10223 if (ARGF.next_p == 1) {
10224 if (ARGF.init_p == 1) argf_close(argf);
10225 retry:
10226 if (RARRAY_LEN(ARGF.argv) > 0) {
10227 VALUE filename = rb_ary_shift(ARGF.argv);
10228 FilePathValue(filename);
10229 ARGF.filename = filename;
10230 filename = rb_str_encode_ospath(filename);
10231 fn = StringValueCStr(filename);
10232 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10233 ARGF.current_file = rb_stdin;
10234 if (ARGF.inplace) {
10235 rb_warn("Can't do inplace edit for stdio; skipping");
10236 goto retry;
10237 }
10238 }
10239 else {
10240 VALUE write_io = Qnil;
10241 int fr = rb_sysopen(filename, O_RDONLY, 0);
10242
10243 if (ARGF.inplace) {
10244 struct stat st;
10245#ifndef NO_SAFE_RENAME
10246 struct stat st2;
10247#endif
10248 VALUE str;
10249 int fw;
10250
10251 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10252 rb_io_close(r_stdout);
10253 }
10254 fstat(fr, &st);
10255 str = filename;
10256 if (!NIL_P(ARGF.inplace)) {
10257 VALUE suffix = ARGF.inplace;
10258 str = rb_str_dup(str);
10259 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10260 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10261 rb_enc_get(suffix), 0, Qnil))) {
10262 rb_str_append(str, suffix);
10263 }
10264#ifdef NO_SAFE_RENAME
10265 (void)close(fr);
10266 (void)unlink(RSTRING_PTR(str));
10267 if (rename(fn, RSTRING_PTR(str)) < 0) {
10268 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10269 filename, str, strerror(errno));
10270 goto retry;
10271 }
10272 fr = rb_sysopen(str, O_RDONLY, 0);
10273#else
10274 if (rename(fn, RSTRING_PTR(str)) < 0) {
10275 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10276 filename, str, strerror(errno));
10277 close(fr);
10278 goto retry;
10279 }
10280#endif
10281 }
10282 else {
10283#ifdef NO_SAFE_RENAME
10284 rb_fatal("Can't do inplace edit without backup");
10285#else
10286 if (unlink(fn) < 0) {
10287 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10288 filename, strerror(errno));
10289 close(fr);
10290 goto retry;
10291 }
10292#endif
10293 }
10294 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10295#ifndef NO_SAFE_RENAME
10296 fstat(fw, &st2);
10297#ifdef HAVE_FCHMOD
10298 fchmod(fw, st.st_mode);
10299#else
10300 chmod(fn, st.st_mode);
10301#endif
10302 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10303 int err;
10304#ifdef HAVE_FCHOWN
10305 err = fchown(fw, st.st_uid, st.st_gid);
10306#else
10307 err = chown(fn, st.st_uid, st.st_gid);
10308#endif
10309 if (err && getuid() == 0 && st2.st_uid == 0) {
10310 const char *wkfn = RSTRING_PTR(filename);
10311 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10312 filename, str, strerror(errno));
10313 (void)close(fr);
10314 (void)close(fw);
10315 (void)unlink(wkfn);
10316 goto retry;
10317 }
10318 }
10319#endif
10320 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10321 rb_ractor_stdout_set(write_io);
10322 if (stdout_binmode) rb_io_binmode(rb_stdout);
10323 }
10324 fmode = FMODE_READABLE;
10325 if (!ARGF.binmode) {
10326 fmode |= DEFAULT_TEXTMODE;
10327 }
10328 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10329 if (!NIL_P(write_io)) {
10330 rb_io_set_write_io(ARGF.current_file, write_io);
10331 }
10332 RB_GC_GUARD(filename);
10333 }
10334 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10335 GetOpenFile(ARGF.current_file, fptr);
10336 if (ARGF.encs.enc) {
10337 fptr->encs = ARGF.encs;
10338 clear_codeconv(fptr);
10339 }
10340 else {
10342 if (!ARGF.binmode) {
10344#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10345 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10346#endif
10347 }
10348 }
10349 ARGF.next_p = 0;
10350 }
10351 else {
10352 ARGF.next_p = 1;
10353 return FALSE;
10354 }
10355 }
10356 else if (ARGF.next_p == -1) {
10357 ARGF.current_file = rb_stdin;
10358 ARGF.filename = rb_str_new2("-");
10359 if (ARGF.inplace) {
10360 rb_warn("Can't do inplace edit for stdio");
10361 rb_ractor_stdout_set(orig_stdout);
10362 }
10363 }
10364 if (ARGF.init_p == -1) ARGF.init_p = 1;
10365 return TRUE;
10366}
10367
10368static VALUE
10369argf_getline(int argc, VALUE *argv, VALUE argf)
10370{
10371 VALUE line;
10372 long lineno = ARGF.lineno;
10373
10374 retry:
10375 if (!next_argv()) return Qnil;
10376 if (ARGF_GENERIC_INPUT_P()) {
10377 line = forward_current(idGets, argc, argv);
10378 }
10379 else {
10380 if (argc == 0 && rb_rs == rb_default_rs) {
10381 line = rb_io_gets(ARGF.current_file);
10382 }
10383 else {
10384 line = rb_io_getline(argc, argv, ARGF.current_file);
10385 }
10386 if (NIL_P(line) && ARGF.next_p != -1) {
10387 argf_close(argf);
10388 ARGF.next_p = 1;
10389 goto retry;
10390 }
10391 }
10392 if (!NIL_P(line)) {
10393 ARGF.lineno = ++lineno;
10394 ARGF.last_lineno = ARGF.lineno;
10395 }
10396 return line;
10397}
10398
10399static VALUE
10400argf_lineno_getter(ID id, VALUE *var)
10401{
10402 VALUE argf = *var;
10403 return INT2FIX(ARGF.last_lineno);
10404}
10405
10406static void
10407argf_lineno_setter(VALUE val, ID id, VALUE *var)
10408{
10409 VALUE argf = *var;
10410 int n = NUM2INT(val);
10411 ARGF.last_lineno = ARGF.lineno = n;
10412}
10413
10414void
10415rb_reset_argf_lineno(long n)
10416{
10417 ARGF.last_lineno = ARGF.lineno = n;
10418}
10419
10420static VALUE argf_gets(int, VALUE *, VALUE);
10421
10422/*
10423 * call-seq:
10424 * gets(sep=$/ [, getline_args]) -> string or nil
10425 * gets(limit [, getline_args]) -> string or nil
10426 * gets(sep, limit [, getline_args]) -> string or nil
10427 *
10428 * Returns (and assigns to <code>$_</code>) the next line from the list
10429 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10430 * no files are present on the command line. Returns +nil+ at end of
10431 * file. The optional argument specifies the record separator. The
10432 * separator is included with the contents of each record. A separator
10433 * of +nil+ reads the entire contents, and a zero-length separator
10434 * reads the input one paragraph at a time, where paragraphs are
10435 * divided by two consecutive newlines. If the first argument is an
10436 * integer, or optional second argument is given, the returning string
10437 * would not be longer than the given value in bytes. If multiple
10438 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10439 * the contents one file at a time.
10440 *
10441 * ARGV << "testfile"
10442 * print while gets
10443 *
10444 * <em>produces:</em>
10445 *
10446 * This is line one
10447 * This is line two
10448 * This is line three
10449 * And so on...
10450 *
10451 * The style of programming using <code>$_</code> as an implicit
10452 * parameter is gradually losing favor in the Ruby community.
10453 */
10454
10455static VALUE
10456rb_f_gets(int argc, VALUE *argv, VALUE recv)
10457{
10458 if (recv == argf) {
10459 return argf_gets(argc, argv, argf);
10460 }
10461 return forward(argf, idGets, argc, argv);
10462}
10463
10464/*
10465 * call-seq:
10466 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10467 * ARGF.gets(limit [, getline_args]) -> string or nil
10468 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10469 *
10470 * Returns the next line from the current file in ARGF.
10471 *
10472 * By default lines are assumed to be separated by <code>$/</code>;
10473 * to use a different character as a separator, supply it as a String
10474 * for the _sep_ argument.
10475 *
10476 * The optional _limit_ argument specifies how many characters of each line
10477 * to return. By default all characters are returned.
10478 *
10479 * See IO.readlines for details about getline_args.
10480 *
10481 */
10482static VALUE
10483argf_gets(int argc, VALUE *argv, VALUE argf)
10484{
10485 VALUE line;
10486
10487 line = argf_getline(argc, argv, argf);
10488 rb_lastline_set(line);
10489
10490 return line;
10491}
10492
10493VALUE
10495{
10496 VALUE line;
10497
10498 if (rb_rs != rb_default_rs) {
10499 return rb_f_gets(0, 0, argf);
10500 }
10501
10502 retry:
10503 if (!next_argv()) return Qnil;
10504 line = rb_io_gets(ARGF.current_file);
10505 if (NIL_P(line) && ARGF.next_p != -1) {
10506 rb_io_close(ARGF.current_file);
10507 ARGF.next_p = 1;
10508 goto retry;
10509 }
10510 rb_lastline_set(line);
10511 if (!NIL_P(line)) {
10512 ARGF.lineno++;
10513 ARGF.last_lineno = ARGF.lineno;
10514 }
10515
10516 return line;
10517}
10518
10519static VALUE argf_readline(int, VALUE *, VALUE);
10520
10521/*
10522 * call-seq:
10523 * readline(sep = $/, chomp: false) -> string
10524 * readline(limit, chomp: false) -> string
10525 * readline(sep, limit, chomp: false) -> string
10526 *
10527 * Equivalent to method Kernel#gets, except that it raises an exception
10528 * if called at end-of-stream:
10529 *
10530 * $ cat t.txt | ruby -e "p readlines; readline"
10531 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10532 * in `readline': end of file reached (EOFError)
10533 *
10534 * Optional keyword argument +chomp+ specifies whether line separators
10535 * are to be omitted.
10536 */
10537
10538static VALUE
10539rb_f_readline(int argc, VALUE *argv, VALUE recv)
10540{
10541 if (recv == argf) {
10542 return argf_readline(argc, argv, argf);
10543 }
10544 return forward(argf, rb_intern("readline"), argc, argv);
10545}
10546
10547
10548/*
10549 * call-seq:
10550 * ARGF.readline(sep=$/) -> string
10551 * ARGF.readline(limit) -> string
10552 * ARGF.readline(sep, limit) -> string
10553 *
10554 * Returns the next line from the current file in ARGF.
10555 *
10556 * By default lines are assumed to be separated by <code>$/</code>;
10557 * to use a different character as a separator, supply it as a String
10558 * for the _sep_ argument.
10559 *
10560 * The optional _limit_ argument specifies how many characters of each line
10561 * to return. By default all characters are returned.
10562 *
10563 * An EOFError is raised at the end of the file.
10564 */
10565static VALUE
10566argf_readline(int argc, VALUE *argv, VALUE argf)
10567{
10568 VALUE line;
10569
10570 if (!next_argv()) rb_eof_error();
10571 ARGF_FORWARD(argc, argv);
10572 line = argf_gets(argc, argv, argf);
10573 if (NIL_P(line)) {
10574 rb_eof_error();
10575 }
10576
10577 return line;
10578}
10579
10580static VALUE argf_readlines(int, VALUE *, VALUE);
10581
10582/*
10583 * call-seq:
10584 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10585 * readlines(limit, chomp: false, **enc_opts) -> array
10586 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10587 *
10588 * Returns an array containing the lines returned by calling
10589 * Kernel#gets until the end-of-stream is reached;
10590 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10591 *
10592 * With only string argument +sep+ given,
10593 * returns the remaining lines as determined by line separator +sep+,
10594 * or +nil+ if none;
10595 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10596 *
10597 * # Default separator.
10598 * $ cat t.txt | ruby -e "p readlines"
10599 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10600 *
10601 * # Specified separator.
10602 * $ cat t.txt | ruby -e "p readlines 'li'"
10603 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10604 *
10605 * # Get-all separator.
10606 * $ cat t.txt | ruby -e "p readlines nil"
10607 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10608 *
10609 * # Get-paragraph separator.
10610 * $ cat t.txt | ruby -e "p readlines ''"
10611 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10612 *
10613 * With only integer argument +limit+ given,
10614 * limits the number of bytes in the line;
10615 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10616 *
10617 * $cat t.txt | ruby -e "p readlines 10"
10618 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10619 *
10620 * $cat t.txt | ruby -e "p readlines 11"
10621 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10622 *
10623 * $cat t.txt | ruby -e "p readlines 12"
10624 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10625 *
10626 * With arguments +sep+ and +limit+ given,
10627 * combines the two behaviors
10628 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10629 *
10630 * Optional keyword argument +chomp+ specifies whether line separators
10631 * are to be omitted:
10632 *
10633 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10634 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10635 *
10636 * Optional keyword arguments +enc_opts+ specify encoding options;
10637 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10638 *
10639 */
10640
10641static VALUE
10642rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10643{
10644 if (recv == argf) {
10645 return argf_readlines(argc, argv, argf);
10646 }
10647 return forward(argf, rb_intern("readlines"), argc, argv);
10648}
10649
10650/*
10651 * call-seq:
10652 * ARGF.readlines(sep = $/, chomp: false) -> array
10653 * ARGF.readlines(limit, chomp: false) -> array
10654 * ARGF.readlines(sep, limit, chomp: false) -> array
10655 *
10656 * ARGF.to_a(sep = $/, chomp: false) -> array
10657 * ARGF.to_a(limit, chomp: false) -> array
10658 * ARGF.to_a(sep, limit, chomp: false) -> array
10659 *
10660 * Reads each file in ARGF in its entirety, returning an Array containing
10661 * lines from the files. Lines are assumed to be separated by _sep_.
10662 *
10663 * lines = ARGF.readlines
10664 * lines[0] #=> "This is line one\n"
10665 *
10666 * See +IO.readlines+ for a full description of all options.
10667 */
10668static VALUE
10669argf_readlines(int argc, VALUE *argv, VALUE argf)
10670{
10671 long lineno = ARGF.lineno;
10672 VALUE lines, ary;
10673
10674 ary = rb_ary_new();
10675 while (next_argv()) {
10676 if (ARGF_GENERIC_INPUT_P()) {
10677 lines = forward_current(rb_intern("readlines"), argc, argv);
10678 }
10679 else {
10680 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10681 argf_close(argf);
10682 }
10683 ARGF.next_p = 1;
10684 rb_ary_concat(ary, lines);
10685 ARGF.lineno = lineno + RARRAY_LEN(ary);
10686 ARGF.last_lineno = ARGF.lineno;
10687 }
10688 ARGF.init_p = 0;
10689 return ary;
10690}
10691
10692/*
10693 * call-seq:
10694 * `command` -> string
10695 *
10696 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10697 * sets global variable <tt>$?</tt> to the process status.
10698 *
10699 * This method has potential security vulnerabilities if called with untrusted input;
10700 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
10701 *
10702 * Examples:
10703 *
10704 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10705 * $ `echo oops && exit 99` # => "oops\n"
10706 * $ $? # => #<Process::Status: pid 17088 exit 99>
10707 * $ $?.exitstatus # => 99
10708 *
10709 * The built-in syntax <tt>%x{...}</tt> uses this method.
10710 *
10711 */
10712
10713static VALUE
10714rb_f_backquote(VALUE obj, VALUE str)
10715{
10716 VALUE port;
10717 VALUE result;
10718 rb_io_t *fptr;
10719
10720 StringValue(str);
10721 rb_last_status_clear();
10722 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10723 if (NIL_P(port)) return rb_str_new(0,0);
10724
10725 GetOpenFile(port, fptr);
10726 result = read_all(fptr, remain_size(fptr), Qnil);
10727 rb_io_close(port);
10728 rb_io_fptr_cleanup_all(fptr);
10729 RB_GC_GUARD(port);
10730
10731 return result;
10732}
10733
10734#ifdef HAVE_SYS_SELECT_H
10735#include <sys/select.h>
10736#endif
10737
10738static VALUE
10739select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10740{
10741 VALUE res, list;
10742 rb_fdset_t *rp, *wp, *ep;
10743 rb_io_t *fptr;
10744 long i;
10745 int max = 0, n;
10746 int pending = 0;
10747 struct timeval timerec;
10748
10749 if (!NIL_P(read)) {
10750 Check_Type(read, T_ARRAY);
10751 for (i=0; i<RARRAY_LEN(read); i++) {
10752 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10753 rb_fd_set(fptr->fd, &fds[0]);
10754 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10755 pending++;
10756 rb_fd_set(fptr->fd, &fds[3]);
10757 }
10758 if (max < fptr->fd) max = fptr->fd;
10759 }
10760 if (pending) { /* no blocking if there's buffered data */
10761 timerec.tv_sec = timerec.tv_usec = 0;
10762 tp = &timerec;
10763 }
10764 rp = &fds[0];
10765 }
10766 else
10767 rp = 0;
10768
10769 if (!NIL_P(write)) {
10770 Check_Type(write, T_ARRAY);
10771 for (i=0; i<RARRAY_LEN(write); i++) {
10772 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10773 GetOpenFile(write_io, fptr);
10774 rb_fd_set(fptr->fd, &fds[1]);
10775 if (max < fptr->fd) max = fptr->fd;
10776 }
10777 wp = &fds[1];
10778 }
10779 else
10780 wp = 0;
10781
10782 if (!NIL_P(except)) {
10783 Check_Type(except, T_ARRAY);
10784 for (i=0; i<RARRAY_LEN(except); i++) {
10785 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10786 VALUE write_io = GetWriteIO(io);
10787 GetOpenFile(io, fptr);
10788 rb_fd_set(fptr->fd, &fds[2]);
10789 if (max < fptr->fd) max = fptr->fd;
10790 if (io != write_io) {
10791 GetOpenFile(write_io, fptr);
10792 rb_fd_set(fptr->fd, &fds[2]);
10793 if (max < fptr->fd) max = fptr->fd;
10794 }
10795 }
10796 ep = &fds[2];
10797 }
10798 else {
10799 ep = 0;
10800 }
10801
10802 max++;
10803
10804 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10805 if (n < 0) {
10806 rb_sys_fail(0);
10807 }
10808 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10809
10810 res = rb_ary_new2(3);
10811 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10812 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10813 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10814
10815 if (rp) {
10816 list = RARRAY_AREF(res, 0);
10817 for (i=0; i< RARRAY_LEN(read); i++) {
10818 VALUE obj = rb_ary_entry(read, i);
10819 VALUE io = rb_io_get_io(obj);
10820 GetOpenFile(io, fptr);
10821 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10822 rb_fd_isset(fptr->fd, &fds[3])) {
10823 rb_ary_push(list, obj);
10824 }
10825 }
10826 }
10827
10828 if (wp) {
10829 list = RARRAY_AREF(res, 1);
10830 for (i=0; i< RARRAY_LEN(write); i++) {
10831 VALUE obj = rb_ary_entry(write, i);
10832 VALUE io = rb_io_get_io(obj);
10833 VALUE write_io = GetWriteIO(io);
10834 GetOpenFile(write_io, fptr);
10835 if (rb_fd_isset(fptr->fd, &fds[1])) {
10836 rb_ary_push(list, obj);
10837 }
10838 }
10839 }
10840
10841 if (ep) {
10842 list = RARRAY_AREF(res, 2);
10843 for (i=0; i< RARRAY_LEN(except); i++) {
10844 VALUE obj = rb_ary_entry(except, i);
10845 VALUE io = rb_io_get_io(obj);
10846 VALUE write_io = GetWriteIO(io);
10847 GetOpenFile(io, fptr);
10848 if (rb_fd_isset(fptr->fd, &fds[2])) {
10849 rb_ary_push(list, obj);
10850 }
10851 else if (io != write_io) {
10852 GetOpenFile(write_io, fptr);
10853 if (rb_fd_isset(fptr->fd, &fds[2])) {
10854 rb_ary_push(list, obj);
10855 }
10856 }
10857 }
10858 }
10859
10860 return res; /* returns an empty array on interrupt */
10861}
10862
10864 VALUE read, write, except;
10865 struct timeval *timeout;
10866 rb_fdset_t fdsets[4];
10867};
10868
10869static VALUE
10870select_call(VALUE arg)
10871{
10872 struct select_args *p = (struct select_args *)arg;
10873
10874 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10875}
10876
10877static VALUE
10878select_end(VALUE arg)
10879{
10880 struct select_args *p = (struct select_args *)arg;
10881 int i;
10882
10883 for (i = 0; i < numberof(p->fdsets); ++i)
10884 rb_fd_term(&p->fdsets[i]);
10885 return Qnil;
10886}
10887
10888static VALUE sym_normal, sym_sequential, sym_random,
10889 sym_willneed, sym_dontneed, sym_noreuse;
10890
10891#ifdef HAVE_POSIX_FADVISE
10892struct io_advise_struct {
10893 int fd;
10894 int advice;
10895 rb_off_t offset;
10896 rb_off_t len;
10897};
10898
10899static VALUE
10900io_advise_internal(void *arg)
10901{
10902 struct io_advise_struct *ptr = arg;
10903 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10904}
10905
10906static VALUE
10907io_advise_sym_to_const(VALUE sym)
10908{
10909#ifdef POSIX_FADV_NORMAL
10910 if (sym == sym_normal)
10911 return INT2NUM(POSIX_FADV_NORMAL);
10912#endif
10913
10914#ifdef POSIX_FADV_RANDOM
10915 if (sym == sym_random)
10916 return INT2NUM(POSIX_FADV_RANDOM);
10917#endif
10918
10919#ifdef POSIX_FADV_SEQUENTIAL
10920 if (sym == sym_sequential)
10921 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10922#endif
10923
10924#ifdef POSIX_FADV_WILLNEED
10925 if (sym == sym_willneed)
10926 return INT2NUM(POSIX_FADV_WILLNEED);
10927#endif
10928
10929#ifdef POSIX_FADV_DONTNEED
10930 if (sym == sym_dontneed)
10931 return INT2NUM(POSIX_FADV_DONTNEED);
10932#endif
10933
10934#ifdef POSIX_FADV_NOREUSE
10935 if (sym == sym_noreuse)
10936 return INT2NUM(POSIX_FADV_NOREUSE);
10937#endif
10938
10939 return Qnil;
10940}
10941
10942static VALUE
10943do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10944{
10945 int rv;
10946 struct io_advise_struct ias;
10947 VALUE num_adv;
10948
10949 num_adv = io_advise_sym_to_const(advice);
10950
10951 /*
10952 * The platform doesn't support this hint. We don't raise exception, instead
10953 * silently ignore it. Because IO::advise is only hint.
10954 */
10955 if (NIL_P(num_adv))
10956 return Qnil;
10957
10958 ias.fd = fptr->fd;
10959 ias.advice = NUM2INT(num_adv);
10960 ias.offset = offset;
10961 ias.len = len;
10962
10963 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10964 if (rv && rv != ENOSYS) {
10965 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10966 it returns the error code. */
10967 VALUE message = rb_sprintf("%"PRIsVALUE" "
10968 "(%"PRI_OFFT_PREFIX"d, "
10969 "%"PRI_OFFT_PREFIX"d, "
10970 "%"PRIsVALUE")",
10971 fptr->pathv, offset, len, advice);
10972 rb_syserr_fail_str(rv, message);
10973 }
10974
10975 return Qnil;
10976}
10977
10978#endif /* HAVE_POSIX_FADVISE */
10979
10980static void
10981advice_arg_check(VALUE advice)
10982{
10983 if (!SYMBOL_P(advice))
10984 rb_raise(rb_eTypeError, "advice must be a Symbol");
10985
10986 if (advice != sym_normal &&
10987 advice != sym_sequential &&
10988 advice != sym_random &&
10989 advice != sym_willneed &&
10990 advice != sym_dontneed &&
10991 advice != sym_noreuse) {
10992 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10993 }
10994}
10995
10996/*
10997 * call-seq:
10998 * advise(advice, offset = 0, len = 0) -> nil
10999 *
11000 * Invokes Posix system call
11001 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
11002 * which announces an intention to access data from the current file
11003 * in a particular manner.
11004 *
11005 * The arguments and results are platform-dependent.
11006 *
11007 * The relevant data is specified by:
11008 *
11009 * - +offset+: The offset of the first byte of data.
11010 * - +len+: The number of bytes to be accessed;
11011 * if +len+ is zero, or is larger than the number of bytes remaining,
11012 * all remaining bytes will be accessed.
11013 *
11014 * Argument +advice+ is one of the following symbols:
11015 *
11016 * - +:normal+: The application has no advice to give
11017 * about its access pattern for the specified data.
11018 * If no advice is given for an open file, this is the default assumption.
11019 * - +:sequential+: The application expects to access the specified data sequentially
11020 * (with lower offsets read before higher ones).
11021 * - +:random+: The specified data will be accessed in random order.
11022 * - +:noreuse+: The specified data will be accessed only once.
11023 * - +:willneed+: The specified data will be accessed in the near future.
11024 * - +:dontneed+: The specified data will not be accessed in the near future.
11025 *
11026 * Not implemented on all platforms.
11027 *
11028 */
11029static VALUE
11030rb_io_advise(int argc, VALUE *argv, VALUE io)
11031{
11032 VALUE advice, offset, len;
11033 rb_off_t off, l;
11034 rb_io_t *fptr;
11035
11036 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
11037 advice_arg_check(advice);
11038
11039 io = GetWriteIO(io);
11040 GetOpenFile(io, fptr);
11041
11042 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
11043 l = NIL_P(len) ? 0 : NUM2OFFT(len);
11044
11045#ifdef HAVE_POSIX_FADVISE
11046 return do_io_advise(fptr, advice, off, l);
11047#else
11048 ((void)off, (void)l); /* Ignore all hint */
11049 return Qnil;
11050#endif
11051}
11052
11053static int
11054is_pos_inf(VALUE x)
11055{
11056 double f;
11057 if (!RB_FLOAT_TYPE_P(x))
11058 return 0;
11059 f = RFLOAT_VALUE(x);
11060 return isinf(f) && 0 < f;
11061}
11062
11063/*
11064 * call-seq:
11065 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11066 *
11067 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
11068 * which monitors multiple file descriptors,
11069 * waiting until one or more of the file descriptors
11070 * becomes ready for some class of I/O operation.
11071 *
11072 * Not implemented on all platforms.
11073 *
11074 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11075 * is an array of IO objects.
11076 *
11077 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11078 * interval in seconds.
11079 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11080 * +nil+ and +Float::INFINITY+ means no timeout.
11081 *
11082 * The method monitors the \IO objects given in all three arrays,
11083 * waiting for some to be ready;
11084 * returns a 3-element array whose elements are:
11085 *
11086 * - An array of the objects in +read_ios+ that are ready for reading.
11087 * - An array of the objects in +write_ios+ that are ready for writing.
11088 * - An array of the objects in +error_ios+ have pending exceptions.
11089 *
11090 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11091 *
11092 * \IO.select peeks the buffer of \IO objects for testing readability.
11093 * If the \IO buffer is not empty, \IO.select immediately notifies
11094 * readability. This "peek" only happens for \IO objects. It does not
11095 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11096 *
11097 * The best way to use \IO.select is invoking it after non-blocking
11098 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11099 * raise an exception which is extended by IO::WaitReadable or
11100 * IO::WaitWritable. The modules notify how the caller should wait
11101 * with \IO.select. If IO::WaitReadable is raised, the caller should
11102 * wait for reading. If IO::WaitWritable is raised, the caller should
11103 * wait for writing.
11104 *
11105 * So, blocking read (#readpartial) can be emulated using
11106 * #read_nonblock and \IO.select as follows:
11107 *
11108 * begin
11109 * result = io_like.read_nonblock(maxlen)
11110 * rescue IO::WaitReadable
11111 * IO.select([io_like])
11112 * retry
11113 * rescue IO::WaitWritable
11114 * IO.select(nil, [io_like])
11115 * retry
11116 * end
11117 *
11118 * Especially, the combination of non-blocking methods and \IO.select is
11119 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11120 * has #to_io method to return underlying IO object. IO.select calls
11121 * #to_io to obtain the file descriptor to wait.
11122 *
11123 * This means that readability notified by \IO.select doesn't mean
11124 * readability from OpenSSL::SSL::SSLSocket object.
11125 *
11126 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11127 * some data. \IO.select doesn't see the buffer. So \IO.select can
11128 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11129 *
11130 * However, several more complicated situations exist.
11131 *
11132 * SSL is a protocol which is sequence of records.
11133 * The record consists of multiple bytes.
11134 * So, the remote side of SSL sends a partial record, IO.select
11135 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11136 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11137 *
11138 * Also, the remote side can request SSL renegotiation which forces
11139 * the local SSL engine to write some data.
11140 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11141 * system call and it can block.
11142 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11143 * IO::WaitWritable instead of blocking.
11144 * So, the caller should wait for ready for writability as above
11145 * example.
11146 *
11147 * The combination of non-blocking methods and \IO.select is also useful
11148 * for streams such as tty, pipe socket socket when multiple processes
11149 * read from a stream.
11150 *
11151 * Finally, Linux kernel developers don't guarantee that
11152 * readability of select(2) means readability of following read(2) even
11153 * for a single process;
11154 * see {select(2)}[https://linux.die.net/man/2/select]
11155 *
11156 * Invoking \IO.select before IO#readpartial works well as usual.
11157 * However it is not the best way to use \IO.select.
11158 *
11159 * The writability notified by select(2) doesn't show
11160 * how many bytes are writable.
11161 * IO#write method blocks until given whole string is written.
11162 * So, <tt>IO#write(two or more bytes)</tt> can block after
11163 * writability is notified by \IO.select. IO#write_nonblock is required
11164 * to avoid the blocking.
11165 *
11166 * Blocking write (#write) can be emulated using #write_nonblock and
11167 * IO.select as follows: IO::WaitReadable should also be rescued for
11168 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11169 *
11170 * while 0 < string.bytesize
11171 * begin
11172 * written = io_like.write_nonblock(string)
11173 * rescue IO::WaitReadable
11174 * IO.select([io_like])
11175 * retry
11176 * rescue IO::WaitWritable
11177 * IO.select(nil, [io_like])
11178 * retry
11179 * end
11180 * string = string.byteslice(written..-1)
11181 * end
11182 *
11183 * Example:
11184 *
11185 * rp, wp = IO.pipe
11186 * mesg = "ping "
11187 * 100.times {
11188 * # IO.select follows IO#read. Not the best way to use IO.select.
11189 * rs, ws, = IO.select([rp], [wp])
11190 * if r = rs[0]
11191 * ret = r.read(5)
11192 * print ret
11193 * case ret
11194 * when /ping/
11195 * mesg = "pong\n"
11196 * when /pong/
11197 * mesg = "ping "
11198 * end
11199 * end
11200 * if w = ws[0]
11201 * w.write(mesg)
11202 * end
11203 * }
11204 *
11205 * Output:
11206 *
11207 * ping pong
11208 * ping pong
11209 * ping pong
11210 * (snipped)
11211 * ping
11212 *
11213 */
11214
11215static VALUE
11216rb_f_select(int argc, VALUE *argv, VALUE obj)
11217{
11218 VALUE scheduler = rb_fiber_scheduler_current();
11219 if (scheduler != Qnil) {
11220 // It's optionally supported.
11221 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11222 if (!UNDEF_P(result)) return result;
11223 }
11224
11225 VALUE timeout;
11226 struct select_args args;
11227 struct timeval timerec;
11228 int i;
11229
11230 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11231 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11232 args.timeout = 0;
11233 }
11234 else {
11235 timerec = rb_time_interval(timeout);
11236 args.timeout = &timerec;
11237 }
11238
11239 for (i = 0; i < numberof(args.fdsets); ++i)
11240 rb_fd_init(&args.fdsets[i]);
11241
11242 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11243}
11244
11245#ifdef IOCTL_REQ_TYPE
11246 typedef IOCTL_REQ_TYPE ioctl_req_t;
11247#else
11248 typedef int ioctl_req_t;
11249# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11250#endif
11251
11252#ifdef HAVE_IOCTL
11253struct ioctl_arg {
11254 int fd;
11255 ioctl_req_t cmd;
11256 long narg;
11257};
11258
11259static VALUE
11260nogvl_ioctl(void *ptr)
11261{
11262 struct ioctl_arg *arg = ptr;
11263
11264 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11265}
11266
11267static int
11268do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11269{
11270 int retval;
11271 struct ioctl_arg arg;
11272
11273 arg.fd = io->fd;
11274 arg.cmd = cmd;
11275 arg.narg = narg;
11276
11277 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11278
11279 return retval;
11280}
11281#endif
11282
11283#define DEFAULT_IOCTL_NARG_LEN (256)
11284
11285#if defined(__linux__) && defined(_IOC_SIZE)
11286static long
11287linux_iocparm_len(ioctl_req_t cmd)
11288{
11289 long len;
11290
11291 if ((cmd & 0xFFFF0000) == 0) {
11292 /* legacy and unstructured ioctl number. */
11293 return DEFAULT_IOCTL_NARG_LEN;
11294 }
11295
11296 len = _IOC_SIZE(cmd);
11297
11298 /* paranoia check for silly drivers which don't keep ioctl convention */
11299 if (len < DEFAULT_IOCTL_NARG_LEN)
11300 len = DEFAULT_IOCTL_NARG_LEN;
11301
11302 return len;
11303}
11304#endif
11305
11306#ifdef HAVE_IOCTL
11307static long
11308ioctl_narg_len(ioctl_req_t cmd)
11309{
11310 long len;
11311
11312#ifdef IOCPARM_MASK
11313#ifndef IOCPARM_LEN
11314#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11315#endif
11316#endif
11317#ifdef IOCPARM_LEN
11318 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11319#elif defined(__linux__) && defined(_IOC_SIZE)
11320 len = linux_iocparm_len(cmd);
11321#else
11322 /* otherwise guess at what's safe */
11323 len = DEFAULT_IOCTL_NARG_LEN;
11324#endif
11325
11326 return len;
11327}
11328#endif
11329
11330#ifdef HAVE_FCNTL
11331#ifdef __linux__
11332typedef long fcntl_arg_t;
11333#else
11334/* posix */
11335typedef int fcntl_arg_t;
11336#endif
11337
11338static long
11339fcntl_narg_len(ioctl_req_t cmd)
11340{
11341 long len;
11342
11343 switch (cmd) {
11344#ifdef F_DUPFD
11345 case F_DUPFD:
11346 len = sizeof(fcntl_arg_t);
11347 break;
11348#endif
11349#ifdef F_DUP2FD /* bsd specific */
11350 case F_DUP2FD:
11351 len = sizeof(int);
11352 break;
11353#endif
11354#ifdef F_DUPFD_CLOEXEC /* linux specific */
11355 case F_DUPFD_CLOEXEC:
11356 len = sizeof(fcntl_arg_t);
11357 break;
11358#endif
11359#ifdef F_GETFD
11360 case F_GETFD:
11361 len = 1;
11362 break;
11363#endif
11364#ifdef F_SETFD
11365 case F_SETFD:
11366 len = sizeof(fcntl_arg_t);
11367 break;
11368#endif
11369#ifdef F_GETFL
11370 case F_GETFL:
11371 len = 1;
11372 break;
11373#endif
11374#ifdef F_SETFL
11375 case F_SETFL:
11376 len = sizeof(fcntl_arg_t);
11377 break;
11378#endif
11379#ifdef F_GETOWN
11380 case F_GETOWN:
11381 len = 1;
11382 break;
11383#endif
11384#ifdef F_SETOWN
11385 case F_SETOWN:
11386 len = sizeof(fcntl_arg_t);
11387 break;
11388#endif
11389#ifdef F_GETOWN_EX /* linux specific */
11390 case F_GETOWN_EX:
11391 len = sizeof(struct f_owner_ex);
11392 break;
11393#endif
11394#ifdef F_SETOWN_EX /* linux specific */
11395 case F_SETOWN_EX:
11396 len = sizeof(struct f_owner_ex);
11397 break;
11398#endif
11399#ifdef F_GETLK
11400 case F_GETLK:
11401 len = sizeof(struct flock);
11402 break;
11403#endif
11404#ifdef F_SETLK
11405 case F_SETLK:
11406 len = sizeof(struct flock);
11407 break;
11408#endif
11409#ifdef F_SETLKW
11410 case F_SETLKW:
11411 len = sizeof(struct flock);
11412 break;
11413#endif
11414#ifdef F_READAHEAD /* bsd specific */
11415 case F_READAHEAD:
11416 len = sizeof(int);
11417 break;
11418#endif
11419#ifdef F_RDAHEAD /* Darwin specific */
11420 case F_RDAHEAD:
11421 len = sizeof(int);
11422 break;
11423#endif
11424#ifdef F_GETSIG /* linux specific */
11425 case F_GETSIG:
11426 len = 1;
11427 break;
11428#endif
11429#ifdef F_SETSIG /* linux specific */
11430 case F_SETSIG:
11431 len = sizeof(fcntl_arg_t);
11432 break;
11433#endif
11434#ifdef F_GETLEASE /* linux specific */
11435 case F_GETLEASE:
11436 len = 1;
11437 break;
11438#endif
11439#ifdef F_SETLEASE /* linux specific */
11440 case F_SETLEASE:
11441 len = sizeof(fcntl_arg_t);
11442 break;
11443#endif
11444#ifdef F_NOTIFY /* linux specific */
11445 case F_NOTIFY:
11446 len = sizeof(fcntl_arg_t);
11447 break;
11448#endif
11449
11450 default:
11451 len = 256;
11452 break;
11453 }
11454
11455 return len;
11456}
11457#else /* HAVE_FCNTL */
11458static long
11459fcntl_narg_len(ioctl_req_t cmd)
11460{
11461 return 0;
11462}
11463#endif /* HAVE_FCNTL */
11464
11465#define NARG_SENTINEL 17
11466
11467static long
11468setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11469{
11470 long narg = 0;
11471 VALUE arg = *argp;
11472
11473 if (!RTEST(arg)) {
11474 narg = 0;
11475 }
11476 else if (FIXNUM_P(arg)) {
11477 narg = FIX2LONG(arg);
11478 }
11479 else if (arg == Qtrue) {
11480 narg = 1;
11481 }
11482 else {
11483 VALUE tmp = rb_check_string_type(arg);
11484
11485 if (NIL_P(tmp)) {
11486 narg = NUM2LONG(arg);
11487 }
11488 else {
11489 char *ptr;
11490 long len, slen;
11491
11492 *argp = arg = tmp;
11493 len = narg_len(cmd);
11494 rb_str_modify(arg);
11495
11496 slen = RSTRING_LEN(arg);
11497 /* expand for data + sentinel. */
11498 if (slen < len+1) {
11499 rb_str_resize(arg, len+1);
11500 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11501 slen = len+1;
11502 }
11503 /* a little sanity check here */
11504 ptr = RSTRING_PTR(arg);
11505 ptr[slen - 1] = NARG_SENTINEL;
11506 narg = (long)(SIGNED_VALUE)ptr;
11507 }
11508 }
11509
11510 return narg;
11511}
11512
11513static VALUE
11514finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11515{
11516 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11517 if (RB_TYPE_P(arg, T_STRING)) {
11518 char *ptr;
11519 long slen;
11520 RSTRING_GETMEM(arg, ptr, slen);
11521 if (ptr[slen-1] != NARG_SENTINEL)
11522 rb_raise(rb_eArgError, "return value overflowed string");
11523 ptr[slen-1] = '\0';
11524 }
11525
11526 return INT2NUM(retval);
11527}
11528
11529#ifdef HAVE_IOCTL
11530static VALUE
11531rb_ioctl(VALUE io, VALUE req, VALUE arg)
11532{
11533 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11534 rb_io_t *fptr;
11535 long narg;
11536 int retval;
11537
11538 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11539 GetOpenFile(io, fptr);
11540 retval = do_ioctl(fptr, cmd, narg);
11541 return finish_narg(retval, arg, fptr);
11542}
11543
11544/*
11545 * call-seq:
11546 * ioctl(integer_cmd, argument) -> integer
11547 *
11548 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11549 * which issues a low-level command to an I/O device.
11550 *
11551 * Issues a low-level command to an I/O device.
11552 * The arguments and returned value are platform-dependent.
11553 * The effect of the call is platform-dependent.
11554 *
11555 * If argument +argument+ is an integer, it is passed directly;
11556 * if it is a string, it is interpreted as a binary sequence of bytes.
11557 *
11558 * Not implemented on all platforms.
11559 *
11560 */
11561
11562static VALUE
11563rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11564{
11565 VALUE req, arg;
11566
11567 rb_scan_args(argc, argv, "11", &req, &arg);
11568 return rb_ioctl(io, req, arg);
11569}
11570#else
11571#define rb_io_ioctl rb_f_notimplement
11572#endif
11573
11574#ifdef HAVE_FCNTL
11575struct fcntl_arg {
11576 int fd;
11577 int cmd;
11578 long narg;
11579};
11580
11581static VALUE
11582nogvl_fcntl(void *ptr)
11583{
11584 struct fcntl_arg *arg = ptr;
11585
11586#if defined(F_DUPFD)
11587 if (arg->cmd == F_DUPFD)
11588 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11589#endif
11590 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11591}
11592
11593static int
11594do_fcntl(struct rb_io *io, int cmd, long narg)
11595{
11596 int retval;
11597 struct fcntl_arg arg;
11598
11599 arg.fd = io->fd;
11600 arg.cmd = cmd;
11601 arg.narg = narg;
11602
11603 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11604 if (retval != -1) {
11605 switch (cmd) {
11606#if defined(F_DUPFD)
11607 case F_DUPFD:
11608#endif
11609#if defined(F_DUPFD_CLOEXEC)
11610 case F_DUPFD_CLOEXEC:
11611#endif
11612 rb_update_max_fd(retval);
11613 }
11614 }
11615
11616 return retval;
11617}
11618
11619static VALUE
11620rb_fcntl(VALUE io, VALUE req, VALUE arg)
11621{
11622 int cmd = NUM2INT(req);
11623 rb_io_t *fptr;
11624 long narg;
11625 int retval;
11626
11627 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11628 GetOpenFile(io, fptr);
11629 retval = do_fcntl(fptr, cmd, narg);
11630 return finish_narg(retval, arg, fptr);
11631}
11632
11633/*
11634 * call-seq:
11635 * fcntl(integer_cmd, argument) -> integer
11636 *
11637 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11638 * which provides a mechanism for issuing low-level commands to control or query
11639 * a file-oriented I/O stream. Arguments and results are platform
11640 * dependent.
11641 *
11642 * If +argument+ is a number, its value is passed directly;
11643 * if it is a string, it is interpreted as a binary sequence of bytes.
11644 * (Array#pack might be a useful way to build this string.)
11645 *
11646 * Not implemented on all platforms.
11647 *
11648 */
11649
11650static VALUE
11651rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11652{
11653 VALUE req, arg;
11654
11655 rb_scan_args(argc, argv, "11", &req, &arg);
11656 return rb_fcntl(io, req, arg);
11657}
11658#else
11659#define rb_io_fcntl rb_f_notimplement
11660#endif
11661
11662#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11663/*
11664 * call-seq:
11665 * syscall(integer_callno, *arguments) -> integer
11666 *
11667 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11668 * which calls a specified function.
11669 *
11670 * Calls the operating system function identified by +integer_callno+;
11671 * returns the result of the function or raises SystemCallError if it failed.
11672 * The effect of the call is platform-dependent.
11673 * The arguments and returned value are platform-dependent.
11674 *
11675 * For each of +arguments+: if it is an integer, it is passed directly;
11676 * if it is a string, it is interpreted as a binary sequence of bytes.
11677 * There may be as many as nine such arguments.
11678 *
11679 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11680 * are platform-dependent.
11681 *
11682 * Note: Method +syscall+ is essentially unsafe and unportable.
11683 * The DL (Fiddle) library is preferred for safer and a bit
11684 * more portable programming.
11685 *
11686 * Not implemented on all platforms.
11687 *
11688 */
11689
11690static VALUE
11691rb_f_syscall(int argc, VALUE *argv, VALUE _)
11692{
11693 VALUE arg[8];
11694#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11695# define SYSCALL __syscall
11696# define NUM2SYSCALLID(x) NUM2LONG(x)
11697# define RETVAL2NUM(x) LONG2NUM(x)
11698# if SIZEOF_LONG == 8
11699 long num, retval = -1;
11700# elif SIZEOF_LONG_LONG == 8
11701 long long num, retval = -1;
11702# else
11703# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11704# endif
11705#elif defined(__linux__)
11706# define SYSCALL syscall
11707# define NUM2SYSCALLID(x) NUM2LONG(x)
11708# define RETVAL2NUM(x) LONG2NUM(x)
11709 /*
11710 * Linux man page says, syscall(2) function prototype is below.
11711 *
11712 * int syscall(int number, ...);
11713 *
11714 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11715 */
11716 long num, retval = -1;
11717#else
11718# define SYSCALL syscall
11719# define NUM2SYSCALLID(x) NUM2INT(x)
11720# define RETVAL2NUM(x) INT2NUM(x)
11721 int num, retval = -1;
11722#endif
11723 int i;
11724
11725 if (RTEST(ruby_verbose)) {
11727 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11728 }
11729
11730 if (argc == 0)
11731 rb_raise(rb_eArgError, "too few arguments for syscall");
11732 if (argc > numberof(arg))
11733 rb_raise(rb_eArgError, "too many arguments for syscall");
11734 num = NUM2SYSCALLID(argv[0]); ++argv;
11735 for (i = argc - 1; i--; ) {
11736 VALUE v = rb_check_string_type(argv[i]);
11737
11738 if (!NIL_P(v)) {
11739 StringValue(v);
11740 rb_str_modify(v);
11741 arg[i] = (VALUE)StringValueCStr(v);
11742 }
11743 else {
11744 arg[i] = (VALUE)NUM2LONG(argv[i]);
11745 }
11746 }
11747
11748 switch (argc) {
11749 case 1:
11750 retval = SYSCALL(num);
11751 break;
11752 case 2:
11753 retval = SYSCALL(num, arg[0]);
11754 break;
11755 case 3:
11756 retval = SYSCALL(num, arg[0],arg[1]);
11757 break;
11758 case 4:
11759 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11760 break;
11761 case 5:
11762 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11763 break;
11764 case 6:
11765 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11766 break;
11767 case 7:
11768 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11769 break;
11770 case 8:
11771 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11772 break;
11773 }
11774
11775 if (retval == -1)
11776 rb_sys_fail(0);
11777 return RETVAL2NUM(retval);
11778#undef SYSCALL
11779#undef NUM2SYSCALLID
11780#undef RETVAL2NUM
11781}
11782#else
11783#define rb_f_syscall rb_f_notimplement
11784#endif
11785
11786static VALUE
11787io_new_instance(VALUE args)
11788{
11789 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11790}
11791
11792static rb_encoding *
11793find_encoding(VALUE v)
11794{
11795 rb_encoding *enc = rb_find_encoding(v);
11796 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11797 return enc;
11798}
11799
11800static void
11801io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11802{
11803 rb_encoding *enc, *enc2;
11804 int ecflags = fptr->encs.ecflags;
11805 VALUE ecopts, tmp;
11806
11807 if (!NIL_P(v2)) {
11808 enc2 = find_encoding(v1);
11809 tmp = rb_check_string_type(v2);
11810 if (!NIL_P(tmp)) {
11811 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11812 /* Special case - "-" => no transcoding */
11813 enc = enc2;
11814 enc2 = NULL;
11815 }
11816 else
11817 enc = find_encoding(v2);
11818 if (enc == enc2) {
11819 /* Special case - "-" => no transcoding */
11820 enc2 = NULL;
11821 }
11822 }
11823 else {
11824 enc = find_encoding(v2);
11825 if (enc == enc2) {
11826 /* Special case - "-" => no transcoding */
11827 enc2 = NULL;
11828 }
11829 }
11830 if (enc2 == rb_ascii8bit_encoding()) {
11831 /* If external is ASCII-8BIT, no transcoding */
11832 enc = enc2;
11833 enc2 = NULL;
11834 }
11835 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11836 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11837 }
11838 else {
11839 if (NIL_P(v1)) {
11840 /* Set to default encodings */
11841 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11842 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11843 ecopts = Qnil;
11844 }
11845 else {
11846 tmp = rb_check_string_type(v1);
11847 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11848 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11849 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11850 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11851 }
11852 else {
11853 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11854 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11855 ecopts = Qnil;
11856 }
11857 }
11858 }
11859 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11860 fptr->encs.enc = enc;
11861 fptr->encs.enc2 = enc2;
11862 fptr->encs.ecflags = ecflags;
11863 fptr->encs.ecopts = ecopts;
11864 clear_codeconv(fptr);
11865
11866}
11867
11869 rb_io_t *fptr;
11870 VALUE v1;
11871 VALUE v2;
11872 VALUE opt;
11873};
11874
11875static VALUE
11876io_encoding_set_v(VALUE v)
11877{
11878 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11879 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11880 return Qnil;
11881}
11882
11883static VALUE
11884pipe_pair_close(VALUE rw)
11885{
11886 VALUE *rwp = (VALUE *)rw;
11887 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11888}
11889
11890/*
11891 * call-seq:
11892 * IO.pipe(**opts) -> [read_io, write_io]
11893 * IO.pipe(enc, **opts) -> [read_io, write_io]
11894 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11895 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11896 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11897 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11898 *
11899 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11900 * connected to each other.
11901 *
11902 * If argument +enc_string+ is given, it must be a string containing one of:
11903 *
11904 * - The name of the encoding to be used as the external encoding.
11905 * - The colon-separated names of two encodings to be used as the external
11906 * and internal encodings.
11907 *
11908 * If argument +int_enc+ is given, it must be an Encoding object
11909 * or encoding name string that specifies the internal encoding to be used;
11910 * if argument +ext_enc+ is also given, it must be an Encoding object
11911 * or encoding name string that specifies the external encoding to be used.
11912 *
11913 * The string read from +read_io+ is tagged with the external encoding;
11914 * if an internal encoding is also specified, the string is converted
11915 * to, and tagged with, that encoding.
11916 *
11917 * If any encoding is specified,
11918 * optional hash arguments specify the conversion option.
11919 *
11920 * Optional keyword arguments +opts+ specify:
11921 *
11922 * - {Open Options}[rdoc-ref:IO@Open+Options].
11923 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11924 *
11925 * With no block given, returns the two endpoints in an array:
11926 *
11927 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11928 *
11929 * With a block given, calls the block with the two endpoints;
11930 * closes both endpoints and returns the value of the block:
11931 *
11932 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11933 *
11934 * Output:
11935 *
11936 * #<IO:fd 6>
11937 * #<IO:fd 7>
11938 *
11939 * Not available on all platforms.
11940 *
11941 * In the example below, the two processes close the ends of the pipe
11942 * that they are not using. This is not just a cosmetic nicety. The
11943 * read end of a pipe will not generate an end of file condition if
11944 * there are any writers with the pipe still open. In the case of the
11945 * parent process, the <tt>rd.read</tt> will never return if it
11946 * does not first issue a <tt>wr.close</tt>:
11947 *
11948 * rd, wr = IO.pipe
11949 *
11950 * if fork
11951 * wr.close
11952 * puts "Parent got: <#{rd.read}>"
11953 * rd.close
11954 * Process.wait
11955 * else
11956 * rd.close
11957 * puts 'Sending message to parent'
11958 * wr.write "Hi Dad"
11959 * wr.close
11960 * end
11961 *
11962 * <em>produces:</em>
11963 *
11964 * Sending message to parent
11965 * Parent got: <Hi Dad>
11966 *
11967 */
11968
11969static VALUE
11970rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11971{
11972 int pipes[2], state;
11973 VALUE r, w, args[3], v1, v2;
11974 VALUE opt;
11975 rb_io_t *fptr, *fptr2;
11976 struct io_encoding_set_args ies_args;
11977 enum rb_io_mode fmode = 0;
11978 VALUE ret;
11979
11980 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11981 if (rb_pipe(pipes) < 0)
11982 rb_sys_fail(0);
11983
11984 args[0] = klass;
11985 args[1] = INT2NUM(pipes[0]);
11986 args[2] = INT2FIX(O_RDONLY);
11987 r = rb_protect(io_new_instance, (VALUE)args, &state);
11988 if (state) {
11989 close(pipes[0]);
11990 close(pipes[1]);
11991 rb_jump_tag(state);
11992 }
11993 GetOpenFile(r, fptr);
11994
11995 ies_args.fptr = fptr;
11996 ies_args.v1 = v1;
11997 ies_args.v2 = v2;
11998 ies_args.opt = opt;
11999 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
12000 if (state) {
12001 close(pipes[1]);
12002 io_close(r);
12003 rb_jump_tag(state);
12004 }
12005
12006 args[1] = INT2NUM(pipes[1]);
12007 args[2] = INT2FIX(O_WRONLY);
12008 w = rb_protect(io_new_instance, (VALUE)args, &state);
12009 if (state) {
12010 close(pipes[1]);
12011 if (!NIL_P(r)) rb_io_close(r);
12012 rb_jump_tag(state);
12013 }
12014 GetOpenFile(w, fptr2);
12015 rb_io_synchronized(fptr2);
12016
12017 extract_binmode(opt, &fmode);
12018
12019 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
12022 }
12023
12024#if DEFAULT_TEXTMODE
12025 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12026 fptr->mode &= ~FMODE_TEXTMODE;
12027 setmode(fptr->fd, O_BINARY);
12028 }
12029#if RUBY_CRLF_ENVIRONMENT
12032 }
12033#endif
12034#endif
12035 fptr->mode |= fmode;
12036#if DEFAULT_TEXTMODE
12037 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12038 fptr2->mode &= ~FMODE_TEXTMODE;
12039 setmode(fptr2->fd, O_BINARY);
12040 }
12041#endif
12042 fptr2->mode |= fmode;
12043
12044 ret = rb_assoc_new(r, w);
12045 if (rb_block_given_p()) {
12046 VALUE rw[2];
12047 rw[0] = r;
12048 rw[1] = w;
12049 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12050 }
12051 return ret;
12052}
12053
12055 int argc;
12056 VALUE *argv;
12057 VALUE io;
12058};
12059
12060static void
12061open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12062{
12063 VALUE path, v;
12064 VALUE vmode = Qnil, vperm = Qnil;
12065
12066 path = *argv++;
12067 argc--;
12068 FilePathValue(path);
12069 arg->io = 0;
12070 arg->argc = argc;
12071 arg->argv = argv;
12072 if (NIL_P(opt)) {
12073 vmode = INT2NUM(O_RDONLY);
12074 vperm = INT2FIX(0666);
12075 }
12076 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12077 int n;
12078
12079 v = rb_to_array_type(v);
12080 n = RARRAY_LENINT(v);
12081 rb_check_arity(n, 0, 3); /* rb_io_open */
12082 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12083 }
12084 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12085}
12086
12087static VALUE
12088io_s_foreach(VALUE v)
12089{
12090 struct getline_arg *arg = (void *)v;
12091 VALUE str;
12092
12093 if (arg->limit == 0)
12094 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12095 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12096 rb_lastline_set(str);
12097 rb_yield(str);
12098 }
12100 return Qnil;
12101}
12102
12103/*
12104 * call-seq:
12105 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12106 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12107 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12108 * IO.foreach(...) -> an_enumerator
12109 *
12110 * Calls the block with each successive line read from the stream.
12111 *
12112 * The first argument must be a string that is the path to a file.
12113 *
12114 * With only argument +path+ given, parses lines from the file at the given +path+,
12115 * as determined by the default line separator,
12116 * and calls the block with each successive line:
12117 *
12118 * File.foreach('t.txt') {|line| p line }
12119 *
12120 * Output: the same as above.
12121 *
12122 * For both forms, command and path, the remaining arguments are the same.
12123 *
12124 * With argument +sep+ given, parses lines as determined by that line separator
12125 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12126 *
12127 * File.foreach('t.txt', 'li') {|line| p line }
12128 *
12129 * Output:
12130 *
12131 * "First li"
12132 * "ne\nSecond li"
12133 * "ne\n\nThird li"
12134 * "ne\nFourth li"
12135 * "ne\n"
12136 *
12137 * Each paragraph:
12138 *
12139 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12140 *
12141 * Output:
12142 *
12143 * "First line\nSecond line\n\n"
12144 * "Third line\nFourth line\n"
12145 *
12146 * With argument +limit+ given, parses lines as determined by the default
12147 * line separator and the given line-length limit
12148 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12149 *
12150 * File.foreach('t.txt', 7) {|line| p line }
12151 *
12152 * Output:
12153 *
12154 * "First l"
12155 * "ine\n"
12156 * "Second "
12157 * "line\n"
12158 * "\n"
12159 * "Third l"
12160 * "ine\n"
12161 * "Fourth l"
12162 * "line\n"
12163 *
12164 * With arguments +sep+ and +limit+ given,
12165 * combines the two behaviors
12166 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12167 *
12168 * Optional keyword arguments +opts+ specify:
12169 *
12170 * - {Open Options}[rdoc-ref:IO@Open+Options].
12171 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12172 * - {Line Options}[rdoc-ref:IO@Line+IO].
12173 *
12174 * Returns an Enumerator if no block is given.
12175 *
12176 */
12177
12178static VALUE
12179rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12180{
12181 VALUE opt;
12182 int orig_argc = argc;
12183 struct foreach_arg arg;
12184 struct getline_arg garg;
12185
12186 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12187 RETURN_ENUMERATOR(self, orig_argc, argv);
12188 extract_getline_args(argc-1, argv+1, &garg);
12189 open_key_args(self, argc, argv, opt, &arg);
12190 if (NIL_P(arg.io)) return Qnil;
12191 extract_getline_opts(opt, &garg);
12192 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12193 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12194}
12195
12196static VALUE
12197io_s_readlines(VALUE v)
12198{
12199 struct getline_arg *arg = (void *)v;
12200 return io_readlines(arg, arg->io);
12201}
12202
12203/*
12204 * call-seq:
12205 * IO.readlines(path, sep = $/, **opts) -> array
12206 * IO.readlines(path, limit, **opts) -> array
12207 * IO.readlines(path, sep, limit, **opts) -> array
12208 *
12209 * Returns an array of all lines read from the stream.
12210 *
12211 * The first argument must be a string that is the path to a file.
12212 *
12213 * With only argument +path+ given, parses lines from the file at the given +path+,
12214 * as determined by the default line separator,
12215 * and returns those lines in an array:
12216 *
12217 * IO.readlines('t.txt')
12218 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12219 *
12220 * With argument +sep+ given, parses lines as determined by that line separator
12221 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12222 *
12223 * # Ordinary separator.
12224 * IO.readlines('t.txt', 'li')
12225 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12226 * # Get-paragraphs separator.
12227 * IO.readlines('t.txt', '')
12228 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12229 * # Get-all separator.
12230 * IO.readlines('t.txt', nil)
12231 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12232 *
12233 * With argument +limit+ given, parses lines as determined by the default
12234 * line separator and the given line-length limit
12235 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12236 *
12237 * IO.readlines('t.txt', 7)
12238 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12239 *
12240 * With arguments +sep+ and +limit+ given,
12241 * combines the two behaviors
12242 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12243 *
12244 * Optional keyword arguments +opts+ specify:
12245 *
12246 * - {Open Options}[rdoc-ref:IO@Open+Options].
12247 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12248 * - {Line Options}[rdoc-ref:IO@Line+IO].
12249 *
12250 */
12251
12252static VALUE
12253rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12254{
12255 VALUE opt;
12256 struct foreach_arg arg;
12257 struct getline_arg garg;
12258
12259 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12260 extract_getline_args(argc-1, argv+1, &garg);
12261 open_key_args(io, argc, argv, opt, &arg);
12262 if (NIL_P(arg.io)) return Qnil;
12263 extract_getline_opts(opt, &garg);
12264 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12265 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12266}
12267
12268static VALUE
12269io_s_read(VALUE v)
12270{
12271 struct foreach_arg *arg = (void *)v;
12272 return io_read(arg->argc, arg->argv, arg->io);
12273}
12274
12275struct seek_arg {
12276 VALUE io;
12277 VALUE offset;
12278 int mode;
12279};
12280
12281static VALUE
12282seek_before_access(VALUE argp)
12283{
12284 struct seek_arg *arg = (struct seek_arg *)argp;
12285 rb_io_binmode(arg->io);
12286 return rb_io_seek(arg->io, arg->offset, arg->mode);
12287}
12288
12289/*
12290 * call-seq:
12291 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12292 *
12293 * Opens the stream, reads and returns some or all of its content,
12294 * and closes the stream; returns +nil+ if no bytes were read.
12295 *
12296 * The first argument must be a string that is the path to a file.
12297 *
12298 * With only argument +path+ given, reads in text mode and returns the entire content
12299 * of the file at the given path:
12300 *
12301 * IO.read('t.txt')
12302 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12303 *
12304 * On Windows, text mode can terminate reading and leave bytes in the file
12305 * unread when encountering certain special bytes. Consider using
12306 * IO.binread if all bytes in the file should be read.
12307 *
12308 * With argument +length+, returns +length+ bytes if available:
12309 *
12310 * IO.read('t.txt', 7) # => "First l"
12311 * IO.read('t.txt', 700)
12312 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12313 *
12314 * With arguments +length+ and +offset+, returns +length+ bytes
12315 * if available, beginning at the given +offset+:
12316 *
12317 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12318 * IO.read('t.txt', 10, 200) # => nil
12319 *
12320 * Optional keyword arguments +opts+ specify:
12321 *
12322 * - {Open Options}[rdoc-ref:IO@Open+Options].
12323 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12324 *
12325 */
12326
12327static VALUE
12328rb_io_s_read(int argc, VALUE *argv, VALUE io)
12329{
12330 VALUE opt, offset;
12331 long off;
12332 struct foreach_arg arg;
12333
12334 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12335 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12336 rb_raise(rb_eArgError, "negative offset %ld given", off);
12337 }
12338 open_key_args(io, argc, argv, opt, &arg);
12339 if (NIL_P(arg.io)) return Qnil;
12340 if (!NIL_P(offset)) {
12341 struct seek_arg sarg;
12342 int state = 0;
12343 sarg.io = arg.io;
12344 sarg.offset = offset;
12345 sarg.mode = SEEK_SET;
12346 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12347 if (state) {
12348 rb_io_close(arg.io);
12349 rb_jump_tag(state);
12350 }
12351 if (arg.argc == 2) arg.argc = 1;
12352 }
12353 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12354}
12355
12356/*
12357 * call-seq:
12358 * IO.binread(path, length = nil, offset = 0) -> string or nil
12359 *
12360 * Behaves like IO.read, except that the stream is opened in binary mode
12361 * with ASCII-8BIT encoding.
12362 *
12363 */
12364
12365static VALUE
12366rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12367{
12368 VALUE offset;
12369 struct foreach_arg arg;
12370 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12371 enum {
12372 oflags = O_RDONLY
12373#ifdef O_BINARY
12374 |O_BINARY
12375#endif
12376 };
12377 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12378
12379 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12380 FilePathValue(argv[0]);
12381 convconfig.enc = rb_ascii8bit_encoding();
12382 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12383 if (NIL_P(arg.io)) return Qnil;
12384 arg.argv = argv+1;
12385 arg.argc = (argc > 1) ? 1 : 0;
12386 if (!NIL_P(offset)) {
12387 struct seek_arg sarg;
12388 int state = 0;
12389 sarg.io = arg.io;
12390 sarg.offset = offset;
12391 sarg.mode = SEEK_SET;
12392 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12393 if (state) {
12394 rb_io_close(arg.io);
12395 rb_jump_tag(state);
12396 }
12397 }
12398 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12399}
12400
12401static VALUE
12402io_s_write0(VALUE v)
12403{
12404 struct write_arg *arg = (void *)v;
12405 return io_write(arg->io,arg->str,arg->nosync);
12406}
12407
12408static VALUE
12409io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12410{
12411 VALUE string, offset, opt;
12412 struct foreach_arg arg;
12413 struct write_arg warg;
12414
12415 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12416
12417 if (NIL_P(opt)) opt = rb_hash_new();
12418 else opt = rb_hash_dup(opt);
12419
12420
12421 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12422 int mode = O_WRONLY|O_CREAT;
12423#ifdef O_BINARY
12424 if (binary) mode |= O_BINARY;
12425#endif
12426 if (NIL_P(offset)) mode |= O_TRUNC;
12427 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12428 }
12429 open_key_args(klass, argc, argv, opt, &arg);
12430
12431#ifndef O_BINARY
12432 if (binary) rb_io_binmode_m(arg.io);
12433#endif
12434
12435 if (NIL_P(arg.io)) return Qnil;
12436 if (!NIL_P(offset)) {
12437 struct seek_arg sarg;
12438 int state = 0;
12439 sarg.io = arg.io;
12440 sarg.offset = offset;
12441 sarg.mode = SEEK_SET;
12442 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12443 if (state) {
12444 rb_io_close(arg.io);
12445 rb_jump_tag(state);
12446 }
12447 }
12448
12449 warg.io = arg.io;
12450 warg.str = string;
12451 warg.nosync = 0;
12452
12453 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12454}
12455
12456/*
12457 * call-seq:
12458 * IO.write(path, data, offset = 0, **opts) -> integer
12459 *
12460 * Opens the stream, writes the given +data+ to it,
12461 * and closes the stream; returns the number of bytes written.
12462 *
12463 * The first argument must be a string that is the path to a file.
12464 *
12465 * With only argument +path+ given, writes the given +data+ to the file at that path:
12466 *
12467 * IO.write('t.tmp', 'abc') # => 3
12468 * File.read('t.tmp') # => "abc"
12469 *
12470 * If +offset+ is zero (the default), the file is overwritten:
12471 *
12472 * IO.write('t.tmp', 'A') # => 1
12473 * File.read('t.tmp') # => "A"
12474 *
12475 * If +offset+ in within the file content, the file is partly overwritten:
12476 *
12477 * IO.write('t.tmp', 'abcdef') # => 3
12478 * File.read('t.tmp') # => "abcdef"
12479 * # Offset within content.
12480 * IO.write('t.tmp', '012', 2) # => 3
12481 * File.read('t.tmp') # => "ab012f"
12482 *
12483 * If +offset+ is outside the file content,
12484 * the file is padded with null characters <tt>"\u0000"</tt>:
12485 *
12486 * IO.write('t.tmp', 'xyz', 10) # => 3
12487 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12488 *
12489 * Optional keyword arguments +opts+ specify:
12490 *
12491 * - {Open Options}[rdoc-ref:IO@Open+Options].
12492 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12493 *
12494 */
12495
12496static VALUE
12497rb_io_s_write(int argc, VALUE *argv, VALUE io)
12498{
12499 return io_s_write(argc, argv, io, 0);
12500}
12501
12502/*
12503 * call-seq:
12504 * IO.binwrite(path, string, offset = 0) -> integer
12505 *
12506 * Behaves like IO.write, except that the stream is opened in binary mode
12507 * with ASCII-8BIT encoding.
12508 *
12509 */
12510
12511static VALUE
12512rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12513{
12514 return io_s_write(argc, argv, io, 1);
12515}
12516
12518 VALUE src;
12519 VALUE dst;
12520 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12521 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12522
12523 rb_io_t *src_fptr;
12524 rb_io_t *dst_fptr;
12525 unsigned close_src : 1;
12526 unsigned close_dst : 1;
12527 int error_no;
12528 rb_off_t total;
12529 const char *syserr;
12530 const char *notimp;
12531 VALUE th;
12532 struct stat src_stat;
12533 struct stat dst_stat;
12534#ifdef HAVE_FCOPYFILE
12535 copyfile_state_t copyfile_state;
12536#endif
12537};
12538
12539static void *
12540exec_interrupts(void *arg)
12541{
12542 VALUE th = (VALUE)arg;
12543 rb_thread_execute_interrupts(th);
12544 return NULL;
12545}
12546
12547/*
12548 * returns TRUE if the preceding system call was interrupted
12549 * so we can continue. If the thread was interrupted, we
12550 * reacquire the GVL to execute interrupts before continuing.
12551 */
12552static int
12553maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12554{
12555 switch (errno) {
12556 case EINTR:
12557#if defined(ERESTART)
12558 case ERESTART:
12559#endif
12560 if (rb_thread_interrupted(stp->th)) {
12561 if (has_gvl)
12562 rb_thread_execute_interrupts(stp->th);
12563 else
12564 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12565 }
12566 return TRUE;
12567 }
12568 return FALSE;
12569}
12570
12572 VALUE scheduler;
12573
12574 rb_io_t *fptr;
12575 short events;
12576
12577 VALUE result;
12578};
12579
12580static void *
12581fiber_scheduler_wait_for(void * _arguments)
12582{
12583 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12584
12585 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12586
12587 return NULL;
12588}
12589
12590#if USE_POLL
12591# define IOWAIT_SYSCALL "poll"
12592STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12593STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12594static int
12595nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12596{
12598 if (scheduler != Qnil) {
12599 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12600 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12601 return RTEST(args.result);
12602 }
12603
12604 int fd = fptr->fd;
12605 if (fd == -1) return 0;
12606
12607 struct pollfd fds;
12608
12609 fds.fd = fd;
12610 fds.events = events;
12611
12612 int timeout_milliseconds = -1;
12613
12614 if (timeout) {
12615 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12616 }
12617
12618 return poll(&fds, 1, timeout_milliseconds);
12619}
12620#else /* !USE_POLL */
12621# define IOWAIT_SYSCALL "select"
12622static int
12623nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12624{
12626 if (scheduler != Qnil) {
12627 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12628 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12629 return RTEST(args.result);
12630 }
12631
12632 int fd = fptr->fd;
12633
12634 if (fd == -1) {
12635 errno = EBADF;
12636 return -1;
12637 }
12638
12639 rb_fdset_t fds;
12640 int ret;
12641
12642 rb_fd_init(&fds);
12643 rb_fd_set(fd, &fds);
12644
12645 switch (events) {
12646 case RB_WAITFD_IN:
12647 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12648 break;
12649 case RB_WAITFD_OUT:
12650 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12651 break;
12652 default:
12653 VM_UNREACHABLE(nogvl_wait_for);
12654 }
12655
12656 rb_fd_term(&fds);
12657
12658 // On timeout, this returns 0.
12659 return ret;
12660}
12661#endif /* !USE_POLL */
12662
12663static int
12664maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12665{
12666 int ret;
12667
12668 do {
12669 if (has_gvl) {
12671 }
12672 else {
12673 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12674 }
12675 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12676
12677 if (ret < 0) {
12678 stp->syserr = IOWAIT_SYSCALL;
12679 stp->error_no = errno;
12680 return ret;
12681 }
12682 return 0;
12683}
12684
12685static int
12686nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12687{
12688 int ret;
12689
12690 do {
12691 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12692 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12693
12694 if (ret < 0) {
12695 stp->syserr = IOWAIT_SYSCALL;
12696 stp->error_no = errno;
12697 return ret;
12698 }
12699 return 0;
12700}
12701
12702#ifdef USE_COPY_FILE_RANGE
12703
12704static ssize_t
12705simple_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)
12706{
12707#ifdef HAVE_COPY_FILE_RANGE
12708 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12709#else
12710 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12711#endif
12712}
12713
12714static int
12715nogvl_copy_file_range(struct copy_stream_struct *stp)
12716{
12717 ssize_t ss;
12718 rb_off_t src_size;
12719 rb_off_t copy_length, src_offset, *src_offset_ptr;
12720
12721 if (!S_ISREG(stp->src_stat.st_mode))
12722 return 0;
12723
12724 src_size = stp->src_stat.st_size;
12725 src_offset = stp->src_offset;
12726 if (src_offset >= (rb_off_t)0) {
12727 src_offset_ptr = &src_offset;
12728 }
12729 else {
12730 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12731 }
12732
12733 copy_length = stp->copy_length;
12734 if (copy_length < (rb_off_t)0) {
12735 if (src_offset < (rb_off_t)0) {
12736 rb_off_t current_offset;
12737 errno = 0;
12738 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12739 if (current_offset < (rb_off_t)0 && errno) {
12740 stp->syserr = "lseek";
12741 stp->error_no = errno;
12742 return (int)current_offset;
12743 }
12744 copy_length = src_size - current_offset;
12745 }
12746 else {
12747 copy_length = src_size - src_offset;
12748 }
12749 }
12750
12751 retry_copy_file_range:
12752# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12753 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12754 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12755# else
12756 ss = (ssize_t)copy_length;
12757# endif
12758 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12759 if (0 < ss) {
12760 stp->total += ss;
12761 copy_length -= ss;
12762 if (0 < copy_length) {
12763 goto retry_copy_file_range;
12764 }
12765 }
12766 if (ss < 0) {
12767 if (maygvl_copy_stream_continue_p(0, stp)) {
12768 goto retry_copy_file_range;
12769 }
12770 switch (errno) {
12771 case EINVAL:
12772 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12773 docker container) */
12774#ifdef ENOSYS
12775 case ENOSYS:
12776#endif
12777#ifdef EXDEV
12778 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12779#endif
12780 return 0;
12781 case EAGAIN:
12782#if EWOULDBLOCK != EAGAIN
12783 case EWOULDBLOCK:
12784#endif
12785 {
12786 int ret = nogvl_copy_stream_wait_write(stp);
12787 if (ret < 0) return ret;
12788 }
12789 goto retry_copy_file_range;
12790 case EBADF:
12791 {
12792 int e = errno;
12793 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12794
12795 if (flags != -1 && flags & O_APPEND) {
12796 return 0;
12797 }
12798 errno = e;
12799 }
12800 }
12801 stp->syserr = "copy_file_range";
12802 stp->error_no = errno;
12803 return (int)ss;
12804 }
12805 return 1;
12806}
12807#endif
12808
12809#ifdef HAVE_FCOPYFILE
12810static int
12811nogvl_fcopyfile(struct copy_stream_struct *stp)
12812{
12813 rb_off_t cur, ss = 0;
12814 const rb_off_t src_offset = stp->src_offset;
12815 int ret;
12816
12817 if (stp->copy_length >= (rb_off_t)0) {
12818 /* copy_length can't be specified in fcopyfile(3) */
12819 return 0;
12820 }
12821
12822 if (!S_ISREG(stp->src_stat.st_mode))
12823 return 0;
12824
12825 if (!S_ISREG(stp->dst_stat.st_mode))
12826 return 0;
12827 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12828 return 0;
12829 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12830 /* fcopyfile(3) appends src IO to dst IO and then truncates
12831 * dst IO to src IO's original size. */
12832 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12833 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12834 if (end > (rb_off_t)0) return 0;
12835 }
12836
12837 if (src_offset > (rb_off_t)0) {
12838 rb_off_t r;
12839
12840 /* get current offset */
12841 errno = 0;
12842 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12843 if (cur < (rb_off_t)0 && errno) {
12844 stp->error_no = errno;
12845 return 1;
12846 }
12847
12848 errno = 0;
12849 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12850 if (r < (rb_off_t)0 && errno) {
12851 stp->error_no = errno;
12852 return 1;
12853 }
12854 }
12855
12856 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12857 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12858 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12859
12860 if (ret == 0) { /* success */
12861 stp->total = ss;
12862 if (src_offset > (rb_off_t)0) {
12863 rb_off_t r;
12864 errno = 0;
12865 /* reset offset */
12866 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12867 if (r < (rb_off_t)0 && errno) {
12868 stp->error_no = errno;
12869 return 1;
12870 }
12871 }
12872 }
12873 else {
12874 switch (errno) {
12875 case ENOTSUP:
12876 case EPERM:
12877 case EINVAL:
12878 return 0;
12879 }
12880 stp->syserr = "fcopyfile";
12881 stp->error_no = errno;
12882 return (int)ret;
12883 }
12884 return 1;
12885}
12886#endif
12887
12888#ifdef HAVE_SENDFILE
12889
12890# ifdef __linux__
12891# define USE_SENDFILE
12892
12893# ifdef HAVE_SYS_SENDFILE_H
12894# include <sys/sendfile.h>
12895# endif
12896
12897static ssize_t
12898simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12899{
12900 return sendfile(out_fd, in_fd, offset, (size_t)count);
12901}
12902
12903# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12904/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12905 * without cpuset -l 0.
12906 */
12907# define USE_SENDFILE
12908
12909static ssize_t
12910simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12911{
12912 int r;
12913 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12914 rb_off_t sbytes;
12915# ifdef __APPLE__
12916 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12917 sbytes = count;
12918# else
12919 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12920# endif
12921 if (r != 0 && sbytes == 0) return r;
12922 if (offset) {
12923 *offset += sbytes;
12924 }
12925 else {
12926 lseek(in_fd, sbytes, SEEK_CUR);
12927 }
12928 return (ssize_t)sbytes;
12929}
12930
12931# endif
12932
12933#endif
12934
12935#ifdef USE_SENDFILE
12936static int
12937nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12938{
12939 ssize_t ss;
12940 rb_off_t src_size;
12941 rb_off_t copy_length;
12942 rb_off_t src_offset;
12943 int use_pread;
12944
12945 if (!S_ISREG(stp->src_stat.st_mode))
12946 return 0;
12947
12948 src_size = stp->src_stat.st_size;
12949#ifndef __linux__
12950 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12951 return 0;
12952#endif
12953
12954 src_offset = stp->src_offset;
12955 use_pread = src_offset >= (rb_off_t)0;
12956
12957 copy_length = stp->copy_length;
12958 if (copy_length < (rb_off_t)0) {
12959 if (use_pread)
12960 copy_length = src_size - src_offset;
12961 else {
12962 rb_off_t cur;
12963 errno = 0;
12964 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12965 if (cur < (rb_off_t)0 && errno) {
12966 stp->syserr = "lseek";
12967 stp->error_no = errno;
12968 return (int)cur;
12969 }
12970 copy_length = src_size - cur;
12971 }
12972 }
12973
12974 retry_sendfile:
12975# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12976 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12977 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12978# else
12979 ss = (ssize_t)copy_length;
12980# endif
12981 if (use_pread) {
12982 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12983 }
12984 else {
12985 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12986 }
12987 if (0 < ss) {
12988 stp->total += ss;
12989 copy_length -= ss;
12990 if (0 < copy_length) {
12991 goto retry_sendfile;
12992 }
12993 }
12994 if (ss < 0) {
12995 if (maygvl_copy_stream_continue_p(0, stp))
12996 goto retry_sendfile;
12997 switch (errno) {
12998 case EINVAL:
12999#ifdef ENOSYS
13000 case ENOSYS:
13001#endif
13002#ifdef EOPNOTSUP
13003 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
13004 see also: [Feature #16965] */
13005 case EOPNOTSUP:
13006#endif
13007 return 0;
13008 case EAGAIN:
13009#if EWOULDBLOCK != EAGAIN
13010 case EWOULDBLOCK:
13011#endif
13012 {
13013 int ret;
13014#ifndef __linux__
13015 /*
13016 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
13017 * select() reports regular files to always be "ready", so
13018 * there is no need to select() on it.
13019 * Other OSes may have the same limitation for sendfile() which
13020 * allow us to bypass maygvl_copy_stream_wait_read()...
13021 */
13022 ret = maygvl_copy_stream_wait_read(0, stp);
13023 if (ret < 0) return ret;
13024#endif
13025 ret = nogvl_copy_stream_wait_write(stp);
13026 if (ret < 0) return ret;
13027 }
13028 goto retry_sendfile;
13029 }
13030 stp->syserr = "sendfile";
13031 stp->error_no = errno;
13032 return (int)ss;
13033 }
13034 return 1;
13035}
13036#endif
13037
13038static ssize_t
13039maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13040{
13041 if (has_gvl)
13042 return rb_io_read_memory(fptr, buf, count);
13043 else
13044 return read(fptr->fd, buf, count);
13045}
13046
13047static ssize_t
13048maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13049{
13050 ssize_t ss;
13051 retry_read:
13052 if (offset < (rb_off_t)0) {
13053 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13054 }
13055 else {
13056 ss = pread(stp->src_fptr->fd, buf, len, offset);
13057 }
13058 if (ss == 0) {
13059 return 0;
13060 }
13061 if (ss < 0) {
13062 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13063 goto retry_read;
13064 switch (errno) {
13065 case EAGAIN:
13066#if EWOULDBLOCK != EAGAIN
13067 case EWOULDBLOCK:
13068#endif
13069 {
13070 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13071 if (ret < 0) return ret;
13072 }
13073 goto retry_read;
13074#ifdef ENOSYS
13075 case ENOSYS:
13076 stp->notimp = "pread";
13077 return ss;
13078#endif
13079 }
13080 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13081 stp->error_no = errno;
13082 }
13083 return ss;
13084}
13085
13086static int
13087nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13088{
13089 ssize_t ss;
13090 int off = 0;
13091 while (len) {
13092 ss = write(stp->dst_fptr->fd, buf+off, len);
13093 if (ss < 0) {
13094 if (maygvl_copy_stream_continue_p(0, stp))
13095 continue;
13096 if (io_again_p(errno)) {
13097 int ret = nogvl_copy_stream_wait_write(stp);
13098 if (ret < 0) return ret;
13099 continue;
13100 }
13101 stp->syserr = "write";
13102 stp->error_no = errno;
13103 return (int)ss;
13104 }
13105 off += (int)ss;
13106 len -= (int)ss;
13107 stp->total += ss;
13108 }
13109 return 0;
13110}
13111
13112static void
13113nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13114{
13115 char buf[1024*16];
13116 size_t len;
13117 ssize_t ss;
13118 int ret;
13119 rb_off_t copy_length;
13120 rb_off_t src_offset;
13121 int use_eof;
13122 int use_pread;
13123
13124 copy_length = stp->copy_length;
13125 use_eof = copy_length < (rb_off_t)0;
13126 src_offset = stp->src_offset;
13127 use_pread = src_offset >= (rb_off_t)0;
13128
13129 if (use_pread && stp->close_src) {
13130 rb_off_t r;
13131 errno = 0;
13132 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13133 if (r < (rb_off_t)0 && errno) {
13134 stp->syserr = "lseek";
13135 stp->error_no = errno;
13136 return;
13137 }
13138 src_offset = (rb_off_t)-1;
13139 use_pread = 0;
13140 }
13141
13142 while (use_eof || 0 < copy_length) {
13143 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13144 len = (size_t)copy_length;
13145 }
13146 else {
13147 len = sizeof(buf);
13148 }
13149 if (use_pread) {
13150 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13151 if (0 < ss)
13152 src_offset += ss;
13153 }
13154 else {
13155 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13156 }
13157 if (ss <= 0) /* EOF or error */
13158 return;
13159
13160 ret = nogvl_copy_stream_write(stp, buf, ss);
13161 if (ret < 0)
13162 return;
13163
13164 if (!use_eof)
13165 copy_length -= ss;
13166 }
13167}
13168
13169static void *
13170nogvl_copy_stream_func(void *arg)
13171{
13172 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13173#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13174 int ret;
13175#endif
13176
13177#ifdef USE_COPY_FILE_RANGE
13178 ret = nogvl_copy_file_range(stp);
13179 if (ret != 0)
13180 goto finish; /* error or success */
13181#endif
13182
13183#ifdef HAVE_FCOPYFILE
13184 ret = nogvl_fcopyfile(stp);
13185 if (ret != 0)
13186 goto finish; /* error or success */
13187#endif
13188
13189#ifdef USE_SENDFILE
13190 ret = nogvl_copy_stream_sendfile(stp);
13191 if (ret != 0)
13192 goto finish; /* error or success */
13193#endif
13194
13195 nogvl_copy_stream_read_write(stp);
13196
13197#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13198 finish:
13199#endif
13200 return 0;
13201}
13202
13203static VALUE
13204copy_stream_fallback_body(VALUE arg)
13205{
13206 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13207 const int buflen = 16*1024;
13208 VALUE n;
13209 VALUE buf = rb_str_buf_new(buflen);
13210 rb_off_t rest = stp->copy_length;
13211 rb_off_t off = stp->src_offset;
13212 ID read_method = id_readpartial;
13213
13214 if (!stp->src_fptr) {
13215 if (!rb_respond_to(stp->src, read_method)) {
13216 read_method = id_read;
13217 }
13218 }
13219
13220 while (1) {
13221 long numwrote;
13222 long l;
13223 rb_str_make_independent(buf);
13224 if (stp->copy_length < (rb_off_t)0) {
13225 l = buflen;
13226 }
13227 else {
13228 if (rest == 0) {
13229 rb_str_resize(buf, 0);
13230 break;
13231 }
13232 l = buflen < rest ? buflen : (long)rest;
13233 }
13234 if (!stp->src_fptr) {
13235 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13236
13237 if (read_method == id_read && NIL_P(rc))
13238 break;
13239 }
13240 else {
13241 ssize_t ss;
13242 rb_str_resize(buf, buflen);
13243 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13244 rb_str_resize(buf, ss > 0 ? ss : 0);
13245 if (ss < 0)
13246 return Qnil;
13247 if (ss == 0)
13248 rb_eof_error();
13249 if (off >= (rb_off_t)0)
13250 off += ss;
13251 }
13252 n = rb_io_write(stp->dst, buf);
13253 numwrote = NUM2LONG(n);
13254 stp->total += numwrote;
13255 rest -= numwrote;
13256 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13257 break;
13258 }
13259 }
13260
13261 return Qnil;
13262}
13263
13264static VALUE
13265copy_stream_fallback(struct copy_stream_struct *stp)
13266{
13267 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13268 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13269 }
13270 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13271 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13272 rb_eEOFError, (VALUE)0);
13273 return Qnil;
13274}
13275
13276static VALUE
13277copy_stream_body(VALUE arg)
13278{
13279 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13280 VALUE src_io = stp->src, dst_io = stp->dst;
13281 const int common_oflags = 0
13282#ifdef O_NOCTTY
13283 | O_NOCTTY
13284#endif
13285 ;
13286
13287 stp->th = rb_thread_current();
13288
13289 stp->total = 0;
13290
13291 if (src_io == argf ||
13292 !(RB_TYPE_P(src_io, T_FILE) ||
13293 RB_TYPE_P(src_io, T_STRING) ||
13294 rb_respond_to(src_io, rb_intern("to_path")))) {
13295 stp->src_fptr = NULL;
13296 }
13297 else {
13298 int stat_ret;
13299 VALUE tmp_io = rb_io_check_io(src_io);
13300 if (!NIL_P(tmp_io)) {
13301 src_io = tmp_io;
13302 }
13303 else if (!RB_TYPE_P(src_io, T_FILE)) {
13304 VALUE args[2];
13305 FilePathValue(src_io);
13306 args[0] = src_io;
13307 args[1] = INT2NUM(O_RDONLY|common_oflags);
13308 src_io = rb_class_new_instance(2, args, rb_cFile);
13309 stp->src = src_io;
13310 stp->close_src = 1;
13311 }
13312 RB_IO_POINTER(src_io, stp->src_fptr);
13313 rb_io_check_byte_readable(stp->src_fptr);
13314
13315 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13316 if (stat_ret < 0) {
13317 stp->syserr = "fstat";
13318 stp->error_no = errno;
13319 return Qnil;
13320 }
13321 }
13322
13323 if (dst_io == argf ||
13324 !(RB_TYPE_P(dst_io, T_FILE) ||
13325 RB_TYPE_P(dst_io, T_STRING) ||
13326 rb_respond_to(dst_io, rb_intern("to_path")))) {
13327 stp->dst_fptr = NULL;
13328 }
13329 else {
13330 int stat_ret;
13331 VALUE tmp_io = rb_io_check_io(dst_io);
13332 if (!NIL_P(tmp_io)) {
13333 dst_io = GetWriteIO(tmp_io);
13334 }
13335 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13336 VALUE args[3];
13337 FilePathValue(dst_io);
13338 args[0] = dst_io;
13339 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13340 args[2] = INT2FIX(0666);
13341 dst_io = rb_class_new_instance(3, args, rb_cFile);
13342 stp->dst = dst_io;
13343 stp->close_dst = 1;
13344 }
13345 else {
13346 dst_io = GetWriteIO(dst_io);
13347 stp->dst = dst_io;
13348 }
13349 RB_IO_POINTER(dst_io, stp->dst_fptr);
13350 rb_io_check_writable(stp->dst_fptr);
13351
13352 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13353 if (stat_ret < 0) {
13354 stp->syserr = "fstat";
13355 stp->error_no = errno;
13356 return Qnil;
13357 }
13358 }
13359
13360#ifdef O_BINARY
13361 if (stp->src_fptr)
13362 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13363#endif
13364 if (stp->dst_fptr)
13365 io_ascii8bit_binmode(stp->dst_fptr);
13366
13367 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13368 size_t len = stp->src_fptr->rbuf.len;
13369 VALUE str;
13370 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13371 len = (size_t)stp->copy_length;
13372 }
13373 str = rb_str_buf_new(len);
13374 rb_str_resize(str,len);
13375 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13376 if (stp->dst_fptr) { /* IO or filename */
13377 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13378 rb_sys_fail_on_write(stp->dst_fptr);
13379 }
13380 else /* others such as StringIO */
13381 rb_io_write(dst_io, str);
13382 rb_str_resize(str, 0);
13383 stp->total += len;
13384 if (stp->copy_length >= (rb_off_t)0)
13385 stp->copy_length -= len;
13386 }
13387
13388 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13389 rb_raise(rb_eIOError, "flush failed");
13390 }
13391
13392 if (stp->copy_length == 0)
13393 return Qnil;
13394
13395 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13396 return copy_stream_fallback(stp);
13397 }
13398
13399 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13400 return Qnil;
13401}
13402
13403static VALUE
13404copy_stream_finalize(VALUE arg)
13405{
13406 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13407
13408#ifdef HAVE_FCOPYFILE
13409 if (stp->copyfile_state) {
13410 copyfile_state_free(stp->copyfile_state);
13411 }
13412#endif
13413
13414 if (stp->close_src) {
13415 rb_io_close_m(stp->src);
13416 }
13417 if (stp->close_dst) {
13418 rb_io_close_m(stp->dst);
13419 }
13420 if (stp->syserr) {
13421 rb_syserr_fail(stp->error_no, stp->syserr);
13422 }
13423 if (stp->notimp) {
13424 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13425 }
13426 return Qnil;
13427}
13428
13429/*
13430 * call-seq:
13431 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13432 *
13433 * Copies from the given +src+ to the given +dst+,
13434 * returning the number of bytes copied.
13435 *
13436 * - The given +src+ must be one of the following:
13437 *
13438 * - The path to a readable file, from which source data is to be read.
13439 * - An \IO-like object, opened for reading and capable of responding
13440 * to method +:readpartial+ or method +:read+.
13441 *
13442 * - The given +dst+ must be one of the following:
13443 *
13444 * - The path to a writable file, to which data is to be written.
13445 * - An \IO-like object, opened for writing and capable of responding
13446 * to method +:write+.
13447 *
13448 * The examples here use file <tt>t.txt</tt> as source:
13449 *
13450 * File.read('t.txt')
13451 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13452 * File.read('t.txt').size # => 47
13453 *
13454 * If only arguments +src+ and +dst+ are given,
13455 * the entire source stream is copied:
13456 *
13457 * # Paths.
13458 * IO.copy_stream('t.txt', 't.tmp') # => 47
13459 *
13460 * # IOs (recall that a File is also an IO).
13461 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13462 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13463 * IO.copy_stream(src_io, dst_io) # => 47
13464 * src_io.close
13465 * dst_io.close
13466 *
13467 * With argument +src_length+ a non-negative integer,
13468 * no more than that many bytes are copied:
13469 *
13470 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13471 * File.read('t.tmp') # => "First line"
13472 *
13473 * With argument +src_offset+ also given,
13474 * the source stream is read beginning at that offset:
13475 *
13476 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13477 * IO.read('t.tmp') # => "Second line"
13478 *
13479 */
13480static VALUE
13481rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13482{
13483 VALUE src, dst, length, src_offset;
13484 struct copy_stream_struct st;
13485
13486 MEMZERO(&st, struct copy_stream_struct, 1);
13487
13488 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13489
13490 st.src = src;
13491 st.dst = dst;
13492
13493 st.src_fptr = NULL;
13494 st.dst_fptr = NULL;
13495
13496 if (NIL_P(length))
13497 st.copy_length = (rb_off_t)-1;
13498 else
13499 st.copy_length = NUM2OFFT(length);
13500
13501 if (NIL_P(src_offset))
13502 st.src_offset = (rb_off_t)-1;
13503 else
13504 st.src_offset = NUM2OFFT(src_offset);
13505
13506 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13507
13508 return OFFT2NUM(st.total);
13509}
13510
13511/*
13512 * call-seq:
13513 * external_encoding -> encoding or nil
13514 *
13515 * Returns the Encoding object that represents the encoding of the stream,
13516 * or +nil+ if the stream is in write mode and no encoding is specified.
13517 *
13518 * See {Encodings}[rdoc-ref:File@Encodings].
13519 *
13520 */
13521
13522static VALUE
13523rb_io_external_encoding(VALUE io)
13524{
13525 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13526
13527 if (fptr->encs.enc2) {
13528 return rb_enc_from_encoding(fptr->encs.enc2);
13529 }
13530 if (fptr->mode & FMODE_WRITABLE) {
13531 if (fptr->encs.enc)
13532 return rb_enc_from_encoding(fptr->encs.enc);
13533 return Qnil;
13534 }
13535 return rb_enc_from_encoding(io_read_encoding(fptr));
13536}
13537
13538/*
13539 * call-seq:
13540 * internal_encoding -> encoding or nil
13541 *
13542 * Returns the Encoding object that represents the encoding of the internal string,
13543 * if conversion is specified,
13544 * or +nil+ otherwise.
13545 *
13546 * See {Encodings}[rdoc-ref:File@Encodings].
13547 *
13548 */
13549
13550static VALUE
13551rb_io_internal_encoding(VALUE io)
13552{
13553 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13554
13555 if (!fptr->encs.enc2) return Qnil;
13556 return rb_enc_from_encoding(io_read_encoding(fptr));
13557}
13558
13559/*
13560 * call-seq:
13561 * set_encoding(ext_enc) -> self
13562 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13563 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13564 *
13565 * See {Encodings}[rdoc-ref:File@Encodings].
13566 *
13567 * Argument +ext_enc+, if given, must be an Encoding object
13568 * or a String with the encoding name;
13569 * it is assigned as the encoding for the stream.
13570 *
13571 * Argument +int_enc+, if given, must be an Encoding object
13572 * or a String with the encoding name;
13573 * it is assigned as the encoding for the internal string.
13574 *
13575 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13576 * containing two colon-separated encoding names;
13577 * corresponding Encoding objects are assigned as the external
13578 * and internal encodings for the stream.
13579 *
13580 * If the external encoding of a string is binary/ASCII-8BIT,
13581 * the internal encoding of the string is set to nil, since no
13582 * transcoding is needed.
13583 *
13584 * Optional keyword arguments +enc_opts+ specify
13585 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13586 *
13587 */
13588
13589static VALUE
13590rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13591{
13592 rb_io_t *fptr;
13593 VALUE v1, v2, opt;
13594
13595 if (!RB_TYPE_P(io, T_FILE)) {
13596 return forward(io, id_set_encoding, argc, argv);
13597 }
13598
13599 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13600 GetOpenFile(io, fptr);
13601 io_encoding_set(fptr, v1, v2, opt);
13602 return io;
13603}
13604
13605void
13606rb_stdio_set_default_encoding(void)
13607{
13608 VALUE val = Qnil;
13609
13610#ifdef _WIN32
13611 if (isatty(fileno(stdin))) {
13612 rb_encoding *external = rb_locale_encoding();
13613 rb_encoding *internal = rb_default_internal_encoding();
13614 if (!internal) internal = rb_default_external_encoding();
13615 io_encoding_set(RFILE(rb_stdin)->fptr,
13616 rb_enc_from_encoding(external),
13617 rb_enc_from_encoding(internal),
13618 Qnil);
13619 }
13620 else
13621#endif
13622 rb_io_set_encoding(1, &val, rb_stdin);
13623 rb_io_set_encoding(1, &val, rb_stdout);
13624 rb_io_set_encoding(1, &val, rb_stderr);
13625}
13626
13627static inline int
13628global_argf_p(VALUE arg)
13629{
13630 return arg == argf;
13631}
13632
13633typedef VALUE (*argf_encoding_func)(VALUE io);
13634
13635static VALUE
13636argf_encoding(VALUE argf, argf_encoding_func func)
13637{
13638 if (!RTEST(ARGF.current_file)) {
13639 return rb_enc_default_external();
13640 }
13641 return func(rb_io_check_io(ARGF.current_file));
13642}
13643
13644/*
13645 * call-seq:
13646 * ARGF.external_encoding -> encoding
13647 *
13648 * Returns the external encoding for files read from ARGF as an Encoding
13649 * object. The external encoding is the encoding of the text as stored in a
13650 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13651 * represent this text within Ruby.
13652 *
13653 * To set the external encoding use ARGF.set_encoding.
13654 *
13655 * For example:
13656 *
13657 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13658 *
13659 */
13660static VALUE
13661argf_external_encoding(VALUE argf)
13662{
13663 return argf_encoding(argf, rb_io_external_encoding);
13664}
13665
13666/*
13667 * call-seq:
13668 * ARGF.internal_encoding -> encoding
13669 *
13670 * Returns the internal encoding for strings read from ARGF as an
13671 * Encoding object.
13672 *
13673 * If ARGF.set_encoding has been called with two encoding names, the second
13674 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13675 * value is returned. Failing that, if a default external encoding was
13676 * specified on the command-line, that value is used. If the encoding is
13677 * unknown, +nil+ is returned.
13678 */
13679static VALUE
13680argf_internal_encoding(VALUE argf)
13681{
13682 return argf_encoding(argf, rb_io_internal_encoding);
13683}
13684
13685/*
13686 * call-seq:
13687 * ARGF.set_encoding(ext_enc) -> ARGF
13688 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13689 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13690 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13691 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13692 *
13693 * If single argument is specified, strings read from ARGF are tagged with
13694 * the encoding specified.
13695 *
13696 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13697 * the read string is converted from the first encoding (external encoding)
13698 * to the second encoding (internal encoding), then tagged with the second
13699 * encoding.
13700 *
13701 * If two arguments are specified, they must be encoding objects or encoding
13702 * names. Again, the first specifies the external encoding; the second
13703 * specifies the internal encoding.
13704 *
13705 * If the external encoding and the internal encoding are specified, the
13706 * optional Hash argument can be used to adjust the conversion process. The
13707 * structure of this hash is explained in the String#encode documentation.
13708 *
13709 * For example:
13710 *
13711 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13712 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13713 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13714 * # to UTF-8.
13715 */
13716static VALUE
13717argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13718{
13719 rb_io_t *fptr;
13720
13721 if (!next_argv()) {
13722 rb_raise(rb_eArgError, "no stream to set encoding");
13723 }
13724 rb_io_set_encoding(argc, argv, ARGF.current_file);
13725 GetOpenFile(ARGF.current_file, fptr);
13726 ARGF.encs = fptr->encs;
13727 return argf;
13728}
13729
13730/*
13731 * call-seq:
13732 * ARGF.tell -> Integer
13733 * ARGF.pos -> Integer
13734 *
13735 * Returns the current offset (in bytes) of the current file in ARGF.
13736 *
13737 * ARGF.pos #=> 0
13738 * ARGF.gets #=> "This is line one\n"
13739 * ARGF.pos #=> 17
13740 *
13741 */
13742static VALUE
13743argf_tell(VALUE argf)
13744{
13745 if (!next_argv()) {
13746 rb_raise(rb_eArgError, "no stream to tell");
13747 }
13748 ARGF_FORWARD(0, 0);
13749 return rb_io_tell(ARGF.current_file);
13750}
13751
13752/*
13753 * call-seq:
13754 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13755 *
13756 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13757 * the value of _whence_. See IO#seek for further details.
13758 */
13759static VALUE
13760argf_seek_m(int argc, VALUE *argv, VALUE argf)
13761{
13762 if (!next_argv()) {
13763 rb_raise(rb_eArgError, "no stream to seek");
13764 }
13765 ARGF_FORWARD(argc, argv);
13766 return rb_io_seek_m(argc, argv, ARGF.current_file);
13767}
13768
13769/*
13770 * call-seq:
13771 * ARGF.pos = position -> Integer
13772 *
13773 * Seeks to the position given by _position_ (in bytes) in ARGF.
13774 *
13775 * For example:
13776 *
13777 * ARGF.pos = 17
13778 * ARGF.gets #=> "This is line two\n"
13779 */
13780static VALUE
13781argf_set_pos(VALUE argf, VALUE offset)
13782{
13783 if (!next_argv()) {
13784 rb_raise(rb_eArgError, "no stream to set position");
13785 }
13786 ARGF_FORWARD(1, &offset);
13787 return rb_io_set_pos(ARGF.current_file, offset);
13788}
13789
13790/*
13791 * call-seq:
13792 * ARGF.rewind -> 0
13793 *
13794 * Positions the current file to the beginning of input, resetting
13795 * ARGF.lineno to zero.
13796 *
13797 * ARGF.readline #=> "This is line one\n"
13798 * ARGF.rewind #=> 0
13799 * ARGF.lineno #=> 0
13800 * ARGF.readline #=> "This is line one\n"
13801 */
13802static VALUE
13803argf_rewind(VALUE argf)
13804{
13805 VALUE ret;
13806 int old_lineno;
13807
13808 if (!next_argv()) {
13809 rb_raise(rb_eArgError, "no stream to rewind");
13810 }
13811 ARGF_FORWARD(0, 0);
13812 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13813 ret = rb_io_rewind(ARGF.current_file);
13814 if (!global_argf_p(argf)) {
13815 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13816 }
13817 return ret;
13818}
13819
13820/*
13821 * call-seq:
13822 * ARGF.fileno -> integer
13823 * ARGF.to_i -> integer
13824 *
13825 * Returns an integer representing the numeric file descriptor for
13826 * the current file. Raises an ArgumentError if there isn't a current file.
13827 *
13828 * ARGF.fileno #=> 3
13829 */
13830static VALUE
13831argf_fileno(VALUE argf)
13832{
13833 if (!next_argv()) {
13834 rb_raise(rb_eArgError, "no stream");
13835 }
13836 ARGF_FORWARD(0, 0);
13837 return rb_io_fileno(ARGF.current_file);
13838}
13839
13840/*
13841 * call-seq:
13842 * ARGF.to_io -> IO
13843 *
13844 * Returns an IO object representing the current file. This will be a
13845 * File object unless the current file is a stream such as STDIN.
13846 *
13847 * For example:
13848 *
13849 * ARGF.to_io #=> #<File:glark.txt>
13850 * ARGF.to_io #=> #<IO:<STDIN>>
13851 */
13852static VALUE
13853argf_to_io(VALUE argf)
13854{
13855 next_argv();
13856 ARGF_FORWARD(0, 0);
13857 return ARGF.current_file;
13858}
13859
13860/*
13861 * call-seq:
13862 * ARGF.eof? -> true or false
13863 * ARGF.eof -> true or false
13864 *
13865 * Returns true if the current file in ARGF is at end of file, i.e. it has
13866 * no data to read. The stream must be opened for reading or an IOError
13867 * will be raised.
13868 *
13869 * $ echo "eof" | ruby argf.rb
13870 *
13871 * ARGF.eof? #=> false
13872 * 3.times { ARGF.readchar }
13873 * ARGF.eof? #=> false
13874 * ARGF.readchar #=> "\n"
13875 * ARGF.eof? #=> true
13876 */
13877
13878static VALUE
13879argf_eof(VALUE argf)
13880{
13881 next_argv();
13882 if (RTEST(ARGF.current_file)) {
13883 if (ARGF.init_p == 0) return Qtrue;
13884 next_argv();
13885 ARGF_FORWARD(0, 0);
13886 if (rb_io_eof(ARGF.current_file)) {
13887 return Qtrue;
13888 }
13889 }
13890 return Qfalse;
13891}
13892
13893/*
13894 * call-seq:
13895 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13896 *
13897 * Reads _length_ bytes from ARGF. The files named on the command line
13898 * are concatenated and treated as a single file by this method, so when
13899 * called without arguments the contents of this pseudo file are returned in
13900 * their entirety.
13901 *
13902 * _length_ must be a non-negative integer or +nil+.
13903 *
13904 * If _length_ is a positive integer, +read+ tries to read
13905 * _length_ bytes without any conversion (binary mode).
13906 * It returns +nil+ if an EOF is encountered before anything can be read.
13907 * Fewer than _length_ bytes are returned if an EOF is encountered during
13908 * the read.
13909 * In the case of an integer _length_, the resulting string is always
13910 * in ASCII-8BIT encoding.
13911 *
13912 * If _length_ is omitted or is +nil+, it reads until EOF
13913 * and the encoding conversion is applied, if applicable.
13914 * A string is returned even if EOF is encountered before any data is read.
13915 *
13916 * If _length_ is zero, it returns an empty string (<code>""</code>).
13917 *
13918 * If the optional _outbuf_ argument is present,
13919 * it must reference a String, which will receive the data.
13920 * The _outbuf_ will contain only the received data after the method call
13921 * even if it is not empty at the beginning.
13922 *
13923 * For example:
13924 *
13925 * $ echo "small" > small.txt
13926 * $ echo "large" > large.txt
13927 * $ ./glark.rb small.txt large.txt
13928 *
13929 * ARGF.read #=> "small\nlarge"
13930 * ARGF.read(200) #=> "small\nlarge"
13931 * ARGF.read(2) #=> "sm"
13932 * ARGF.read(0) #=> ""
13933 *
13934 * Note that this method behaves like the fread() function in C.
13935 * This means it retries to invoke read(2) system calls to read data
13936 * with the specified length.
13937 * If you need the behavior like a single read(2) system call,
13938 * consider ARGF#readpartial or ARGF#read_nonblock.
13939 */
13940
13941static VALUE
13942argf_read(int argc, VALUE *argv, VALUE argf)
13943{
13944 VALUE tmp, str, length;
13945 long len = 0;
13946
13947 rb_scan_args(argc, argv, "02", &length, &str);
13948 if (!NIL_P(length)) {
13949 len = NUM2LONG(argv[0]);
13950 }
13951 if (!NIL_P(str)) {
13952 StringValue(str);
13953 rb_str_resize(str,0);
13954 argv[1] = Qnil;
13955 }
13956
13957 retry:
13958 if (!next_argv()) {
13959 return str;
13960 }
13961 if (ARGF_GENERIC_INPUT_P()) {
13962 tmp = argf_forward(argc, argv, argf);
13963 }
13964 else {
13965 tmp = io_read(argc, argv, ARGF.current_file);
13966 }
13967 if (NIL_P(str)) str = tmp;
13968 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13969 if (NIL_P(tmp) || NIL_P(length)) {
13970 if (ARGF.next_p != -1) {
13971 argf_close(argf);
13972 ARGF.next_p = 1;
13973 goto retry;
13974 }
13975 }
13976 else if (argc >= 1) {
13977 long slen = RSTRING_LEN(str);
13978 if (slen < len) {
13979 argv[0] = LONG2NUM(len - slen);
13980 goto retry;
13981 }
13982 }
13983 return str;
13984}
13985
13987 int argc;
13988 VALUE *argv;
13989 VALUE argf;
13990};
13991
13992static VALUE
13993argf_forward_call(VALUE arg)
13994{
13995 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13996 argf_forward(p->argc, p->argv, p->argf);
13997 return Qnil;
13998}
13999
14000static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
14001 int nonblock);
14002
14003/*
14004 * call-seq:
14005 * ARGF.readpartial(maxlen) -> string
14006 * ARGF.readpartial(maxlen, outbuf) -> outbuf
14007 *
14008 * Reads at most _maxlen_ bytes from the ARGF stream.
14009 *
14010 * If the optional _outbuf_ argument is present,
14011 * it must reference a String, which will receive the data.
14012 * The _outbuf_ will contain only the received data after the method call
14013 * even if it is not empty at the beginning.
14014 *
14015 * It raises EOFError on end of ARGF stream.
14016 * Since ARGF stream is a concatenation of multiple files,
14017 * internally EOF is occur for each file.
14018 * ARGF.readpartial returns empty strings for EOFs except the last one and
14019 * raises EOFError for the last one.
14020 *
14021 */
14022
14023static VALUE
14024argf_readpartial(int argc, VALUE *argv, VALUE argf)
14025{
14026 return argf_getpartial(argc, argv, argf, Qnil, 0);
14027}
14028
14029/*
14030 * call-seq:
14031 * ARGF.read_nonblock(maxlen[, options]) -> string
14032 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14033 *
14034 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14035 */
14036
14037static VALUE
14038argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14039{
14040 VALUE opts;
14041
14042 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14043
14044 if (!NIL_P(opts))
14045 argc--;
14046
14047 return argf_getpartial(argc, argv, argf, opts, 1);
14048}
14049
14050static VALUE
14051argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14052{
14053 VALUE tmp, str, length;
14054 int no_exception;
14055
14056 rb_scan_args(argc, argv, "11", &length, &str);
14057 if (!NIL_P(str)) {
14058 StringValue(str);
14059 argv[1] = str;
14060 }
14061 no_exception = no_exception_p(opts);
14062
14063 if (!next_argv()) {
14064 if (!NIL_P(str)) {
14065 rb_str_resize(str, 0);
14066 }
14067 rb_eof_error();
14068 }
14069 if (ARGF_GENERIC_INPUT_P()) {
14070 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14071 struct argf_call_arg arg;
14072 arg.argc = argc;
14073 arg.argv = argv;
14074 arg.argf = argf;
14075 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14076 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14077 }
14078 else {
14079 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14080 }
14081 if (NIL_P(tmp)) {
14082 if (ARGF.next_p == -1) {
14083 return io_nonblock_eof(no_exception);
14084 }
14085 argf_close(argf);
14086 ARGF.next_p = 1;
14087 if (RARRAY_LEN(ARGF.argv) == 0) {
14088 return io_nonblock_eof(no_exception);
14089 }
14090 if (NIL_P(str))
14091 str = rb_str_new(NULL, 0);
14092 return str;
14093 }
14094 return tmp;
14095}
14096
14097/*
14098 * call-seq:
14099 * ARGF.getc -> String or nil
14100 *
14101 * Reads the next character from ARGF and returns it as a String. Returns
14102 * +nil+ at the end of the stream.
14103 *
14104 * ARGF treats the files named on the command line as a single file created
14105 * by concatenating their contents. After returning the last character of the
14106 * first file, it returns the first character of the second file, and so on.
14107 *
14108 * For example:
14109 *
14110 * $ echo "foo" > file
14111 * $ ruby argf.rb file
14112 *
14113 * ARGF.getc #=> "f"
14114 * ARGF.getc #=> "o"
14115 * ARGF.getc #=> "o"
14116 * ARGF.getc #=> "\n"
14117 * ARGF.getc #=> nil
14118 * ARGF.getc #=> nil
14119 */
14120static VALUE
14121argf_getc(VALUE argf)
14122{
14123 VALUE ch;
14124
14125 retry:
14126 if (!next_argv()) return Qnil;
14127 if (ARGF_GENERIC_INPUT_P()) {
14128 ch = forward_current(rb_intern("getc"), 0, 0);
14129 }
14130 else {
14131 ch = rb_io_getc(ARGF.current_file);
14132 }
14133 if (NIL_P(ch) && ARGF.next_p != -1) {
14134 argf_close(argf);
14135 ARGF.next_p = 1;
14136 goto retry;
14137 }
14138
14139 return ch;
14140}
14141
14142/*
14143 * call-seq:
14144 * ARGF.getbyte -> Integer or nil
14145 *
14146 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14147 * the end of the stream.
14148 *
14149 * For example:
14150 *
14151 * $ echo "foo" > file
14152 * $ ruby argf.rb file
14153 *
14154 * ARGF.getbyte #=> 102
14155 * ARGF.getbyte #=> 111
14156 * ARGF.getbyte #=> 111
14157 * ARGF.getbyte #=> 10
14158 * ARGF.getbyte #=> nil
14159 */
14160static VALUE
14161argf_getbyte(VALUE argf)
14162{
14163 VALUE ch;
14164
14165 retry:
14166 if (!next_argv()) return Qnil;
14167 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14168 ch = forward_current(rb_intern("getbyte"), 0, 0);
14169 }
14170 else {
14171 ch = rb_io_getbyte(ARGF.current_file);
14172 }
14173 if (NIL_P(ch) && ARGF.next_p != -1) {
14174 argf_close(argf);
14175 ARGF.next_p = 1;
14176 goto retry;
14177 }
14178
14179 return ch;
14180}
14181
14182/*
14183 * call-seq:
14184 * ARGF.readchar -> String or nil
14185 *
14186 * Reads the next character from ARGF and returns it as a String. Raises
14187 * an EOFError after the last character of the last file has been read.
14188 *
14189 * For example:
14190 *
14191 * $ echo "foo" > file
14192 * $ ruby argf.rb file
14193 *
14194 * ARGF.readchar #=> "f"
14195 * ARGF.readchar #=> "o"
14196 * ARGF.readchar #=> "o"
14197 * ARGF.readchar #=> "\n"
14198 * ARGF.readchar #=> end of file reached (EOFError)
14199 */
14200static VALUE
14201argf_readchar(VALUE argf)
14202{
14203 VALUE ch;
14204
14205 retry:
14206 if (!next_argv()) rb_eof_error();
14207 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14208 ch = forward_current(rb_intern("getc"), 0, 0);
14209 }
14210 else {
14211 ch = rb_io_getc(ARGF.current_file);
14212 }
14213 if (NIL_P(ch) && ARGF.next_p != -1) {
14214 argf_close(argf);
14215 ARGF.next_p = 1;
14216 goto retry;
14217 }
14218
14219 return ch;
14220}
14221
14222/*
14223 * call-seq:
14224 * ARGF.readbyte -> Integer
14225 *
14226 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14227 * an EOFError after the last byte of the last file has been read.
14228 *
14229 * For example:
14230 *
14231 * $ echo "foo" > file
14232 * $ ruby argf.rb file
14233 *
14234 * ARGF.readbyte #=> 102
14235 * ARGF.readbyte #=> 111
14236 * ARGF.readbyte #=> 111
14237 * ARGF.readbyte #=> 10
14238 * ARGF.readbyte #=> end of file reached (EOFError)
14239 */
14240static VALUE
14241argf_readbyte(VALUE argf)
14242{
14243 VALUE c;
14244
14245 NEXT_ARGF_FORWARD(0, 0);
14246 c = argf_getbyte(argf);
14247 if (NIL_P(c)) {
14248 rb_eof_error();
14249 }
14250 return c;
14251}
14252
14253#define FOREACH_ARGF() while (next_argv())
14254
14255static VALUE
14256argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14257{
14258 const VALUE current = ARGF.current_file;
14259 rb_yield_values2(argc, argv);
14260 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14262 }
14263 return Qnil;
14264}
14265
14266#define ARGF_block_call(mid, argc, argv, func, argf) \
14267 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14268 func, argf, rb_keyword_given_p())
14269
14270static void
14271argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14272{
14273 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14274 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14275}
14276
14277static VALUE
14278argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14279{
14280 if (!global_argf_p(argf)) {
14281 ARGF.last_lineno = ++ARGF.lineno;
14282 }
14283 return argf_block_call_i(i, argf, argc, argv, blockarg);
14284}
14285
14286static void
14287argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14288{
14289 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14290 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14291}
14292
14293/*
14294 * call-seq:
14295 * ARGF.each(sep=$/) {|line| block } -> ARGF
14296 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14297 * ARGF.each(...) -> an_enumerator
14298 *
14299 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14300 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14301 * ARGF.each_line(...) -> an_enumerator
14302 *
14303 * Returns an enumerator which iterates over each line (separated by _sep_,
14304 * which defaults to your platform's newline character) of each file in
14305 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14306 * block, otherwise an enumerator is returned.
14307 * The optional _limit_ argument is an Integer specifying the maximum
14308 * length of each line; longer lines will be split according to this limit.
14309 *
14310 * This method allows you to treat the files supplied on the command line as
14311 * a single file consisting of the concatenation of each named file. After
14312 * the last line of the first file has been returned, the first line of the
14313 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14314 * used to determine the filename of the current line and line number of the
14315 * whole input, respectively.
14316 *
14317 * For example, the following code prints out each line of each named file
14318 * prefixed with its line number, displaying the filename once per file:
14319 *
14320 * ARGF.each_line do |line|
14321 * puts ARGF.filename if ARGF.file.lineno == 1
14322 * puts "#{ARGF.file.lineno}: #{line}"
14323 * end
14324 *
14325 * While the following code prints only the first file's name at first, and
14326 * the contents with line number counted through all named files.
14327 *
14328 * ARGF.each_line do |line|
14329 * puts ARGF.filename if ARGF.lineno == 1
14330 * puts "#{ARGF.lineno}: #{line}"
14331 * end
14332 */
14333static VALUE
14334argf_each_line(int argc, VALUE *argv, VALUE argf)
14335{
14336 RETURN_ENUMERATOR(argf, argc, argv);
14337 FOREACH_ARGF() {
14338 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14339 }
14340 return argf;
14341}
14342
14343/*
14344 * call-seq:
14345 * ARGF.each_byte {|byte| block } -> ARGF
14346 * ARGF.each_byte -> an_enumerator
14347 *
14348 * Iterates over each byte of each file in +ARGV+.
14349 * A byte is returned as an Integer in the range 0..255.
14350 *
14351 * This method allows you to treat the files supplied on the command line as
14352 * a single file consisting of the concatenation of each named file. After
14353 * the last byte of the first file has been returned, the first byte of the
14354 * second file is returned. The ARGF.filename method can be used to
14355 * determine the filename of the current byte.
14356 *
14357 * If no block is given, an enumerator is returned instead.
14358 *
14359 * For example:
14360 *
14361 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14362 *
14363 */
14364static VALUE
14365argf_each_byte(VALUE argf)
14366{
14367 RETURN_ENUMERATOR(argf, 0, 0);
14368 FOREACH_ARGF() {
14369 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14370 }
14371 return argf;
14372}
14373
14374/*
14375 * call-seq:
14376 * ARGF.each_char {|char| block } -> ARGF
14377 * ARGF.each_char -> an_enumerator
14378 *
14379 * Iterates over each character of each file in ARGF.
14380 *
14381 * This method allows you to treat the files supplied on the command line as
14382 * a single file consisting of the concatenation of each named file. After
14383 * the last character of the first file has been returned, the first
14384 * character of the second file is returned. The ARGF.filename method can
14385 * be used to determine the name of the file in which the current character
14386 * appears.
14387 *
14388 * If no block is given, an enumerator is returned instead.
14389 */
14390static VALUE
14391argf_each_char(VALUE argf)
14392{
14393 RETURN_ENUMERATOR(argf, 0, 0);
14394 FOREACH_ARGF() {
14395 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14396 }
14397 return argf;
14398}
14399
14400/*
14401 * call-seq:
14402 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14403 * ARGF.each_codepoint -> an_enumerator
14404 *
14405 * Iterates over each codepoint of each file in ARGF.
14406 *
14407 * This method allows you to treat the files supplied on the command line as
14408 * a single file consisting of the concatenation of each named file. After
14409 * the last codepoint of the first file has been returned, the first
14410 * codepoint of the second file is returned. The ARGF.filename method can
14411 * be used to determine the name of the file in which the current codepoint
14412 * appears.
14413 *
14414 * If no block is given, an enumerator is returned instead.
14415 */
14416static VALUE
14417argf_each_codepoint(VALUE argf)
14418{
14419 RETURN_ENUMERATOR(argf, 0, 0);
14420 FOREACH_ARGF() {
14421 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14422 }
14423 return argf;
14424}
14425
14426/*
14427 * call-seq:
14428 * ARGF.filename -> String
14429 * ARGF.path -> String
14430 *
14431 * Returns the current filename. "-" is returned when the current file is
14432 * STDIN.
14433 *
14434 * For example:
14435 *
14436 * $ echo "foo" > foo
14437 * $ echo "bar" > bar
14438 * $ echo "glark" > glark
14439 *
14440 * $ ruby argf.rb foo bar glark
14441 *
14442 * ARGF.filename #=> "foo"
14443 * ARGF.read(5) #=> "foo\nb"
14444 * ARGF.filename #=> "bar"
14445 * ARGF.skip
14446 * ARGF.filename #=> "glark"
14447 */
14448static VALUE
14449argf_filename(VALUE argf)
14450{
14451 next_argv();
14452 return ARGF.filename;
14453}
14454
14455static VALUE
14456argf_filename_getter(ID id, VALUE *var)
14457{
14458 return argf_filename(*var);
14459}
14460
14461/*
14462 * call-seq:
14463 * ARGF.file -> IO or File object
14464 *
14465 * Returns the current file as an IO or File object.
14466 * <code>$stdin</code> is returned when the current file is STDIN.
14467 *
14468 * For example:
14469 *
14470 * $ echo "foo" > foo
14471 * $ echo "bar" > bar
14472 *
14473 * $ ruby argf.rb foo bar
14474 *
14475 * ARGF.file #=> #<File:foo>
14476 * ARGF.read(5) #=> "foo\nb"
14477 * ARGF.file #=> #<File:bar>
14478 */
14479static VALUE
14480argf_file(VALUE argf)
14481{
14482 next_argv();
14483 return ARGF.current_file;
14484}
14485
14486/*
14487 * call-seq:
14488 * ARGF.binmode -> ARGF
14489 *
14490 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14491 * be reset to non-binary mode. This option has the following effects:
14492 *
14493 * * Newline conversion is disabled.
14494 * * Encoding conversion is disabled.
14495 * * Content is treated as ASCII-8BIT.
14496 */
14497static VALUE
14498argf_binmode_m(VALUE argf)
14499{
14500 ARGF.binmode = 1;
14501 next_argv();
14502 ARGF_FORWARD(0, 0);
14503 rb_io_ascii8bit_binmode(ARGF.current_file);
14504 return argf;
14505}
14506
14507/*
14508 * call-seq:
14509 * ARGF.binmode? -> true or false
14510 *
14511 * Returns true if ARGF is being read in binary mode; false otherwise.
14512 * To enable binary mode use ARGF.binmode.
14513 *
14514 * For example:
14515 *
14516 * ARGF.binmode? #=> false
14517 * ARGF.binmode
14518 * ARGF.binmode? #=> true
14519 */
14520static VALUE
14521argf_binmode_p(VALUE argf)
14522{
14523 return RBOOL(ARGF.binmode);
14524}
14525
14526/*
14527 * call-seq:
14528 * ARGF.skip -> ARGF
14529 *
14530 * Sets the current file to the next file in ARGV. If there aren't any more
14531 * files it has no effect.
14532 *
14533 * For example:
14534 *
14535 * $ ruby argf.rb foo bar
14536 * ARGF.filename #=> "foo"
14537 * ARGF.skip
14538 * ARGF.filename #=> "bar"
14539 */
14540static VALUE
14541argf_skip(VALUE argf)
14542{
14543 if (ARGF.init_p && ARGF.next_p == 0) {
14544 argf_close(argf);
14545 ARGF.next_p = 1;
14546 }
14547 return argf;
14548}
14549
14550/*
14551 * call-seq:
14552 * ARGF.close -> ARGF
14553 *
14554 * Closes the current file and skips to the next file in ARGV. If there are
14555 * no more files to open, just closes the current file. STDIN will not be
14556 * closed.
14557 *
14558 * For example:
14559 *
14560 * $ ruby argf.rb foo bar
14561 *
14562 * ARGF.filename #=> "foo"
14563 * ARGF.close
14564 * ARGF.filename #=> "bar"
14565 * ARGF.close
14566 */
14567static VALUE
14568argf_close_m(VALUE argf)
14569{
14570 next_argv();
14571 argf_close(argf);
14572 if (ARGF.next_p != -1) {
14573 ARGF.next_p = 1;
14574 }
14575 ARGF.lineno = 0;
14576 return argf;
14577}
14578
14579/*
14580 * call-seq:
14581 * ARGF.closed? -> true or false
14582 *
14583 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14584 * ARGF.close to actually close the current file.
14585 */
14586static VALUE
14587argf_closed(VALUE argf)
14588{
14589 next_argv();
14590 ARGF_FORWARD(0, 0);
14591 return rb_io_closed_p(ARGF.current_file);
14592}
14593
14594/*
14595 * call-seq:
14596 * ARGF.to_s -> String
14597 *
14598 * Returns "ARGF".
14599 */
14600static VALUE
14601argf_to_s(VALUE argf)
14602{
14603 return rb_str_new2("ARGF");
14604}
14605
14606/*
14607 * call-seq:
14608 * ARGF.inplace_mode -> String
14609 *
14610 * Returns the file extension appended to the names of backup copies of
14611 * modified files under in-place edit mode. This value can be set using
14612 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14613 */
14614static VALUE
14615argf_inplace_mode_get(VALUE argf)
14616{
14617 if (!ARGF.inplace) return Qnil;
14618 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14619 return rb_str_dup(ARGF.inplace);
14620}
14621
14622static VALUE
14623opt_i_get(ID id, VALUE *var)
14624{
14625 return argf_inplace_mode_get(*var);
14626}
14627
14628/*
14629 * call-seq:
14630 * ARGF.inplace_mode = ext -> ARGF
14631 *
14632 * Sets the filename extension for in-place editing mode to the given String.
14633 * The backup copy of each file being edited has this value appended to its
14634 * filename.
14635 *
14636 * For example:
14637 *
14638 * $ ruby argf.rb file.txt
14639 *
14640 * ARGF.inplace_mode = '.bak'
14641 * ARGF.each_line do |line|
14642 * print line.sub("foo","bar")
14643 * end
14644 *
14645 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14646 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14647 * "bar".
14648 */
14649static VALUE
14650argf_inplace_mode_set(VALUE argf, VALUE val)
14651{
14652 if (!RTEST(val)) {
14653 ARGF.inplace = Qfalse;
14654 }
14655 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14656 ARGF.inplace = Qnil;
14657 }
14658 else {
14659 ARGF.inplace = rb_str_new_frozen(val);
14660 }
14661 return argf;
14662}
14663
14664static void
14665opt_i_set(VALUE val, ID id, VALUE *var)
14666{
14667 argf_inplace_mode_set(*var, val);
14668}
14669
14670void
14671ruby_set_inplace_mode(const char *suffix)
14672{
14673 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14674}
14675
14676/*
14677 * call-seq:
14678 * ARGF.argv -> ARGV
14679 *
14680 * Returns the +ARGV+ array, which contains the arguments passed to your
14681 * script, one per element.
14682 *
14683 * For example:
14684 *
14685 * $ ruby argf.rb -v glark.txt
14686 *
14687 * ARGF.argv #=> ["-v", "glark.txt"]
14688 *
14689 */
14690static VALUE
14691argf_argv(VALUE argf)
14692{
14693 return ARGF.argv;
14694}
14695
14696static VALUE
14697argf_argv_getter(ID id, VALUE *var)
14698{
14699 return argf_argv(*var);
14700}
14701
14702VALUE
14704{
14705 return ARGF.argv;
14706}
14707
14708/*
14709 * call-seq:
14710 * ARGF.to_write_io -> io
14711 *
14712 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14713 * enabled.
14714 */
14715static VALUE
14716argf_write_io(VALUE argf)
14717{
14718 if (!RTEST(ARGF.current_file)) {
14719 rb_raise(rb_eIOError, "not opened for writing");
14720 }
14721 return GetWriteIO(ARGF.current_file);
14722}
14723
14724/*
14725 * call-seq:
14726 * ARGF.write(*objects) -> integer
14727 *
14728 * Writes each of the given +objects+ if inplace mode.
14729 */
14730static VALUE
14731argf_write(int argc, VALUE *argv, VALUE argf)
14732{
14733 return rb_io_writev(argf_write_io(argf), argc, argv);
14734}
14735
14736void
14737rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14738{
14739 rb_readwrite_syserr_fail(waiting, errno, mesg);
14740}
14741
14742void
14743rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14744{
14745 VALUE arg, c = Qnil;
14746 arg = mesg ? rb_str_new2(mesg) : Qnil;
14747 switch (waiting) {
14748 case RB_IO_WAIT_WRITABLE:
14749 switch (n) {
14750 case EAGAIN:
14751 c = rb_eEAGAINWaitWritable;
14752 break;
14753#if EAGAIN != EWOULDBLOCK
14754 case EWOULDBLOCK:
14755 c = rb_eEWOULDBLOCKWaitWritable;
14756 break;
14757#endif
14758 case EINPROGRESS:
14759 c = rb_eEINPROGRESSWaitWritable;
14760 break;
14761 default:
14763 }
14764 break;
14765 case RB_IO_WAIT_READABLE:
14766 switch (n) {
14767 case EAGAIN:
14768 c = rb_eEAGAINWaitReadable;
14769 break;
14770#if EAGAIN != EWOULDBLOCK
14771 case EWOULDBLOCK:
14772 c = rb_eEWOULDBLOCKWaitReadable;
14773 break;
14774#endif
14775 case EINPROGRESS:
14776 c = rb_eEINPROGRESSWaitReadable;
14777 break;
14778 default:
14780 }
14781 break;
14782 default:
14783 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14784 }
14786}
14787
14788static VALUE
14789get_LAST_READ_LINE(ID _x, VALUE *_y)
14790{
14791 return rb_lastline_get();
14792}
14793
14794static void
14795set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14796{
14797 rb_lastline_set(val);
14798}
14799
14800/*
14801 * Document-class: IOError
14802 *
14803 * Raised when an IO operation fails.
14804 *
14805 * File.open("/etc/hosts") {|f| f << "example"}
14806 * #=> IOError: not opened for writing
14807 *
14808 * File.open("/etc/hosts") {|f| f.close; f.read }
14809 * #=> IOError: closed stream
14810 *
14811 * Note that some IO failures raise <code>SystemCallError</code>s
14812 * and these are not subclasses of IOError:
14813 *
14814 * File.open("does/not/exist")
14815 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14816 */
14817
14818/*
14819 * Document-class: EOFError
14820 *
14821 * Raised by some IO operations when reaching the end of file. Many IO
14822 * methods exist in two forms,
14823 *
14824 * one that returns +nil+ when the end of file is reached, the other
14825 * raises EOFError.
14826 *
14827 * EOFError is a subclass of IOError.
14828 *
14829 * file = File.open("/etc/hosts")
14830 * file.read
14831 * file.gets #=> nil
14832 * file.readline #=> EOFError: end of file reached
14833 * file.close
14834 */
14835
14836/*
14837 * Document-class: ARGF
14838 *
14839 * == \ARGF and +ARGV+
14840 *
14841 * The \ARGF object works with the array at global variable +ARGV+
14842 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14843 *
14844 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14845 *
14846 * Initially, it contains the command-line arguments and options
14847 * that are passed to the Ruby program;
14848 * the program can modify that array as it likes.
14849 *
14850 * - **ARGF** may be thought of as the <b>argument files</b> object.
14851 *
14852 * It can access file streams and/or the <tt>$stdin</tt> stream,
14853 * based on what it finds in +ARGV+.
14854 * This provides a convenient way for the command line
14855 * to specify streams for a Ruby program to read.
14856 *
14857 * == Reading
14858 *
14859 * \ARGF may read from _source_ streams,
14860 * which at any particular time are determined by the content of +ARGV+.
14861 *
14862 * === Simplest Case
14863 *
14864 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14865 * the source is <tt>$stdin</tt>:
14866 *
14867 * - \File +t.rb+:
14868 *
14869 * p ['ARGV', ARGV]
14870 * p ['ARGF.read', ARGF.read]
14871 *
14872 * - Commands and outputs
14873 * (see below for the content of files +foo.txt+ and +bar.txt+):
14874 *
14875 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14876 * ["ARGV", []]
14877 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14878 *
14879 * $ cat foo.txt bar.txt | ruby t.rb
14880 * ["ARGV", []]
14881 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14882 *
14883 * === About the Examples
14884 *
14885 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14886 *
14887 * $ cat foo.txt
14888 * Foo 0
14889 * Foo 1
14890 * $ cat bar.txt
14891 * Bar 0
14892 * Bar 1
14893 * Bar 2
14894 * Bar 3
14895 *
14896 * === Sources in +ARGV+
14897 *
14898 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14899 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14900 * the sources are found in +ARGV+.
14901 *
14902 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14903 * and is one of:
14904 *
14905 * - The string path to a file that may be opened as a stream.
14906 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14907 *
14908 * Each element that is _not_ one of these
14909 * should be removed from +ARGV+ before \ARGF accesses that source.
14910 *
14911 * In the following example:
14912 *
14913 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14914 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14915 *
14916 * Example:
14917 *
14918 * - \File +t.rb+:
14919 *
14920 * # Print arguments (and options, if any) found on command line.
14921 * p ['ARGV', ARGV]
14922 *
14923 * - Command and output:
14924 *
14925 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14926 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14927 *
14928 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14929 *
14930 * - \File +t.rb+:
14931 *
14932 * p "ARGV: #{ARGV}"
14933 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
14934 *
14935 * - Command and output:
14936 *
14937 * $ ruby t.rb foo.txt bar.txt
14938 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14939 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14940 *
14941 * Because the value at +ARGV+ is an ordinary array,
14942 * you can manipulate it to control which sources \ARGF considers:
14943 *
14944 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14945 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14946 *
14947 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14948 * when all sources have been accessed, the array is empty:
14949 *
14950 * - \File +t.rb+:
14951 *
14952 * until ARGV.empty? && ARGF.eof?
14953 * p "ARGV: #{ARGV}"
14954 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14955 * end
14956 *
14957 * - Command and output:
14958 *
14959 * $ ruby t.rb foo.txt bar.txt
14960 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14961 * "Line: Foo 0\n"
14962 * "ARGV: [\"bar.txt\"]"
14963 * "Line: Foo 1\n"
14964 * "ARGV: [\"bar.txt\"]"
14965 * "Line: Bar 0\n"
14966 * "ARGV: []"
14967 * "Line: Bar 1\n"
14968 * "ARGV: []"
14969 * "Line: Bar 2\n"
14970 * "ARGV: []"
14971 * "Line: Bar 3\n"
14972 *
14973 * ==== Filepaths in +ARGV+
14974 *
14975 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14976 *
14977 * This program prints what it reads from files at the paths specified
14978 * on the command line:
14979 *
14980 * - \File +t.rb+:
14981 *
14982 * p ['ARGV', ARGV]
14983 * # Read and print all content from the specified sources.
14984 * p ['ARGF.read', ARGF.read]
14985 *
14986 * - Command and output:
14987 *
14988 * $ ruby t.rb foo.txt bar.txt
14989 * ["ARGV", [foo.txt, bar.txt]
14990 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14991 *
14992 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14993 *
14994 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14995 *
14996 * - \File +t.rb+:
14997 *
14998 * p ['ARGV', ARGV]
14999 * p ['ARGF.read', ARGF.read]
15000 *
15001 * - Command and output:
15002 *
15003 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
15004 * ["ARGV", ["-"]]
15005 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15006 *
15007 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
15008 * (exception:
15009 * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
15010 *
15011 * - Command and output:
15012 *
15013 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
15014 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15015 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15016 *
15017 * ==== Mixtures and Repetitions in +ARGV+
15018 *
15019 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
15020 * and character <tt>'-'</tt>, including repetitions.
15021 *
15022 * ==== Modifications to +ARGV+
15023 *
15024 * The running Ruby program may make any modifications to the +ARGV+ array;
15025 * the current value of +ARGV+ affects \ARGF reading.
15026 *
15027 * ==== Empty +ARGV+
15028 *
15029 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15030 * or raises an exception, depending on the specific method.
15031 *
15032 * === More Read Methods
15033 *
15034 * As seen above, method ARGF#read reads the content of all sources
15035 * into a single string.
15036 * Other \ARGF methods provide other ways to access that content;
15037 * these include:
15038 *
15039 * - Byte access: #each_byte, #getbyte, #readbyte.
15040 * - Character access: #each_char, #getc, #readchar.
15041 * - Codepoint access: #each_codepoint.
15042 * - Line access: #each_line, #gets, #readline, #readlines.
15043 * - Source access: #read, #read_nonblock, #readpartial.
15044 *
15045 * === About \Enumerable
15046 *
15047 * \ARGF includes module Enumerable.
15048 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15049 *
15050 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15051 * _not_ from +ARGV+;
15052 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15053 * not an array of the strings from +ARGV+:
15054 *
15055 * - \File +t.rb+:
15056 *
15057 * p ['ARGV', ARGV]
15058 * p ['ARGF.entries', ARGF.entries]
15059 *
15060 * - Command and output:
15061 *
15062 * $ ruby t.rb foo.txt bar.txt
15063 * ["ARGV", ["foo.txt", "bar.txt"]]
15064 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15065 *
15066 * == Writing
15067 *
15068 * If <i>inplace mode</i> is in effect,
15069 * \ARGF may write to target streams,
15070 * which at any particular time are determined by the content of ARGV.
15071 *
15072 * Methods about inplace mode:
15073 *
15074 * - #inplace_mode
15075 * - #inplace_mode=
15076 * - #to_write_io
15077 *
15078 * Methods for writing:
15079 *
15080 * - #print
15081 * - #printf
15082 * - #putc
15083 * - #puts
15084 * - #write
15085 *
15086 */
15087
15088/*
15089 * An instance of class \IO (commonly called a _stream_)
15090 * represents an input/output stream in the underlying operating system.
15091 * Class \IO is the basis for input and output in Ruby.
15092 *
15093 * Class File is the only class in the Ruby core that is a subclass of \IO.
15094 * Some classes in the Ruby standard library are also subclasses of \IO;
15095 * these include TCPSocket and UDPSocket.
15096 *
15097 * The global constant ARGF (also accessible as <tt>$<</tt>)
15098 * provides an IO-like stream that allows access to all file paths
15099 * found in ARGV (or found in STDIN if ARGV is empty).
15100 * ARGF is not itself a subclass of \IO.
15101 *
15102 * Class StringIO provides an IO-like stream that handles a String.
15103 * StringIO is not itself a subclass of \IO.
15104 *
15105 * Important objects based on \IO include:
15106 *
15107 * - $stdin.
15108 * - $stdout.
15109 * - $stderr.
15110 * - Instances of class File.
15111 *
15112 * An instance of \IO may be created using:
15113 *
15114 * - IO.new: returns a new \IO object for the given integer file descriptor.
15115 * - IO.open: passes a new \IO object to the given block.
15116 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15117 * of a newly-launched subprocess.
15118 * - Kernel#open: Returns a new \IO object connected to a given source:
15119 * stream, file, or subprocess.
15120 *
15121 * Like a File stream, an \IO stream has:
15122 *
15123 * - A read/write mode, which may be read-only, write-only, or read/write;
15124 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
15125 * - A data mode, which may be text-only or binary;
15126 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15127 * - Internal and external encodings;
15128 * see {Encodings}[rdoc-ref:File@Encodings].
15129 *
15130 * And like other \IO streams, it has:
15131 *
15132 * - A position, which determines where in the stream the next
15133 * read or write is to occur;
15134 * see {Position}[rdoc-ref:IO@Position].
15135 * - A line number, which is a special, line-oriented, "position"
15136 * (different from the position mentioned above);
15137 * see {Line Number}[rdoc-ref:IO@Line+Number].
15138 *
15139 * == Extension <tt>io/console</tt>
15140 *
15141 * Extension <tt>io/console</tt> provides numerous methods
15142 * for interacting with the console;
15143 * requiring it adds numerous methods to class \IO.
15144 *
15145 * == Example Files
15146 *
15147 * Many examples here use these variables:
15148 *
15149 * :include: doc/examples/files.rdoc
15150 *
15151 * == Open Options
15152 *
15153 * A number of \IO methods accept optional keyword arguments
15154 * that determine how a new stream is to be opened:
15155 *
15156 * - +:mode+: Stream mode.
15157 * - +:flags+: Integer file open flags;
15158 * If +mode+ is also given, the two are bitwise-ORed.
15159 * - +:external_encoding+: External encoding for the stream.
15160 * - +:internal_encoding+: Internal encoding for the stream.
15161 * <tt>'-'</tt> is a synonym for the default internal encoding.
15162 * If the value is +nil+ no conversion occurs.
15163 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15164 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15165 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15166 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15167 * when the stream closes; otherwise it remains open.
15168 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15169 * #path method.
15170 *
15171 * Also available are the options offered in String#encode,
15172 * which may control conversion between external and internal encoding.
15173 *
15174 * == Basic \IO
15175 *
15176 * You can perform basic stream \IO with these methods,
15177 * which typically operate on multi-byte strings:
15178 *
15179 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15180 * - IO#write: Writes zero or more strings to the stream;
15181 * each given object that is not already a string is converted via +to_s+.
15182 *
15183 * === Position
15184 *
15185 * An \IO stream has a nonnegative integer _position_,
15186 * which is the byte offset at which the next read or write is to occur.
15187 * A new stream has position zero (and line number zero);
15188 * method +rewind+ resets the position (and line number) to zero.
15189 *
15190 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15191 * Encoding::Converter instances used for that \IO.
15192 *
15193 * The relevant methods:
15194 *
15195 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15196 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15197 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15198 * relative to a given position +whence+
15199 * (indicating the beginning, end, or current position).
15200 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15201 *
15202 * === Open and Closed Streams
15203 *
15204 * A new \IO stream may be open for reading, open for writing, or both.
15205 *
15206 * A stream is automatically closed when claimed by the garbage collector.
15207 *
15208 * Attempted reading or writing on a closed stream raises an exception.
15209 *
15210 * The relevant methods:
15211 *
15212 * - IO#close: Closes the stream for both reading and writing.
15213 * - IO#close_read: Closes the stream for reading.
15214 * - IO#close_write: Closes the stream for writing.
15215 * - IO#closed?: Returns whether the stream is closed.
15216 *
15217 * === End-of-Stream
15218 *
15219 * You can query whether a stream is positioned at its end:
15220 *
15221 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15222 *
15223 * You can reposition to end-of-stream by using method IO#seek:
15224 *
15225 * f = File.new('t.txt')
15226 * f.eof? # => false
15227 * f.seek(0, :END)
15228 * f.eof? # => true
15229 * f.close
15230 *
15231 * Or by reading all stream content (which is slower than using IO#seek):
15232 *
15233 * f.rewind
15234 * f.eof? # => false
15235 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15236 * f.eof? # => true
15237 *
15238 * == Line \IO
15239 *
15240 * Class \IO supports line-oriented
15241 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15242 *
15243 * === Line Input
15244 *
15245 * Class \IO supports line-oriented input for
15246 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15247 *
15248 * ==== \File Line Input
15249 *
15250 * You can read lines from a file using these methods:
15251 *
15252 * - IO.foreach: Reads each line and passes it to the given block.
15253 * - IO.readlines: Reads and returns all lines in an array.
15254 *
15255 * For each of these methods:
15256 *
15257 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15258 * - Line parsing depends on the effective <i>line separator</i>;
15259 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15260 * - The length of each returned line depends on the effective <i>line limit</i>;
15261 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15262 *
15263 * ==== Stream Line Input
15264 *
15265 * You can read lines from an \IO stream using these methods:
15266 *
15267 * - IO#each_line: Reads each remaining line, passing it to the given block.
15268 * - IO#gets: Returns the next line.
15269 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15270 * - IO#readlines: Returns all remaining lines in an array.
15271 *
15272 * For each of these methods:
15273 *
15274 * - Reading may begin mid-line,
15275 * depending on the stream's _position_;
15276 * see {Position}[rdoc-ref:IO@Position].
15277 * - Line parsing depends on the effective <i>line separator</i>;
15278 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15279 * - The length of each returned line depends on the effective <i>line limit</i>;
15280 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15281 *
15282 * ===== Line Separator
15283 *
15284 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15285 * the string that determines what is considered a line;
15286 * it is sometimes called the <i>input record separator</i>.
15287 *
15288 * The default line separator is taken from global variable <tt>$/</tt>,
15289 * whose initial value is <tt>"\n"</tt>.
15290 *
15291 * Generally, the line to be read next is all data
15292 * from the current {position}[rdoc-ref:IO@Position]
15293 * to the next line separator
15294 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15295 *
15296 * f = File.new('t.txt')
15297 * # Method gets with no sep argument returns the next line, according to $/.
15298 * f.gets # => "First line\n"
15299 * f.gets # => "Second line\n"
15300 * f.gets # => "\n"
15301 * f.gets # => "Fourth line\n"
15302 * f.gets # => "Fifth line\n"
15303 * f.close
15304 *
15305 * You can use a different line separator by passing argument +sep+:
15306 *
15307 * f = File.new('t.txt')
15308 * f.gets('l') # => "First l"
15309 * f.gets('li') # => "ine\nSecond li"
15310 * f.gets('lin') # => "ne\n\nFourth lin"
15311 * f.gets # => "e\n"
15312 * f.close
15313 *
15314 * Or by setting global variable <tt>$/</tt>:
15315 *
15316 * f = File.new('t.txt')
15317 * $/ = 'l'
15318 * f.gets # => "First l"
15319 * f.gets # => "ine\nSecond l"
15320 * f.gets # => "ine\n\nFourth l"
15321 * f.close
15322 *
15323 * ===== Special Line Separator Values
15324 *
15325 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15326 * accepts two special values for parameter +sep+:
15327 *
15328 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15329 *
15330 * f = File.new('t.txt')
15331 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15332 * f.close
15333 *
15334 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15335 * (paragraphs being separated by two consecutive line separators):
15336 *
15337 * f = File.new('t.txt')
15338 * f.gets('') # => "First line\nSecond line\n\n"
15339 * f.gets('') # => "Fourth line\nFifth line\n"
15340 * f.close
15341 *
15342 * ===== Line Limit
15343 *
15344 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15345 * uses an integer <i>line limit</i>,
15346 * which restricts the number of bytes that may be returned.
15347 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15348 * than the limit).
15349 *
15350 * The default limit value is <tt>-1</tt>;
15351 * any negative limit value means that there is no limit.
15352 *
15353 * If there is no limit, the line is determined only by +sep+.
15354 *
15355 * # Text with 1-byte characters.
15356 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15357 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15358 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15359 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15360 * # No more than one line.
15361 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15362 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15363 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15364 *
15365 * # Text with 2-byte characters, which will not be split.
15366 * File.open('t.rus') {|f| f.gets(1).size } # => 1
15367 * File.open('t.rus') {|f| f.gets(2).size } # => 1
15368 * File.open('t.rus') {|f| f.gets(3).size } # => 2
15369 * File.open('t.rus') {|f| f.gets(4).size } # => 2
15370 *
15371 * ===== Line Separator and Line Limit
15372 *
15373 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15374 *
15375 * - Returns the next line as determined by line separator +sep+.
15376 * - But returns no more bytes than are allowed by the limit +limit+.
15377 *
15378 * Example:
15379 *
15380 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15381 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15382 *
15383 * ===== Line Number
15384 *
15385 * A readable \IO stream has a non-negative integer <i>line number</i>:
15386 *
15387 * - IO#lineno: Returns the line number.
15388 * - IO#lineno=: Resets and returns the line number.
15389 *
15390 * Unless modified by a call to method IO#lineno=,
15391 * the line number is the number of lines read
15392 * by certain line-oriented methods,
15393 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15394 *
15395 * - IO.foreach: Increments the line number on each call to the block.
15396 * - IO#each_line: Increments the line number on each call to the block.
15397 * - IO#gets: Increments the line number.
15398 * - IO#readline: Increments the line number.
15399 * - IO#readlines: Increments the line number for each line read.
15400 *
15401 * A new stream is initially has line number zero (and position zero);
15402 * method +rewind+ resets the line number (and position) to zero:
15403 *
15404 * f = File.new('t.txt')
15405 * f.lineno # => 0
15406 * f.gets # => "First line\n"
15407 * f.lineno # => 1
15408 * f.rewind
15409 * f.lineno # => 0
15410 * f.close
15411 *
15412 * Reading lines from a stream usually changes its line number:
15413 *
15414 * f = File.new('t.txt', 'r')
15415 * f.lineno # => 0
15416 * f.readline # => "This is line one.\n"
15417 * f.lineno # => 1
15418 * f.readline # => "This is the second line.\n"
15419 * f.lineno # => 2
15420 * f.readline # => "Here's the third line.\n"
15421 * f.lineno # => 3
15422 * f.eof? # => true
15423 * f.close
15424 *
15425 * Iterating over lines in a stream usually changes its line number:
15426 *
15427 * File.open('t.txt') do |f|
15428 * f.each_line do |line|
15429 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15430 * end
15431 * end
15432 *
15433 * Output:
15434 *
15435 * "position=11 eof?=false lineno=1"
15436 * "position=23 eof?=false lineno=2"
15437 * "position=24 eof?=false lineno=3"
15438 * "position=36 eof?=false lineno=4"
15439 * "position=47 eof?=true lineno=5"
15440 *
15441 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15442 * the line number does not affect where the next read or write will occur:
15443 *
15444 * f = File.new('t.txt')
15445 * f.lineno = 1000
15446 * f.lineno # => 1000
15447 * f.gets # => "First line\n"
15448 * f.lineno # => 1001
15449 * f.close
15450 *
15451 * Associated with the line number is the global variable <tt>$.</tt>:
15452 *
15453 * - When a stream is opened, <tt>$.</tt> is not set;
15454 * its value is left over from previous activity in the process:
15455 *
15456 * $. = 41
15457 * f = File.new('t.txt')
15458 * $. = 41
15459 * # => 41
15460 * f.close
15461 *
15462 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15463 *
15464 * f0 = File.new('t.txt')
15465 * f1 = File.new('t.dat')
15466 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15467 * $. # => 5
15468 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15469 * $. # => 1
15470 * f0.close
15471 * f1.close
15472 *
15473 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15474 *
15475 * f = File.new('t.txt')
15476 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15477 * $. # => 5
15478 * f.rewind
15479 * f.seek(0, :SET)
15480 * $. # => 5
15481 * f.close
15482 *
15483 * === Line Output
15484 *
15485 * You can write to an \IO stream line-by-line using this method:
15486 *
15487 * - IO#puts: Writes objects to the stream.
15488 *
15489 * == Character \IO
15490 *
15491 * You can process an \IO stream character-by-character using these methods:
15492 *
15493 * - IO#getc: Reads and returns the next character from the stream.
15494 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15495 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15496 * - IO#putc: Writes a character to the stream.
15497 * - IO#each_char: Reads each remaining character in the stream,
15498 * passing the character to the given block.
15499 *
15500 * == Byte \IO
15501 *
15502 * You can process an \IO stream byte-by-byte using these methods:
15503 *
15504 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15505 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15506 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15507 * - IO#each_byte: Reads each remaining byte in the stream,
15508 * passing the byte to the given block.
15509 *
15510 * == Codepoint \IO
15511 *
15512 * You can process an \IO stream codepoint-by-codepoint:
15513 *
15514 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15515 *
15516 * == What's Here
15517 *
15518 * First, what's elsewhere. Class \IO:
15519 *
15520 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15521 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15522 * which provides dozens of additional methods.
15523 *
15524 * Here, class \IO provides methods that are useful for:
15525 *
15526 * - {Creating}[rdoc-ref:IO@Creating]
15527 * - {Reading}[rdoc-ref:IO@Reading]
15528 * - {Writing}[rdoc-ref:IO@Writing]
15529 * - {Positioning}[rdoc-ref:IO@Positioning]
15530 * - {Iterating}[rdoc-ref:IO@Iterating]
15531 * - {Settings}[rdoc-ref:IO@Settings]
15532 * - {Querying}[rdoc-ref:IO@Querying]
15533 * - {Buffering}[rdoc-ref:IO@Buffering]
15534 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15535 * - {Other}[rdoc-ref:IO@Other]
15536 *
15537 * === Creating
15538 *
15539 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15540 * integer file descriptor.
15541 * - ::open: Creates a new \IO object.
15542 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15543 * - ::popen: Creates an \IO object to interact with a subprocess.
15544 * - ::select: Selects which given \IO instances are ready for reading,
15545 * writing, or have pending exceptions.
15546 *
15547 * === Reading
15548 *
15549 * - ::binread: Returns a binary string with all or a subset of bytes
15550 * from the given file.
15551 * - ::read: Returns a string with all or a subset of bytes from the given file.
15552 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15553 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15554 * - #getc: Returns the next character read from +self+ as a string.
15555 * - #gets: Returns the line read from +self+.
15556 * - #pread: Returns all or the next _n_ bytes read from +self+,
15557 * not updating the receiver's offset.
15558 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15559 * for a given _n_.
15560 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15561 * in non-block mode.
15562 * - #readbyte: Returns the next byte read from +self+;
15563 * same as #getbyte, but raises an exception on end-of-stream.
15564 * - #readchar: Returns the next character read from +self+;
15565 * same as #getc, but raises an exception on end-of-stream.
15566 * - #readline: Returns the next line read from +self+;
15567 * same as #getline, but raises an exception of end-of-stream.
15568 * - #readlines: Returns an array of all lines read read from +self+.
15569 * - #readpartial: Returns up to the given number of bytes from +self+.
15570 *
15571 * === Writing
15572 *
15573 * - ::binwrite: Writes the given string to the file at the given filepath,
15574 * in binary mode.
15575 * - ::write: Writes the given string to +self+.
15576 * - #<<: Appends the given string to +self+.
15577 * - #print: Prints last read line or given objects to +self+.
15578 * - #printf: Writes to +self+ based on the given format string and objects.
15579 * - #putc: Writes a character to +self+.
15580 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15581 * - #pwrite: Writes the given string at the given offset,
15582 * not updating the receiver's offset.
15583 * - #write: Writes one or more given strings to +self+.
15584 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15585 *
15586 * === Positioning
15587 *
15588 * - #lineno: Returns the current line number in +self+.
15589 * - #lineno=: Sets the line number is +self+.
15590 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15591 * - #pos=: Sets the byte offset in +self+.
15592 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15593 * - #rewind: Positions +self+ to the beginning of input.
15594 * - #seek: Sets the offset for +self+ relative to given position.
15595 *
15596 * === Iterating
15597 *
15598 * - ::foreach: Yields each line of given file to the block.
15599 * - #each (aliased as #each_line): Calls the given block
15600 * with each successive line in +self+.
15601 * - #each_byte: Calls the given block with each successive byte in +self+
15602 * as an integer.
15603 * - #each_char: Calls the given block with each successive character in +self+
15604 * as a string.
15605 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15606 * as an integer.
15607 *
15608 * === Settings
15609 *
15610 * - #autoclose=: Sets whether +self+ auto-closes.
15611 * - #binmode: Sets +self+ to binary mode.
15612 * - #close: Closes +self+.
15613 * - #close_on_exec=: Sets the close-on-exec flag.
15614 * - #close_read: Closes +self+ for reading.
15615 * - #close_write: Closes +self+ for writing.
15616 * - #set_encoding: Sets the encoding for +self+.
15617 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15618 * Unicode byte-order-mark.
15619 * - #sync=: Sets the sync-mode to the given value.
15620 *
15621 * === Querying
15622 *
15623 * - #autoclose?: Returns whether +self+ auto-closes.
15624 * - #binmode?: Returns whether +self+ is in binary mode.
15625 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15626 * - #closed?: Returns whether +self+ is closed.
15627 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15628 * - #external_encoding: Returns the external encoding object for +self+.
15629 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15630 * - #internal_encoding: Returns the internal encoding object for +self+.
15631 * - #pid: Returns the process ID of a child process associated with +self+,
15632 * if +self+ was created by ::popen.
15633 * - #stat: Returns the File::Stat object containing status information for +self+.
15634 * - #sync: Returns whether +self+ is in sync-mode.
15635 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15636 *
15637 * === Buffering
15638 *
15639 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15640 * - #flush: Flushes any buffered data within +self+ to the underlying
15641 * operating system.
15642 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15643 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15644 * - #ungetc: Prepends buffer for +self+ with given string.
15645 *
15646 * === Low-Level Access
15647 *
15648 * - ::sysopen: Opens the file given by its path,
15649 * returning the integer file descriptor.
15650 * - #advise: Announces the intention to access data from +self+ in a specific way.
15651 * - #fcntl: Passes a low-level command to the file specified
15652 * by the given file descriptor.
15653 * - #ioctl: Passes a low-level command to the device specified
15654 * by the given file descriptor.
15655 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15656 * - #sysseek: Sets the offset for +self+.
15657 * - #syswrite: Writes the given string to +self+ using a low-level write.
15658 *
15659 * === Other
15660 *
15661 * - ::copy_stream: Copies data from a source to a destination,
15662 * each of which is a filepath or an \IO-like object.
15663 * - ::try_convert: Returns a new \IO object resulting from converting
15664 * the given object.
15665 * - #inspect: Returns the string representation of +self+.
15666 *
15667 */
15668
15669void
15670Init_IO(void)
15671{
15672 VALUE rb_cARGF;
15673#ifdef __CYGWIN__
15674#include <sys/cygwin.h>
15675 static struct __cygwin_perfile pf[] =
15676 {
15677 {"", O_RDONLY | O_BINARY},
15678 {"", O_WRONLY | O_BINARY},
15679 {"", O_RDWR | O_BINARY},
15680 {"", O_APPEND | O_BINARY},
15681 {NULL, 0}
15682 };
15683 cygwin_internal(CW_PERFILE, pf);
15684#endif
15685
15688
15689 id_write = rb_intern_const("write");
15690 id_read = rb_intern_const("read");
15691 id_getc = rb_intern_const("getc");
15692 id_flush = rb_intern_const("flush");
15693 id_readpartial = rb_intern_const("readpartial");
15694 id_set_encoding = rb_intern_const("set_encoding");
15695 id_fileno = rb_intern_const("fileno");
15696
15697 rb_define_global_function("syscall", rb_f_syscall, -1);
15698
15699 rb_define_global_function("open", rb_f_open, -1);
15700 rb_define_global_function("printf", rb_f_printf, -1);
15701 rb_define_global_function("print", rb_f_print, -1);
15702 rb_define_global_function("putc", rb_f_putc, 1);
15703 rb_define_global_function("puts", rb_f_puts, -1);
15704 rb_define_global_function("gets", rb_f_gets, -1);
15705 rb_define_global_function("readline", rb_f_readline, -1);
15706 rb_define_global_function("select", rb_f_select, -1);
15707
15708 rb_define_global_function("readlines", rb_f_readlines, -1);
15709
15710 rb_define_global_function("`", rb_f_backquote, 1);
15711
15712 rb_define_global_function("p", rb_f_p, -1);
15713 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15714
15715 rb_cIO = rb_define_class("IO", rb_cObject);
15717
15718 /* Can be raised by IO operations when IO#timeout= is set. */
15720
15721 /* Readable event mask for IO#wait. */
15722 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15723 /* Writable event mask for IO#wait. */
15724 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15725 /* Priority event mask for IO#wait. */
15726 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15727
15728 /* exception to wait for reading. see IO.select. */
15730 /* exception to wait for writing. see IO.select. */
15732 /* exception to wait for reading by EAGAIN. see IO.select. */
15733 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15734 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15735 /* exception to wait for writing by EAGAIN. see IO.select. */
15736 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15737 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15738#if EAGAIN == EWOULDBLOCK
15739 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15740 /* same as IO::EAGAINWaitReadable */
15741 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15742 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15743 /* same as IO::EAGAINWaitWritable */
15744 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15745#else
15746 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15747 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15748 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15749 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15750 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15751 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15752#endif
15753 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15754 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15755 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15756 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15757 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15758 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15759
15760#if 0
15761 /* This is necessary only for forcing rdoc handle File::open */
15762 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15763#endif
15764
15765 rb_define_alloc_func(rb_cIO, io_alloc);
15766 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15767 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15768 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15769 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15770 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15771 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15772 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15773 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15774 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15775 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15776 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15777 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15778 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15779 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15780 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15781
15782 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15783
15785 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
15786
15787 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15788 rb_vm_register_global_object(rb_default_rs);
15789 rb_rs = rb_default_rs;
15791 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15792 rb_gvar_ractor_local("$/"); // not local but ractor safe
15793 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15794 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15795 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
15796
15797 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15798 rb_gvar_ractor_local("$_");
15799 rb_gvar_box_dynamic("$_");
15800
15801 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15802 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15803
15804 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15805 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15806 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15807 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15808
15809 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15810 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15811 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15812 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15813 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15814
15815 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15816 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15817
15818 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15819 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15820
15821 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15822 rb_define_alias(rb_cIO, "to_i", "fileno");
15823 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15824
15825 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15826 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15827
15828 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15829 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15830 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15831 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15832
15833 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15834 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15835
15836 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15837
15838 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15839 rb_define_method(rb_cIO, "read", io_read, -1);
15840 rb_define_method(rb_cIO, "write", io_write_m, -1);
15841 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15842 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15843 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15844 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15845 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15846 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15847 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15849 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15850 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15851 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15852 /* Set I/O position from the beginning */
15853 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15854 /* Set I/O position from the current position */
15855 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15856 /* Set I/O position from the end */
15857 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15858#ifdef SEEK_DATA
15859 /* Set I/O position to the next location containing data */
15860 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15861#endif
15862#ifdef SEEK_HOLE
15863 /* Set I/O position to the next hole */
15864 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15865#endif
15866 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15867 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15868 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15869 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15870 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15871
15872 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15873 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15874
15875 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15876 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15877 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15878 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15879
15880 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15881 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15882 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15883 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15884 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15885 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15886
15887 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15888 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15889 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15890
15891 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15892 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15893
15894 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15895
15896 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15897 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15898 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15899 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15900
15901 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15902 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15903
15904 rb_define_method(rb_cIO, "wait", io_wait, -1);
15905
15906 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15907 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15908 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15909
15910 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15911 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15912 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15913 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15914
15915 rb_gvar_ractor_local("$stdin");
15916 rb_gvar_ractor_local("$stdout");
15917 rb_gvar_ractor_local("$>");
15918 rb_gvar_ractor_local("$stderr");
15919
15921 rb_stdin = rb_io_prep_stdin();
15923 rb_stdout = rb_io_prep_stdout();
15925 rb_stderr = rb_io_prep_stderr();
15926
15927 orig_stdout = rb_stdout;
15928 orig_stderr = rb_stderr;
15929
15930 /* Holds the original stdin */
15932 /* Holds the original stdout */
15934 /* Holds the original stderr */
15936
15937#if 0
15938 /* Hack to get rdoc to regard ARGF as a class: */
15939 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15940#endif
15941
15942 rb_cARGF = rb_class_new(rb_cObject);
15943 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15944 rb_define_alloc_func(rb_cARGF, argf_alloc);
15945
15947
15948 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15949 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15950 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15951 rb_define_alias(rb_cARGF, "inspect", "to_s");
15952 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15953
15954 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15955 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15956 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15957 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15958 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15959 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15960 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15961 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15962 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15963
15964 rb_define_method(rb_cARGF, "read", argf_read, -1);
15965 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15966 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15967 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15968 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15969 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15970 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15971 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15972 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15973 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15974 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15975 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15976 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15977 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15978 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15979 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15980 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15981 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15982 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15983 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15984
15985 rb_define_method(rb_cARGF, "write", argf_write, -1);
15986 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15987 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15988 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15989 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15990
15991 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15992 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15993 rb_define_method(rb_cARGF, "file", argf_file, 0);
15994 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15995 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15996 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15997
15998 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15999 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
16000
16001 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
16002 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
16003
16004 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
16005 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
16006 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
16007
16008 argf = rb_class_new_instance(0, 0, rb_cARGF);
16009
16011 /*
16012 * ARGF is a stream designed for use in scripts that process files given
16013 * as command-line arguments or passed in via STDIN.
16014 *
16015 * See ARGF (the class) for more details.
16016 */
16018
16019 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
16020 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
16021 ARGF.filename = rb_str_new2("-");
16022
16023 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
16024 rb_gvar_ractor_local("$-i");
16025
16026 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16027
16028#if defined (_WIN32) || defined(__CYGWIN__)
16029 atexit(pipe_atexit);
16030#endif
16031
16032 Init_File();
16033
16034 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16035
16036 sym_mode = ID2SYM(rb_intern_const("mode"));
16037 sym_perm = ID2SYM(rb_intern_const("perm"));
16038 sym_flags = ID2SYM(rb_intern_const("flags"));
16039 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16040 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16041 sym_encoding = ID2SYM(rb_id_encoding());
16042 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16043 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16044 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16045 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16046 sym_normal = ID2SYM(rb_intern_const("normal"));
16047 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16048 sym_random = ID2SYM(rb_intern_const("random"));
16049 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16050 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16051 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16052 sym_SET = ID2SYM(rb_intern_const("SET"));
16053 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16054 sym_END = ID2SYM(rb_intern_const("END"));
16055#ifdef SEEK_DATA
16056 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16057#endif
16058#ifdef SEEK_HOLE
16059 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16060#endif
16061 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16062 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16063}
16064
16065#include "io.rbinc"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
#define STRNCASECMP
@old{st_locale_insensitive_strncasecmp}
Definition ctype.h:103
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:1695
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1488
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:856
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1519
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1624
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2868
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:3171
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:3158
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1021
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2947
#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:134
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
#define ECONV_NEWLINE_DECORATOR_WRITE_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_WRITE_MASK.
Definition transcode.h:531
#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 MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:518
#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 ECONV_NEWLINE_DECORATOR_READ_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_READ_MASK.
Definition transcode.h:530
#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_notimplement(void)
Definition error.c:3840
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:476
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:508
VALUE rb_rescue2(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*r_proc)(VALUE, VALUE), VALUE data2,...)
An equivalent of rescue clause.
Definition eval.c:1050
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1441
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:664
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3909
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int err, const char *msg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
Definition io.c:14743
VALUE rb_eIOError
IOError exception.
Definition io.c:193
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1428
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3999
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3915
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:475
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1431
VALUE rb_eEOFError
EOFError exception.
Definition io.c:192
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *msg)
Raises appropriate exception using the parameters.
Definition io.c:14737
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2289
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1429
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
Definition eval.c:1172
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1451
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:60
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3312
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:675
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2208
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2249
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:2237
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
VALUE rb_stdin
STDIN constant.
Definition io.c:205
VALUE rb_stderr
STDERR constant.
Definition io.c:205
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:264
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:582
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:686
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:195
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:196
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1342
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
Definition object.c:3293
VALUE rb_cFile
File class.
Definition file.c:191
VALUE rb_stdout
STDOUT constant.
Definition io.c:205
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3306
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1342
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3939
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c:831
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
Definition transcode.c:2675
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:2125
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:1782
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1826
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:1961
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:2726
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:2024
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:2989
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4355
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4361
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1743
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1793
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1117
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
Definition vm_eval.c:1084
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:242
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8673
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4390
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:513
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:8806
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2446
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9235
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:5255
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5161
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:411
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:9416
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:285
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:365
VALUE rb_output_rs
The record separator character for outputs, or the $\\endiskip.
Definition io.c:210
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2788
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:9215
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:335
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6470
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6424
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5319
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7472
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10494
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:519
VALUE rb_output_fs
The field separator character for outputs, or the $,.
Definition io.c:208
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:7355
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:404
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7362
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5837
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:211
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:2051
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:2045
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:3102
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1171
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:685
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:3800
#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:1001
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1518
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1997
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3568
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:4270
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3390
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:3742
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2953
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3253
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3372
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:2747
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1718
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h: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:1851
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1483
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:1693
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
Definition thread.c:5615
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:1466
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:3225
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1687
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1489
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2949
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:441
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:2030
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:500
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3471
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
Definition vm_eval.c:686
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
#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:4092
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:855
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:6556
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:869
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:915
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:839
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1127
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:6689
#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:1073
#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:1082
int rb_io_oflags_fmode(int oflags)
Converts an oflags (that rb_io_modestr_oflags() returns) to a fmode (that rb_io_mode_flags() returns)...
Definition io.c:6613
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:1679
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:7172
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:6838
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2991
#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:9462
#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:1746
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:1699
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:3065
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:6963
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:846
#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:5757
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:875
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:5945
struct rb_io_internal_buffer rb_io_buffer_t
Just another name of rb_io_buffer_t.
Definition io.h:125
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:944
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:2111
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:1054
#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
int rb_io_read_pending(rb_io_t *fptr)
Queries if the passed IO has any pending reads.
Definition io.c:1118
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:881
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3511
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1635
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:9328
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:892
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1106
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:1761
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:854
void rb_eof_error(void)
Utility function to raise rb_eEOFError.
Definition io.c:833
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1600
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7459
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1540
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:1081
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
Definition ractor.c:1141
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
Definition ractor.c:1129
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
Definition ractor.c:1117
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:2063
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition sprintf.c:209
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
Definition vm_eval.c:1417
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1372
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition off_t.h:55
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:450
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:80
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:205
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:508
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14703
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9114
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:90
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
Definition scan_args.h:59
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition scan_args.h:78
Scheduler APIs.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
Definition scheduler.c:471
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
Definition scheduler.c:1006
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:522
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:756
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
Definition scheduler.c:982
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:742
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:786
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
Definition scheduler.c:1018
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:479
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
Definition scheduler.c:994
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:484
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:762
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
Definition scheduler.c:1038
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:4578
@ 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:240
Definition win32.h:230
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
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:352
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:363
struct rb_io_encoding encs
Decomposed encoding flags.
Definition io.h:348
VALUE self
The IO's Ruby level counterpart.
Definition io.h:298
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:400
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:406
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:302
VALUE writeconv_pre_ecopts
Value of rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
Definition io.h:390
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:345
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:376
int fd
file descriptor.
Definition io.h:306
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:337
int lineno
number of lines read
Definition io.h:318
struct ccan_list_head blocking_operations
Threads that are performing a blocking operation without the GVL using this IO.
Definition io.h:131
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:372
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:359
rb_pid_t pid
child's pid (for pipes)
Definition io.h:314
int writeconv_pre_ecflags
Value of rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
Definition io.h:383
void(*) finalize(struct rb_io *, int)
finalize proc
Definition io.h:326
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
#define RBIMPL_WARNING_IGNORED(flag)
Suppresses a warning.
#define RBIMPL_WARNING_PUSH()
Pushes compiler warning state.
#define RBIMPL_WARNING_POP()
Pops compiler warning state.