Ruby 4.1.0dev (2026-10-14 revision d71692d49f30e60296bd57c932eb8877e83c3b4d)
io.c (d71692d49f30e60296bd57c932eb8877e83c3b4d)
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17#include "ruby/io/buffer.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <stddef.h>
22
23/* non-Linux poll may not work on all FDs */
24#if defined(HAVE_POLL)
25# if defined(__linux__)
26# define USE_POLL 1
27# endif
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29# define USE_POLL 1
30# endif
31#endif
32
33#ifndef USE_POLL
34# define USE_POLL 0
35#endif
36
37#undef free
38#define free(x) xfree(x)
39
40#ifdef __CYGWIN__
41#include <io.h>
42#endif
43
44#include <sys/types.h>
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
49#endif
50
51#if defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
53#endif
54
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun)
56# define USE_SETVBUF
57#endif
58
59#include <sys/types.h>
60#ifdef HAVE_SYS_IOCTL_H
61#include <sys/ioctl.h>
62#endif
63#if defined(HAVE_FCNTL_H)
64#include <fcntl.h>
65#elif defined(HAVE_SYS_FCNTL_H)
66#include <sys/fcntl.h>
67#endif
68
69#ifdef HAVE_SYS_TIME_H
70# include <sys/time.h>
71#endif
72
73#include <sys/stat.h>
74
75#if defined(HAVE_SYS_PARAM_H)
76# include <sys/param.h>
77#endif
78
79#if !defined NOFILE
80# define NOFILE 64
81#endif
82
83#ifdef HAVE_UNISTD_H
84#include <unistd.h>
85#endif
86
87#ifdef HAVE_SYSCALL_H
88#include <syscall.h>
89#elif defined HAVE_SYS_SYSCALL_H
90#include <sys/syscall.h>
91#endif
92
93#ifdef HAVE_SYS_UIO_H
94#include <sys/uio.h>
95#endif
96
97#ifdef HAVE_SYS_WAIT_H
98# include <sys/wait.h> /* for WNOHANG on BSD */
99#endif
100
101#ifdef HAVE_COPYFILE_H
102# include <copyfile.h>
103#endif
104
105#if defined __APPLE__
106# include <AvailabilityMacros.h>
107#endif
108
110#include "ccan/list/list.h"
111#include "dln.h"
112#include "encindex.h"
113#include "id.h"
114#include "internal.h"
115#include "internal/class.h"
116#include "internal/encoding.h"
117#include "internal/error.h"
118#include "internal/inits.h"
119#include "internal/io.h"
120#include "internal/numeric.h"
121#include "internal/object.h"
122#include "internal/process.h"
123#include "internal/thread.h"
124#include "internal/transcode.h"
125#include "internal/variable.h"
126#include "ruby/io.h"
127#include "ruby/io/buffer.h"
128#include "ruby/missing.h"
129#include "ruby/thread.h"
130#include "ruby/util.h"
131#include "ruby_atomic.h"
132#include "ruby/ractor.h"
133
134#if !USE_POLL
135# include "vm_core.h"
136#endif
137
138#include "builtin.h"
139
140#ifndef O_ACCMODE
141#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
142#endif
143
144#ifndef PIPE_BUF
145# ifdef _POSIX_PIPE_BUF
146# define PIPE_BUF _POSIX_PIPE_BUF
147# else
148# define PIPE_BUF 512 /* is this ok? */
149# endif
150#endif
151
152#ifndef EWOULDBLOCK
153# define EWOULDBLOCK EAGAIN
154#endif
155
156#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
157/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
158off_t __syscall(quad_t number, ...);
159#endif
160
161#define IO_RBUF_CAPA_MIN 8192
162#define IO_CBUF_CAPA_MIN (128*1024)
163#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
164#define IO_WBUF_CAPA_MIN 8192
165
166#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
167
168/* define system APIs */
169#ifdef _WIN32
170#undef open
171#define open rb_w32_uopen
172#undef rename
173#define rename(f, t) rb_w32_urename((f), (t))
174#include "win32/file.h"
175#endif
176
183
184static VALUE rb_eEAGAINWaitReadable;
185static VALUE rb_eEAGAINWaitWritable;
186#if EAGAIN != EWOULDBLOCK
187static VALUE rb_eEWOULDBLOCKWaitReadable;
188static VALUE rb_eEWOULDBLOCKWaitWritable;
189#endif
190static VALUE rb_eEINPROGRESSWaitWritable;
191static VALUE rb_eEINPROGRESSWaitReadable;
192
194static VALUE orig_stdout, orig_stderr;
195
197VALUE rb_rs;
200
201static VALUE argf;
202
203static ID id_write, id_read, id_flush, id_readpartial, id_set_encoding, id_fileno;
204static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
205static VALUE sym_textmode, sym_binmode, sym_autoclose;
206static VALUE sym_SET, sym_CUR, sym_END;
207static VALUE sym_wait_readable, sym_wait_writable;
208#ifdef SEEK_DATA
209static VALUE sym_DATA;
210#endif
211#ifdef SEEK_HOLE
212static VALUE sym_HOLE;
213#endif
214
215static VALUE prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path);
216
217VALUE
218rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
219{
220 return rb_thread_io_blocking_call(io, function, argument, events);
221}
222
223VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
224{
225 return rb_io_blocking_region_wait(io, function, argument, 0);
226}
227
228struct argf {
229 VALUE filename, current_file;
230 long last_lineno; /* $. */
231 long lineno;
232 VALUE argv;
233 VALUE inplace;
234 struct rb_io_encoding encs;
235 int8_t init_p, next_p, binmode;
236};
237
238
239#if defined(__APPLE__) && \
240 (!defined(MAC_OS_VERSION_27_0) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_27_0))
241
242# if __has_attribute(availability) && __has_warning("-Wunguarded-availability-new")
243
245RBIMPL_WARNING_IGNORED(-Wunguarded-availability-new)
246
247# ifdef HAVE_DUP3
248static inline int (*rb_dup3(void))(int, int, int) {return &dup3;}
249# define dup3 rb_dup3()
250# endif
251
252# ifdef HAVE_PIPE2
253static inline int (*rb_pipe2(void))(int [2], int) {return &pipe2;}
254# define pipe2 rb_pipe2()
255# endif
256
258
259# else /* __API_AVAILABLE macro does nothing on gcc */
260
261# ifdef HAVE_DUP3
262__attribute__((weak)) int dup3(int, int, int);
263# endif
264# ifdef HAVE_PIPE2
265__attribute__((weak)) int pipe2(int [2], int);
266# endif
267
268# endif
269#endif /* __APPLE__ && < MAC_OS_X_VERSION_27_0 */
270
271static rb_atomic_t max_file_descriptor = NOFILE;
272void
274{
275 rb_atomic_t afd = (rb_atomic_t)fd;
276 rb_atomic_t max_fd = max_file_descriptor;
277 int err;
278
279 if (fd < 0 || afd <= max_fd)
280 return;
281
282#if defined(HAVE_FCNTL) && defined(F_GETFL)
283 err = fcntl(fd, F_GETFL) == -1;
284#else
285 {
286 struct stat buf;
287 err = fstat(fd, &buf) != 0;
288 }
289#endif
290 if (err && errno == EBADF) {
291 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
292 }
293
294 while (max_fd < afd) {
295 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
296 }
297}
298
299void
300rb_maygvl_fd_fix_cloexec(int fd)
301{
302 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
303#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
304 int flags, flags2, ret;
305 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
306 if (flags == -1) {
307 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
308 }
309 if (fd <= 2)
310 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
311 else
312 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
313 if (flags != flags2) {
314 ret = fcntl(fd, F_SETFD, flags2);
315 if (ret != 0) {
316 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
317 }
318 }
319#endif
320}
321
322void
324{
325 rb_maygvl_fd_fix_cloexec(fd);
327}
328
329static inline bool
330io_again_p(int e)
331{
332 return (e == EWOULDBLOCK) || (e == EAGAIN);
333}
334
335int
336rb_cloexec_open(const char *pathname, int flags, mode_t mode)
337{
338 int ret;
339
340 static const int retry_interval = 0;
341 static const int retry_max_count = 10000;
342
343 int retry_count = 0;
344
345#ifdef O_CLOEXEC
346 flags |= O_CLOEXEC;
347#elif defined O_NOINHERIT
348 flags |= O_NOINHERIT;
349#endif
350
351 while ((ret = open(pathname, flags, mode)) == -1) {
352 int e = errno;
353 if (!io_again_p(e)) break;
354 if (retry_count++ >= retry_max_count) break;
355
356 sleep(retry_interval);
357 }
358
359 if (ret < 0) return ret;
360#ifdef O_CLOEXEC
361 if (ret > 2) return ret;
362#endif
363 rb_maygvl_fd_fix_cloexec(ret);
364 return ret;
365}
366
367int
369{
370 /* Don't allocate standard file descriptors: 0, 1, 2 */
371 return rb_cloexec_fcntl_dupfd(oldfd, 3);
372}
373
374int
375rb_cloexec_dup2(int oldfd, int newfd)
376{
377 int ret;
378
379 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
380 * rb_cloexec_dup2 succeeds as dup2. */
381 if (oldfd == newfd) {
382 ret = newfd;
383 }
384 else {
385#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
386# if defined(__APPLE__)
387# define try_dup3 (dup3 != NULL)
388# define abandon_dup3() true
389# else
390 static bool try_dup3 = true;
391# define abandon_dup3() (errno != ENOSYS || !!(try_dup3 = false))
392# endif
393 if (newfd <= 2) {
394 /* pass stdin, stdout and stderr to children */
395 }
396 else if (try_dup3) {
397 ret = dup3(oldfd, newfd, O_CLOEXEC);
398 /* dup3 is available since:
399 * - Linux 2.6.27, glibc 2.9
400 * - macOS 27.0
401 */
402 if (ret != -1)
403 return ret;
404 if (abandon_dup3()) return ret;
405 }
406#endif
407 ret = dup2(oldfd, newfd);
408 if (ret < 0) return ret;
409 }
410 rb_maygvl_fd_fix_cloexec(ret);
411 return ret;
412}
413
414static int
415rb_fd_set_nonblock(int fd)
416{
417#ifdef _WIN32
418 return rb_w32_set_nonblock(fd);
419#elif defined(F_GETFL)
420 int oflags = fcntl(fd, F_GETFL);
421
422 if (oflags == -1)
423 return -1;
424 if (oflags & O_NONBLOCK)
425 return 0;
426 oflags |= O_NONBLOCK;
427 return fcntl(fd, F_SETFL, oflags);
428#endif
429 return 0;
430}
431
432static inline int
433cloexec_pipe(int descriptors[2], int flags, bool force_cloexec)
434{
435 int result = -1;
436#ifdef HAVE_PIPE2
437# if defined(__APPLE__)
438# define try_pipe2 (pipe2 != NULL)
439# define abandon_pipe2() true
440# else
441 static bool try_pipe2 = true;
442# define abandon_pipe2() (errno != ENOSYS || !!(try_pipe2 = false))
443# endif
444 if (try_pipe2) {
445 result = pipe2(descriptors, O_CLOEXEC | flags);
446 if (result == 0) return result;
447 if (abandon_pipe2()) return result;
448 }
449#endif
450 if (result < 0 && (result = pipe(descriptors)) < 0)
451 return result;
452
453#ifdef __CYGWIN__
454 if (result == 0 && descriptors[1] == -1) {
455 close(descriptors[0]);
456 descriptors[0] = -1;
457 errno = ENFILE;
458 return -1;
459 }
460#endif
461
462 if (!force_cloexec) return result;
463
464 /* no pipe2 or fallenback to dup */
465 rb_maygvl_fd_fix_cloexec(descriptors[0]);
466 rb_maygvl_fd_fix_cloexec(descriptors[1]);
467
468#ifndef _WIN32
469 rb_fd_set_nonblock(descriptors[0]);
470 rb_fd_set_nonblock(descriptors[1]);
471#endif
472
473 return result;
474}
475
476int
477rb_cloexec_pipe(int descriptors[2])
478{
479 return cloexec_pipe(descriptors, O_NONBLOCK, true);
480}
481
482int
483rb_cloexec_fcntl_dupfd(int fd, int minfd)
484{
485 int ret;
486
487#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC)
488 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
489 if (ret > 2) return ret;
490#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
491 ret = fcntl(fd, F_DUPFD, minfd);
492#else
493 ret = dup(fd);
494 if (ret >= 0 && ret < minfd) {
495 const int prev_fd = ret;
496 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
497 close(prev_fd);
498 }
499 return ret;
500#endif
501 if (ret < 0) return ret;
502 rb_maygvl_fd_fix_cloexec(ret);
503 return ret;
504}
505
506#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
507#define ARGF argf_of(argf)
508#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
509
510#define GetWriteIO(io) rb_io_get_write_io(io)
511
512#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
513#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
514#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
515#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
516
517#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
518#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
519#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
520
521#if defined(_WIN32)
522#define WAIT_FD_IN_WIN32(fptr) \
523 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
524#else
525#define WAIT_FD_IN_WIN32(fptr)
526#endif
527
528#define READ_CHECK(fptr) do {\
529 if (!READ_DATA_PENDING(fptr)) {\
530 WAIT_FD_IN_WIN32(fptr);\
531 rb_io_check_closed(fptr);\
532 }\
533} while(0)
534
535#ifndef S_ISSOCK
536# ifdef _S_ISSOCK
537# define S_ISSOCK(m) _S_ISSOCK(m)
538# else
539# ifdef _S_IFSOCK
540# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
541# else
542# ifdef S_IFSOCK
543# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
544# endif
545# endif
546# endif
547#endif
548
549static int io_fflush(rb_io_t *);
550static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
551static void clear_readconv(rb_io_t *fptr);
552static void clear_codeconv(rb_io_t *fptr);
553
554#define FMODE_SIGNAL_ON_EPIPE (1<<17)
555
556#define fptr_signal_on_epipe(fptr) \
557 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
558
559#define fptr_set_signal_on_epipe(fptr, flag) \
560 ((flag) ? \
561 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
562 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
563
564extern ID ruby_static_id_signo;
565
566NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
567static void
568rb_sys_fail_on_write(rb_io_t *fptr)
569{
570 int e = errno;
571 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
572#if defined EPIPE
573 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
574 const VALUE sig =
575# if defined SIGPIPE
576 INT2FIX(SIGPIPE) - INT2FIX(0) +
577# endif
578 INT2FIX(0);
579 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
580 }
581#endif
582 rb_exc_raise(errinfo);
583}
584
585#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
586#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
587#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
588# define RUBY_CRLF_ENVIRONMENT 1
589#else
590# define RUBY_CRLF_ENVIRONMENT 0
591#endif
592
593#if RUBY_CRLF_ENVIRONMENT
594/* Windows */
595# define DEFAULT_TEXTMODE FMODE_TEXTMODE
596# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
597/*
598 * CRLF newline is set as default newline decorator.
599 * If only CRLF newline conversion is needed, we use binary IO process
600 * with OS's text mode for IO performance improvement.
601 * If encoding conversion is needed or a user sets text mode, we use encoding
602 * conversion IO process and universal newline decorator by default.
603 */
604#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
605#define WRITECONV_MASK ( \
606 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
607 ECONV_STATEFUL_DECORATOR_MASK|\
608 0)
609#define NEED_WRITECONV(fptr) ( \
610 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
611 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
612 0)
613#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
614
615#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
616 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
617 if (((fptr)->mode & FMODE_READABLE) &&\
618 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
619 setmode((fptr)->fd, O_BINARY);\
620 }\
621 else {\
622 setmode((fptr)->fd, O_TEXT);\
623 }\
624 }\
625} while(0)
626
627#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
628 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
629 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
630 }\
631} while(0)
632
633/*
634 * IO unread with taking care of removed '\r' in text mode.
635 */
636static void
637io_unread(rb_io_t *fptr, bool discard_rbuf)
638{
639 rb_off_t r, pos;
640 ssize_t read_size;
641 long i;
642 long newlines = 0;
643 long extra_max;
644 char *p;
645 char *buf;
646
647 rb_io_check_closed(fptr);
648 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
649 return;
650 }
651
652 errno = 0;
653 if (!rb_w32_fd_is_text(fptr->fd)) {
654 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
655 if (r < 0 && errno) {
656 if (errno == ESPIPE)
657 fptr->mode |= FMODE_DUPLEX;
658 if (!discard_rbuf) return;
659 }
660
661 goto end;
662 }
663
664 pos = lseek(fptr->fd, 0, SEEK_CUR);
665 if (pos < 0 && errno) {
666 if (errno == ESPIPE)
667 fptr->mode |= FMODE_DUPLEX;
668 if (!discard_rbuf) goto end;
669 }
670
671 /* add extra offset for removed '\r' in rbuf */
672 extra_max = (long)(pos - fptr->rbuf.len);
673 p = fptr->rbuf.ptr + fptr->rbuf.off;
674
675 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
676 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
677 newlines++;
678 }
679
680 for (i = 0; i < fptr->rbuf.len; i++) {
681 if (*p == '\n') newlines++;
682 if (extra_max == newlines) break;
683 p++;
684 }
685
686 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
687 while (newlines >= 0) {
688 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
689 if (newlines == 0) break;
690 if (r < 0) {
691 newlines--;
692 continue;
693 }
694 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
695 if (read_size < 0) {
696 int e = errno;
697 free(buf);
698 rb_syserr_fail_path(e, fptr->pathv);
699 }
700 if (read_size == fptr->rbuf.len) {
701 lseek(fptr->fd, r, SEEK_SET);
702 break;
703 }
704 else {
705 newlines--;
706 }
707 }
708 free(buf);
709 end:
710 fptr->rbuf.off = 0;
711 fptr->rbuf.len = 0;
712 clear_codeconv(fptr);
713 return;
714}
715
716/*
717 * We use io_seek to back cursor position when changing mode from text to binary,
718 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
719 * conversion for working properly with mode change.
720 *
721 * Return previous translation mode.
722 */
723static inline int
724set_binary_mode_with_seek_cur(rb_io_t *fptr)
725{
726 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
727
728 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
729 return setmode(fptr->fd, O_BINARY);
730 }
731 flush_before_seek(fptr, false);
732 return setmode(fptr->fd, O_BINARY);
733}
734#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
735
736#else
737/* Unix */
738# define DEFAULT_TEXTMODE 0
739#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
740#define NEED_WRITECONV(fptr) ( \
741 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
742 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
743 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
744 0)
745#define SET_BINARY_MODE(fptr) (void)(fptr)
746#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
747#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
748#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
749#endif
750
751#if !defined HAVE_SHUTDOWN && !defined shutdown
752#define shutdown(a,b) 0
753#endif
754
755#if defined(_WIN32)
756#define is_socket(fd, path) rb_w32_is_socket(fd)
757#elif !defined(S_ISSOCK)
758#define is_socket(fd, path) 0
759#else
760static int
761is_socket(int fd, VALUE path)
762{
763 struct stat sbuf;
764 if (fstat(fd, &sbuf) < 0)
765 rb_sys_fail_path(path);
766 return S_ISSOCK(sbuf.st_mode);
767}
768#endif
769
770static const char closed_stream[] = "closed stream";
771
772static void
773io_fd_check_closed(int fd)
774{
775 if (fd < 0) {
776 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
777 rb_raise(rb_eIOError, closed_stream);
778 }
779}
780
781void
782rb_eof_error(void)
783{
784 rb_raise(rb_eEOFError, "end of file reached");
785}
786
787VALUE
789{
790 rb_check_frozen(io);
791 return io;
792}
793
794void
796{
797 if (!fptr) {
798 rb_raise(rb_eIOError, "uninitialized stream");
799 }
800}
801
802void
804{
806 io_fd_check_closed(fptr->fd);
807}
808
809static rb_io_t *
810rb_io_get_fptr(VALUE io)
811{
812 rb_io_t *fptr = RFILE(io)->fptr;
814 return fptr;
815}
816
817VALUE
819{
820 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
821}
822
823VALUE
825{
826 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
827}
828
829VALUE
831{
832 VALUE write_io;
833 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
834 if (write_io) {
835 return write_io;
836 }
837 return io;
838}
839
840VALUE
842{
843 VALUE write_io;
844 rb_io_t *fptr = rb_io_get_fptr(io);
845 if (!RTEST(w)) {
846 w = 0;
847 }
848 else {
849 GetWriteIO(w);
850 }
851 write_io = fptr->tied_io_for_writing;
852 fptr->tied_io_for_writing = w;
853 return write_io ? write_io : Qnil;
854}
855
856/*
857 * call-seq:
858 * timeout -> duration or nil
859 *
860 * Get the internal timeout duration or nil if it was not set.
861 *
862 */
863VALUE
865{
866 rb_io_t *fptr = rb_io_get_fptr(self);
867
868 return fptr->timeout;
869}
870
871/*
872 * call-seq:
873 * timeout = duration -> duration
874 * timeout = nil -> nil
875 *
876 * Sets the internal timeout to the specified duration or nil. The timeout
877 * applies to all blocking operations where possible.
878 *
879 * When the operation performs longer than the timeout set, IO::TimeoutError
880 * is raised.
881 *
882 * This affects the following methods (but is not limited to): #gets, #puts,
883 * #read, #write, #wait_readable and #wait_writable. This also affects
884 * blocking socket operations like Socket#accept and Socket#connect.
885 *
886 * Some operations like File#open and IO#close are not affected by the
887 * timeout. A timeout during a write operation may leave the IO in an
888 * inconsistent state, e.g. data was partially written. Generally speaking, a
889 * timeout is a last ditch effort to prevent an application from hanging on
890 * slow I/O operations, such as those that occur during a slowloris attack.
891 */
892VALUE
894{
895 // Validate it:
896 if (RTEST(timeout)) {
897 rb_time_interval(timeout);
898 }
899
900 rb_io_t *fptr = rb_io_get_fptr(self);
901
902 RB_OBJ_WRITE(self, &fptr->timeout, timeout);
903
904 return self;
905}
906
907/*
908 * call-seq:
909 * IO.try_convert(object) -> new_io or nil
910 *
911 * Attempts to convert +object+ into an \IO object via method +to_io+;
912 * returns the new \IO object if successful, or +nil+ otherwise:
913 *
914 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
915 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
916 * IO.try_convert('STDOUT') # => nil
917 *
918 */
919static VALUE
920rb_io_s_try_convert(VALUE dummy, VALUE io)
921{
922 return rb_io_check_io(io);
923}
924
925#if !RUBY_CRLF_ENVIRONMENT
926static void
927io_unread(rb_io_t *fptr, bool discard_rbuf)
928{
929 rb_off_t r;
930 rb_io_check_closed(fptr);
931 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
932 return;
933 /* xxx: target position may be negative if buffer is filled by ungetc */
934 errno = 0;
935 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
936 if (r < 0 && errno) {
937 if (errno == ESPIPE)
938 fptr->mode |= FMODE_DUPLEX;
939 if (!discard_rbuf) return;
940 }
941 fptr->rbuf.off = 0;
942 fptr->rbuf.len = 0;
943 clear_codeconv(fptr);
944 return;
945}
946#endif
947
948static rb_encoding *io_input_encoding(rb_io_t *fptr);
949
950static void
951io_ungetbyte(VALUE str, rb_io_t *fptr)
952{
953 rb_len_t len = RSTRING_LEN(str);
954
955 if (fptr->rbuf.ptr == NULL) {
956 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
957 fptr->rbuf.off = 0;
958 fptr->rbuf.len = 0;
959#if SIZEOF_RB_LEN_T > SIZEOF_INT
960 if (len > INT_MAX)
961 rb_raise(rb_eIOError, "ungetbyte failed");
962#endif
963 if (len > min_capa)
964 fptr->rbuf.capa = (int)len;
965 else
966 fptr->rbuf.capa = min_capa;
967 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
968 }
969 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
970 rb_raise(rb_eIOError, "ungetbyte failed");
971 }
972 if (fptr->rbuf.off < len) {
973 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
974 fptr->rbuf.ptr+fptr->rbuf.off,
975 char, fptr->rbuf.len);
976 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
977 }
978 fptr->rbuf.off-=(int)len;
979 fptr->rbuf.len+=(int)len;
980 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
981}
982
983static void
984io_restore_read_buffer(VALUE str, rb_io_t *fptr)
985{
986 rb_len_t len = RSTRING_LEN(str);
987
988 if (len > INT_MAX - fptr->rbuf.len) {
989 rb_raise(rb_eIOError, "read buffer too large");
990 }
991 if (fptr->rbuf.ptr == NULL || fptr->rbuf.capa >= len + fptr->rbuf.len) {
992 io_ungetbyte(str, fptr);
993 }
994 else {
995 int pending = fptr->rbuf.len;
996 int capa = (int)len + pending;
997 char *ptr = ALLOC_N(char, capa);
998
999 MEMMOVE(ptr, RSTRING_PTR(str), char, len);
1000 MEMMOVE(ptr + len, fptr->rbuf.ptr + fptr->rbuf.off, char, pending);
1001 ruby_xfree(fptr->rbuf.ptr);
1002 fptr->rbuf.ptr = ptr;
1003 fptr->rbuf.off = 0;
1004 fptr->rbuf.len = capa;
1005 fptr->rbuf.capa = capa;
1006 }
1007}
1008
1009static rb_io_t *
1010flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
1011{
1012 if (io_fflush(fptr) < 0)
1013 rb_sys_fail_on_write(fptr);
1014 io_unread(fptr, discard_rbuf);
1015 errno = 0;
1016 return fptr;
1017}
1018
1019#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
1020#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1021
1022#ifndef SEEK_CUR
1023# define SEEK_SET 0
1024# define SEEK_CUR 1
1025# define SEEK_END 2
1026#endif
1027
1028void
1030{
1031 rb_io_check_closed(fptr);
1032 if (!(fptr->mode & FMODE_READABLE)) {
1033 rb_raise(rb_eIOError, "not opened for reading");
1034 }
1035 if (fptr->wbuf.len) {
1036 if (io_fflush(fptr) < 0)
1037 rb_sys_fail_on_write(fptr);
1038 }
1039 if (fptr->tied_io_for_writing) {
1040 rb_io_t *wfptr;
1041 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1042 if (io_fflush(wfptr) < 0)
1043 rb_sys_fail_on_write(wfptr);
1044 }
1045}
1046
1047void
1049{
1051 if (READ_CHAR_PENDING(fptr)) {
1052 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1053 }
1054}
1055
1056void
1061
1062static rb_encoding*
1063io_read_encoding(rb_io_t *fptr)
1064{
1065 if (fptr->encs.enc) {
1066 return fptr->encs.enc;
1067 }
1068 return rb_default_external_encoding();
1069}
1070
1071static rb_encoding*
1072io_input_encoding(rb_io_t *fptr)
1073{
1074 if (fptr->encs.enc2) {
1075 return fptr->encs.enc2;
1076 }
1077 return io_read_encoding(fptr);
1078}
1079
1080void
1082{
1083 rb_io_check_closed(fptr);
1084 if (!(fptr->mode & FMODE_WRITABLE)) {
1085 rb_raise(rb_eIOError, "not opened for writing");
1086 }
1087 if (fptr->rbuf.len) {
1088 io_unread(fptr, true);
1089 }
1090}
1091
1092int
1093rb_io_read_pending(rb_io_t *fptr)
1094{
1095 /* This function is used for bytes and chars. Confusing. */
1096 if (READ_CHAR_PENDING(fptr))
1097 return 1; /* should raise? */
1098 return READ_DATA_PENDING(fptr);
1099}
1100
1101void
1103{
1104 if (!READ_DATA_PENDING(fptr)) {
1105 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1106 }
1107 return;
1108}
1109
1110int
1111rb_gc_for_fd(int err)
1112{
1113 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1114 rb_gc();
1115 return 1;
1116 }
1117 return 0;
1118}
1119
1120/* try `expr` upto twice while it returns false and `errno`
1121 * is to GC. Each `errno`s are available as `first_errno` and
1122 * `retried_errno` respectively */
1123#define TRY_WITH_GC(expr) \
1124 for (int first_errno, retried_errno = 0, retried = 0; \
1125 (!retried && \
1126 !(expr) && \
1127 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1128 (retried_errno = errno, 1)); \
1129 (void)retried_errno, retried = 1)
1130
1131static int
1132ruby_dup(int orig)
1133{
1134 int fd = -1;
1135
1136 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1137 rb_syserr_fail(first_errno, 0);
1138 }
1139 rb_update_max_fd(fd);
1140 return fd;
1141}
1142
1143static VALUE
1144io_alloc(VALUE klass)
1145{
1146 UNPROTECTED_NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile));
1147
1148 io->fptr = 0;
1149
1150 return (VALUE)io;
1151}
1152
1153#ifndef S_ISREG
1154# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1155#endif
1156
1158 VALUE th;
1159 rb_io_t *fptr;
1160 int nonblock;
1161 int fd;
1162
1163 void *buf;
1164 size_t capa;
1165 struct timeval *timeout;
1166};
1167
1169 VALUE th;
1170 rb_io_t *fptr;
1171 int nonblock;
1172 int fd;
1173
1174 const void *buf;
1175 size_t capa;
1176 struct timeval *timeout;
1177};
1178
1179#ifdef HAVE_WRITEV
1180struct io_internal_writev_struct {
1181 VALUE th;
1182 rb_io_t *fptr;
1183 int nonblock;
1184 int fd;
1185
1186 int iovcnt;
1187 const struct iovec *iov;
1188 struct timeval *timeout;
1189};
1190#endif
1191
1192static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1193
1199static inline int
1200io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1201{
1202 if (!timeout && rb_thread_mn_schedulable(thread)) {
1203 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1204 return -1;
1205 }
1206
1207 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1208
1209 if (ready > 0) {
1210 return ready;
1211 }
1212 else if (ready == 0) {
1213 errno = ETIMEDOUT;
1214 return -1;
1215 }
1216
1217 // If there was an error BEFORE we started waiting, return it:
1218 if (error) {
1219 errno = error;
1220 return -1;
1221 }
1222 else {
1223 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1224 return ready;
1225 }
1226}
1227
1228static VALUE
1229internal_read_func(void *ptr)
1230{
1231 struct io_internal_read_struct *iis = ptr;
1232 ssize_t result;
1233
1234 if (iis->timeout && !iis->nonblock) {
1235 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1236 return -1;
1237 }
1238 }
1239
1240 retry:
1241 result = read(iis->fd, iis->buf, iis->capa);
1242
1243 if (result < 0 && !iis->nonblock) {
1244 if (io_again_p(errno)) {
1245 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1246 return -1;
1247 }
1248 else {
1249 goto retry;
1250 }
1251 }
1252 }
1253
1254 return result;
1255}
1256
1257#if defined __APPLE__
1258# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1259#else
1260# define do_write_retry(code) result = code
1261#endif
1262
1263static VALUE
1264internal_write_func(void *ptr)
1265{
1266 struct io_internal_write_struct *iis = ptr;
1267 ssize_t result;
1268
1269 if (iis->timeout && !iis->nonblock) {
1270 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1271 return -1;
1272 }
1273 }
1274
1275 retry:
1276 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1277
1278 if (result < 0 && !iis->nonblock) {
1279 int e = errno;
1280 if (io_again_p(e)) {
1281 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1282 return -1;
1283 }
1284 else {
1285 goto retry;
1286 }
1287 }
1288 }
1289
1290 return result;
1291}
1292
1293#ifdef HAVE_WRITEV
1294static VALUE
1295internal_writev_func(void *ptr)
1296{
1297 struct io_internal_writev_struct *iis = ptr;
1298 ssize_t result;
1299
1300 if (iis->timeout && !iis->nonblock) {
1301 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1302 return -1;
1303 }
1304 }
1305
1306 retry:
1307 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1308
1309 if (result < 0 && !iis->nonblock) {
1310 if (io_again_p(errno)) {
1311 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1312 return -1;
1313 }
1314 else {
1315 goto retry;
1316 }
1317 }
1318 }
1319
1320 return result;
1321}
1322#endif
1323
1324static ssize_t
1325rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1326{
1327 rb_thread_t *th = GET_THREAD();
1329 if (scheduler != Qnil) {
1330 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count);
1331
1332 if (!UNDEF_P(result)) {
1334 }
1335 }
1336
1337 struct io_internal_read_struct iis = {
1338 .th = th->self,
1339 .fptr = fptr,
1340 .nonblock = 0,
1341 .fd = fptr->fd,
1342
1343 .buf = buf,
1344 .capa = count,
1345 .timeout = NULL,
1346 };
1347
1348 struct timeval timeout_storage;
1349
1350 if (fptr->timeout != Qnil) {
1351 timeout_storage = rb_time_interval(fptr->timeout);
1352 iis.timeout = &timeout_storage;
1353 }
1354
1355 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1356}
1357
1358static ssize_t
1359rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1360{
1361 rb_thread_t *th = GET_THREAD();
1363 if (scheduler != Qnil) {
1364 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count);
1365
1366 if (!UNDEF_P(result)) {
1368 }
1369 }
1370
1371 struct io_internal_write_struct iis = {
1372 .th = th->self,
1373 .fptr = fptr,
1374 .nonblock = 0,
1375 .fd = fptr->fd,
1376
1377 .buf = buf,
1378 .capa = count,
1379 .timeout = NULL
1380 };
1381
1382 struct timeval timeout_storage;
1383
1384 if (fptr->timeout != Qnil) {
1385 timeout_storage = rb_time_interval(fptr->timeout);
1386 iis.timeout = &timeout_storage;
1387 }
1388
1389 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1390}
1391
1392#ifdef HAVE_WRITEV
1393static ssize_t
1394rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1395{
1396 if (!iovcnt) return 0;
1397
1398 rb_thread_t *th = GET_THREAD();
1399
1401 if (scheduler != Qnil) {
1402 // This path assumes at least one `iov`:
1403 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len);
1404
1405 if (!UNDEF_P(result)) {
1407 }
1408 }
1409
1410 struct io_internal_writev_struct iis = {
1411 .th = th->self,
1412 .fptr = fptr,
1413 .nonblock = 0,
1414 .fd = fptr->fd,
1415
1416 .iov = iov,
1417 .iovcnt = iovcnt,
1418 .timeout = NULL
1419 };
1420
1421 struct timeval timeout_storage;
1422
1423 if (fptr->timeout != Qnil) {
1424 timeout_storage = rb_time_interval(fptr->timeout);
1425 iis.timeout = &timeout_storage;
1426 }
1427
1428 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1429}
1430#endif
1431
1432static VALUE
1433io_flush_buffer_sync(void *arg)
1434{
1435 rb_io_t *fptr = arg;
1436 rb_len_t l = fptr->wbuf.len;
1437 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1438
1439 if (fptr->wbuf.len <= r) {
1440 fptr->wbuf.off = 0;
1441 fptr->wbuf.len = 0;
1442 return 0;
1443 }
1444
1445 if (0 <= r) {
1446 fptr->wbuf.off += (int)r;
1447 fptr->wbuf.len -= (int)r;
1448 errno = EAGAIN;
1449 }
1450
1451 return (VALUE)-1;
1452}
1453
1454static inline VALUE
1455io_flush_buffer_fiber_scheduler(VALUE scheduler, rb_io_t *fptr)
1456{
1457 VALUE ret = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, fptr->wbuf.ptr+fptr->wbuf.off, fptr->wbuf.len);
1458 if (!UNDEF_P(ret)) {
1459 ssize_t result = rb_fiber_scheduler_io_result_apply(ret);
1460 if (result > 0) {
1461 fptr->wbuf.off += result;
1462 fptr->wbuf.len -= result;
1463 }
1464 return result >= 0 ? (VALUE)0 : (VALUE)-1;
1465 }
1466 return ret;
1467}
1468
1469static VALUE
1470io_flush_buffer_async(VALUE arg)
1471{
1472 rb_io_t *fptr = (rb_io_t *)arg;
1473
1474 VALUE scheduler = rb_fiber_scheduler_current();
1475 if (scheduler != Qnil) {
1476 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1477 if (!UNDEF_P(result)) {
1478 return result;
1479 }
1480 }
1481
1482 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1483}
1484
1485static inline int
1486io_flush_buffer(rb_io_t *fptr)
1487{
1488 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1489 return (int)io_flush_buffer_async((VALUE)fptr);
1490 }
1491 else {
1492 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1493 }
1494}
1495
1496static int
1497io_fflush(rb_io_t *fptr)
1498{
1499 rb_io_check_closed(fptr);
1500
1501 if (fptr->wbuf.len == 0)
1502 return 0;
1503
1504 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1505 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1506 return -1;
1507
1508 rb_io_check_closed(fptr);
1509 }
1510
1511 return 0;
1512}
1513
1514VALUE
1515rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1516{
1517 rb_thread_t *th = GET_THREAD();
1519
1520 if (scheduler != Qnil) {
1521 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1522 }
1523
1524 rb_io_t * fptr = NULL;
1525 RB_IO_POINTER(io, fptr);
1526
1527 struct timeval tv_storage;
1528 struct timeval *tv = NULL;
1529
1530 if (NIL_OR_UNDEF_P(timeout)) {
1531 timeout = fptr->timeout;
1532 }
1533
1534 if (timeout != Qnil) {
1535 tv_storage = rb_time_interval(timeout);
1536 tv = &tv_storage;
1537 }
1538
1539 int ready = rb_thread_io_wait(th, fptr, RB_NUM2INT(events), tv);
1540
1541 if (ready < 0) {
1542 rb_sys_fail(0);
1543 }
1544
1545 // Not sure if this is necessary:
1546 rb_io_check_closed(fptr);
1547
1548 if (ready) {
1549 return RB_INT2NUM(ready);
1550 }
1551 else {
1552 return Qfalse;
1553 }
1554}
1555
1556static VALUE
1557io_from_fd(int fd)
1558{
1559 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1560}
1561
1562static int
1563io_wait_for_single_fd(int fd, int events, struct timeval *timeout, rb_thread_t *th, VALUE scheduler)
1564{
1565 if (scheduler != Qnil) {
1566 return RTEST(
1567 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1568 );
1569 }
1570
1571 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1572}
1573
1574int
1576{
1577 io_fd_check_closed(f);
1578
1579 rb_thread_t *th = GET_THREAD();
1581
1582 switch (errno) {
1583 case EINTR:
1584#if defined(ERESTART)
1585 case ERESTART:
1586#endif
1588 return TRUE;
1589
1590 case EAGAIN:
1591#if EWOULDBLOCK != EAGAIN
1592 case EWOULDBLOCK:
1593#endif
1594 if (scheduler != Qnil) {
1595 return RTEST(
1596 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1597 );
1598 }
1599 else {
1600 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL, th, scheduler);
1601 }
1602 return TRUE;
1603
1604 default:
1605 return FALSE;
1606 }
1607}
1608
1609int
1611{
1612 io_fd_check_closed(f);
1613
1614 rb_thread_t *th = GET_THREAD();
1616
1617 switch (errno) {
1618 case EINTR:
1619#if defined(ERESTART)
1620 case ERESTART:
1621#endif
1622 /*
1623 * In old Linux, several special files under /proc and /sys don't handle
1624 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1625 * Otherwise, we face nasty hang up. Sigh.
1626 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1627 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1628 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1629 * Then rb_thread_check_ints() is enough.
1630 */
1632 return TRUE;
1633
1634 case EAGAIN:
1635#if EWOULDBLOCK != EAGAIN
1636 case EWOULDBLOCK:
1637#endif
1638 if (scheduler != Qnil) {
1639 return RTEST(
1640 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1641 );
1642 }
1643 else {
1644 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL, th, scheduler);
1645 }
1646 return TRUE;
1647
1648 default:
1649 return FALSE;
1650 }
1651}
1652
1653int
1654rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1655{
1656 rb_thread_t *th = GET_THREAD();
1658 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1659}
1660
1661int
1663{
1664 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1665}
1666
1667int
1669{
1670 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1671}
1672
1673VALUE
1674rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1675{
1676 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1677 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1678 // instead relies on `read(-1) -> -1` which causes this code path. We then
1679 // check here whether the IO was in fact closed. Probably it's better to
1680 // check that `fptr->fd != -1` before using it in syscall.
1681 rb_io_check_closed(RFILE(io)->fptr);
1682
1683 switch (error) {
1684 // In old Linux, several special files under /proc and /sys don't handle
1685 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1686 // Otherwise, we face nasty hang up. Sigh.
1687 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1688 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1689 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1690 // Then rb_thread_check_ints() is enough.
1691 case EINTR:
1692#if defined(ERESTART)
1693 case ERESTART:
1694#endif
1695 // We might have pending interrupts since the previous syscall was interrupted:
1697
1698 // The operation was interrupted, so retry it immediately:
1699 return events;
1700
1701 case EAGAIN:
1702#if EWOULDBLOCK != EAGAIN
1703 case EWOULDBLOCK:
1704#endif
1705 {
1706 // The operation would block, so wait for the specified events:
1707 VALUE result = rb_io_wait(io, events, timeout);
1708 // The scheduler may change errno while waiting. Preserve the original
1709 // error in case no events are ready and the caller reports the failure.
1710 errno = error;
1711 return result;
1712 }
1713
1714 default:
1715 // Non-specific error, no event is ready:
1716 return Qnil;
1717 }
1718}
1719
1720int
1722{
1723 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1724
1725 if (RTEST(result)) {
1726 return RB_NUM2INT(result);
1727 }
1728 else if (result == RUBY_Qfalse) {
1729 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1730 }
1731
1732 return 0;
1733}
1734
1735int
1737{
1738 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1739
1740 if (RTEST(result)) {
1741 return RB_NUM2INT(result);
1742 }
1743 else if (result == RUBY_Qfalse) {
1744 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1745 }
1746
1747 return 0;
1748}
1749
1750static void
1751make_writeconv(rb_io_t *fptr)
1752{
1753 if (!fptr->writeconv_initialized) {
1754 const char *senc, *denc;
1755 rb_encoding *enc;
1756 int ecflags;
1757 VALUE ecopts;
1758
1759 fptr->writeconv_initialized = 1;
1760
1761 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1762 ecopts = fptr->encs.ecopts;
1763
1764 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1765 /* no encoding conversion */
1766 fptr->writeconv_pre_ecflags = 0;
1767 fptr->writeconv_pre_ecopts = Qnil;
1768 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1769 if (!fptr->writeconv)
1770 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1772 }
1773 else {
1774 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1775 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1776 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1777 /* single conversion */
1778 fptr->writeconv_pre_ecflags = ecflags;
1779 fptr->writeconv_pre_ecopts = ecopts;
1780 fptr->writeconv = NULL;
1782 }
1783 else {
1784 /* double conversion */
1785 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1786 fptr->writeconv_pre_ecopts = ecopts;
1787 if (senc) {
1788 denc = rb_enc_name(enc);
1789 fptr->writeconv_asciicompat = rb_str_new2(senc);
1790 }
1791 else {
1792 senc = denc = "";
1793 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1794 }
1796 ecopts = fptr->encs.ecopts;
1797 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1798 if (!fptr->writeconv)
1799 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1800 }
1801 }
1802 }
1803}
1804
1805/* writing functions */
1807 rb_io_t *fptr;
1808 const char *ptr;
1809 rb_len_t length;
1810};
1811
1813 VALUE io;
1814 VALUE str;
1815 int nosync;
1816};
1817
1818#ifdef HAVE_WRITEV
1819static ssize_t
1820io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, rb_len_t length)
1821{
1822 if (fptr->wbuf.len) {
1823 struct iovec iov[2];
1824
1825 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1826 iov[0].iov_len = fptr->wbuf.len;
1827 iov[1].iov_base = (void*)ptr;
1828 iov[1].iov_len = length;
1829
1830 ssize_t result = rb_writev_internal(fptr, iov, 2);
1831
1832 if (result < 0)
1833 return result;
1834
1835 if (result >= fptr->wbuf.len) {
1836 // We wrote more than the internal buffer:
1837 result -= fptr->wbuf.len;
1838 fptr->wbuf.off = 0;
1839 fptr->wbuf.len = 0;
1840 }
1841 else {
1842 // We only wrote less data than the internal buffer:
1843 fptr->wbuf.off += (int)result;
1844 fptr->wbuf.len -= (int)result;
1845
1846 result = 0;
1847 }
1848
1849 return result;
1850 }
1851 else {
1852 return rb_io_write_memory(fptr, ptr, length);
1853 }
1854}
1855#else
1856static ssize_t
1857io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, rb_len_t length)
1858{
1859 rb_len_t remaining = length;
1860
1861 if (fptr->wbuf.len) {
1862 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1863 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1864 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1865 fptr->wbuf.off = 0;
1866 }
1867
1868 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1869 fptr->wbuf.len += (int)length;
1870
1871 // We copied the entire incoming data to the internal buffer:
1872 remaining = 0;
1873 }
1874
1875 // Flush the internal buffer:
1876 if (io_fflush(fptr) < 0) {
1877 return -1;
1878 }
1879
1880 // If all the data was buffered, we are done:
1881 if (remaining == 0) {
1882 return length;
1883 }
1884 }
1885
1886 // Otherwise, we should write the data directly:
1887 return rb_io_write_memory(fptr, ptr, length);
1888}
1889#endif
1890
1891static VALUE
1892io_binwrite_string(VALUE arg)
1893{
1894 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1895
1896 const char *ptr = p->ptr;
1897 size_t remaining = p->length;
1898
1899 while (remaining) {
1900 // Write as much as possible:
1901 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1902
1903 if (result == 0) {
1904 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1905 // should try again immediately.
1906 }
1907 else if (result > 0) {
1908 if ((size_t)result == remaining) break;
1909 ptr += result;
1910 remaining -= result;
1911 }
1912 // Wait for it to become writable:
1913 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1914 rb_io_check_closed(p->fptr);
1915 }
1916 else {
1917 // The error was unrelated to waiting for it to become writable, so we fail:
1918 return -1;
1919 }
1920 }
1921
1922 return p->length;
1923}
1924
1925inline static void
1926io_allocate_write_buffer(rb_io_t *fptr, int sync)
1927{
1928 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1929 fptr->wbuf.off = 0;
1930 fptr->wbuf.len = 0;
1931 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1932 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1933 }
1934
1935 if (NIL_P(fptr->write_lock)) {
1936 fptr->write_lock = rb_mutex_new();
1937 rb_mutex_allow_trap(fptr->write_lock, 1);
1938 }
1939}
1940
1941static inline int
1942io_binwrite_requires_flush_write(rb_io_t *fptr, rb_len_t len, int nosync)
1943{
1944 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1945 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1946 return 1;
1947
1948 // If the amount of data we want to write exceeds the internal buffer:
1949 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1950 return 1;
1951
1952 // Otherwise, we can append to the internal buffer:
1953 return 0;
1954}
1955
1956static rb_len_t
1957io_binwrite(const char *ptr, rb_len_t len, rb_io_t *fptr, int nosync)
1958{
1959 if (len <= 0) return len;
1960
1961 // Don't write anything if current thread has a pending interrupt:
1963
1964 io_allocate_write_buffer(fptr, !nosync);
1965
1966 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1967 struct binwrite_arg arg;
1968
1969 arg.fptr = fptr;
1970 arg.ptr = ptr;
1971 arg.length = len;
1972
1973 if (!NIL_P(fptr->write_lock)) {
1974 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1975 }
1976 else {
1977 return io_binwrite_string((VALUE)&arg);
1978 }
1979 }
1980 else {
1981 if (fptr->wbuf.off) {
1982 if (fptr->wbuf.len)
1983 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1984 fptr->wbuf.off = 0;
1985 }
1986
1987 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1988 fptr->wbuf.len += (int)len;
1989
1990 return len;
1991 }
1992}
1993
1994# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1995 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1996
1997#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1998 MODE_BTMODE(d, e, f) : \
1999 MODE_BTMODE(a, b, c))
2000
2001static VALUE
2002do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
2003{
2004 if (NEED_WRITECONV(fptr)) {
2005 VALUE common_encoding = Qnil;
2006 SET_BINARY_MODE(fptr);
2007
2008 make_writeconv(fptr);
2009
2010 if (fptr->writeconv) {
2011#define fmode (fptr->mode)
2012 if (!NIL_P(fptr->writeconv_asciicompat))
2013 common_encoding = fptr->writeconv_asciicompat;
2014 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
2015 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2016 rb_enc_name(rb_enc_get(str)));
2017 }
2018#undef fmode
2019 }
2020 else {
2021 if (fptr->encs.enc2)
2022 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
2023 else if (fptr->encs.enc != rb_ascii8bit_encoding())
2024 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
2025 }
2026
2027 if (!NIL_P(common_encoding)) {
2028 str = rb_str_encode(str, common_encoding,
2030 *converted = 1;
2031 }
2032
2033 if (fptr->writeconv) {
2035 *converted = 1;
2036 }
2037 }
2038#if RUBY_CRLF_ENVIRONMENT
2039#define fmode (fptr->mode)
2040 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2041 if ((fptr->mode & FMODE_READABLE) &&
2043 setmode(fptr->fd, O_BINARY);
2044 }
2045 else {
2046 setmode(fptr->fd, O_TEXT);
2047 }
2048 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2049 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2050 rb_enc_name(rb_enc_get(str)));
2051 }
2052 }
2053#undef fmode
2054#endif
2055 return str;
2056}
2057
2058static rb_len_t
2059io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
2060{
2061 int converted = 0;
2062 VALUE tmp;
2063 rb_len_t n, len;
2064 const char *ptr;
2065
2066#ifdef _WIN32
2067 if (fptr->mode & FMODE_TTY) {
2068 if (rb_w32_write_console(str, fptr->fd) > 0) return RSTRING_LEN(str);
2069 }
2070#endif
2071
2072 str = do_writeconv(str, fptr, &converted);
2073 if (converted)
2074 OBJ_FREEZE(str);
2075
2076 tmp = rb_str_no_gvl_safe_acquire(str);
2077 RSTRING_GETMEM(tmp, ptr, len);
2078 n = io_binwrite(ptr, len, fptr, nosync);
2080
2081 return n;
2082}
2083
2084ssize_t
2085rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2086{
2087 rb_io_t *fptr;
2088
2089 GetOpenFile(io, fptr);
2091 return (ssize_t)io_binwrite(buf, (rb_len_t)size, fptr, 0);
2092}
2093
2094static VALUE
2095io_write(VALUE io, VALUE str, int nosync)
2096{
2097 rb_io_t *fptr;
2098 rb_len_t n;
2099 VALUE tmp;
2100
2101 io = GetWriteIO(io);
2102 str = rb_obj_as_string(str);
2103 tmp = rb_io_check_io(io);
2104
2105 if (NIL_P(tmp)) {
2106 /* port is not IO, call write method for it. */
2107 return rb_funcall(io, id_write, 1, str);
2108 }
2109
2110 io = tmp;
2111 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2112
2113 GetOpenFile(io, fptr);
2115
2116 n = io_fwrite(str, fptr, nosync);
2117 if (n < 0L) rb_sys_fail_on_write(fptr);
2118
2119 return LEN2NUM(n);
2120}
2121
2122#ifdef HAVE_WRITEV
2123struct binwritev_arg {
2124 rb_io_t *fptr;
2125 struct iovec *iov;
2126 int iovcnt;
2127 size_t total;
2128};
2129
2130static VALUE
2131io_binwritev_internal(VALUE arg)
2132{
2133 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2134
2135 size_t remaining = p->total;
2136 size_t offset = 0;
2137
2138 rb_io_t *fptr = p->fptr;
2139 struct iovec *iov = p->iov;
2140 int iovcnt = p->iovcnt;
2141
2142 while (remaining) {
2143 rb_len_t result = rb_writev_internal(fptr, iov, iovcnt);
2144
2145 if (result >= 0) {
2146 offset += result;
2147 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2148 if (offset < (size_t)fptr->wbuf.len) {
2149 fptr->wbuf.off += result;
2150 fptr->wbuf.len -= result;
2151 }
2152 else {
2153 offset -= (size_t)fptr->wbuf.len;
2154 fptr->wbuf.off = 0;
2155 fptr->wbuf.len = 0;
2156 }
2157 }
2158
2159 if (offset == p->total) {
2160 return p->total;
2161 }
2162
2163 while (result >= (ssize_t)iov->iov_len) {
2164 /* iovcnt > 0 */
2165 result -= iov->iov_len;
2166 iov->iov_len = 0;
2167 iov++;
2168
2169 if (!--iovcnt) {
2170 // I don't believe this code path can ever occur.
2171 return offset;
2172 }
2173 }
2174
2175 iov->iov_base = (char *)iov->iov_base + result;
2176 iov->iov_len -= result;
2177 }
2178 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2179 rb_io_check_closed(fptr);
2180 }
2181 else {
2182 return -1;
2183 }
2184 }
2185
2186 return offset;
2187}
2188
2189static rb_len_t
2190io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2191{
2192 // Don't write anything if current thread has a pending interrupt:
2194
2195 if (iovcnt == 0) return 0;
2196
2197 size_t total = 0;
2198 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2199
2200 io_allocate_write_buffer(fptr, 1);
2201
2202 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2203 // The end of the buffered data:
2204 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2205
2206 if (offset + total <= (size_t)fptr->wbuf.capa) {
2207 for (int i = 1; i < iovcnt; i++) {
2208 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2209 offset += iov[i].iov_len;
2210 }
2211
2212 fptr->wbuf.len += total;
2213
2214 /* io_binwritev is only reached in sync/TTY mode (it is called only
2215 * from io_fwritev, which io_writev uses only when FMODE_SYNC or
2216 * FMODE_TTY is set), so the coalesced data must be flushed
2217 * immediately rather than left in the buffer until the next flush
2218 * or close. Otherwise a multi-argument write with many arguments
2219 * would not be observably atomic under sync. */
2220 if (io_fflush(fptr) < 0) return -1;
2221
2222 return total;
2223 }
2224 else {
2225 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2226 iov[0].iov_len = fptr->wbuf.len;
2227 }
2228 }
2229 else {
2230 // The first iov is reserved for the internal buffer, and it's empty.
2231 iov++;
2232
2233 if (!--iovcnt) {
2234 // If there are no other io vectors we are done.
2235 return 0;
2236 }
2237 }
2238
2239 struct binwritev_arg arg;
2240 arg.fptr = fptr;
2241 arg.iov = iov;
2242 arg.iovcnt = iovcnt;
2243 arg.total = total;
2244
2245 if (!NIL_P(fptr->write_lock)) {
2246 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2247 }
2248 else {
2249 return io_binwritev_internal((VALUE)&arg);
2250 }
2251}
2252
2253static rb_len_t
2254io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2255{
2256 int i, converted, iovcnt = argc + 1;
2257 rb_len_t n;
2258 VALUE v1, v2, str, tmp, *tmp_array;
2259 struct iovec *iov;
2260
2261 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2262 tmp_array = ALLOCV_N(VALUE, v2, argc);
2263
2264 for (i = 0; i < argc; i++) {
2265 str = rb_obj_as_string(argv[i]);
2266 converted = 0;
2267 str = do_writeconv(str, fptr, &converted);
2268
2269 if (converted)
2270 OBJ_FREEZE(str);
2271
2272 tmp = rb_str_tmp_frozen_acquire(str);
2273 tmp_array[i] = tmp;
2274
2275 /* iov[0] is reserved for buffer of fptr */
2276 iov[i+1].iov_base = RSTRING_PTR(tmp);
2277 iov[i+1].iov_len = RSTRING_LEN(tmp);
2278 }
2279
2280 n = io_binwritev(iov, iovcnt, fptr);
2281 if (v1) ALLOCV_END(v1);
2282
2283 for (i = 0; i < argc; i++) {
2284 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2285 }
2286
2287 if (v2) ALLOCV_END(v2);
2288
2289 return n;
2290}
2291
2292static int
2293iovcnt_ok(int iovcnt)
2294{
2295#ifdef IOV_MAX
2296 return iovcnt < IOV_MAX;
2297#else /* GNU/Hurd has writev, but no IOV_MAX */
2298 return 1;
2299#endif
2300}
2301#endif /* HAVE_WRITEV */
2302
2303static VALUE
2304io_writev(int argc, const VALUE *argv, VALUE io)
2305{
2306 rb_io_t *fptr;
2307 rb_len_t n;
2308 VALUE tmp, total = INT2FIX(0);
2309 int i, cnt = 1;
2310
2311 io = GetWriteIO(io);
2312 tmp = rb_io_check_io(io);
2313
2314 if (NIL_P(tmp)) {
2315 /* port is not IO, call write method for it. */
2316 return rb_funcallv(io, id_write, argc, argv);
2317 }
2318
2319 io = tmp;
2320
2321 GetOpenFile(io, fptr);
2323
2324 for (i = 0; i < argc; i += cnt) {
2325#ifdef HAVE_WRITEV
2326 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2327 n = io_fwritev(cnt, &argv[i], fptr);
2328 }
2329 else
2330#endif
2331 {
2332 cnt = 1;
2333 /* sync at last item */
2334 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2335 }
2336
2337 if (n < 0L)
2338 rb_sys_fail_on_write(fptr);
2339
2340 total = rb_int_plus(LEN2NUM(n), total);
2341 }
2342
2343 return total;
2344}
2345
2346/*
2347 * call-seq:
2348 * write(*objects) -> integer
2349 *
2350 * Writes each of the given +objects+ to +self+,
2351 * which must be opened for writing
2352 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2353 * returns the total number bytes written;
2354 * each of +objects+ that is not a string is converted via method +to_s+:
2355 *
2356 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2357 * $stdout.write('foo', :bar, 2, "\n") # => 8
2358 *
2359 * Output:
2360 *
2361 * Hello, World!
2362 * foobar2
2363 *
2364 * Related: IO#read.
2365 */
2366
2367static VALUE
2368io_write_m(int argc, VALUE *argv, VALUE io)
2369{
2370 if (argc != 1) {
2371 return io_writev(argc, argv, io);
2372 }
2373 else {
2374 VALUE str = argv[0];
2375 return io_write(io, str, 0);
2376 }
2377}
2378
2379VALUE
2380rb_io_write(VALUE io, VALUE str)
2381{
2382 return rb_funcallv(io, id_write, 1, &str);
2383}
2384
2385static VALUE
2386rb_io_writev(VALUE io, int argc, const VALUE *argv)
2387{
2388 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2389 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2390 VALUE klass = CLASS_OF(io);
2391 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2393 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2394 " which accepts just one argument",
2395 klass, sep
2396 );
2397 }
2398
2399 do rb_io_write(io, *argv++); while (--argc);
2400
2401 return Qnil;
2402 }
2403
2404 return rb_funcallv(io, id_write, argc, argv);
2405}
2406
2407/*
2408 * call-seq:
2409 * self << object -> self
2410 *
2411 * Writes the given +object+ to +self+,
2412 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2413 * returns +self+;
2414 * if +object+ is not a string, it is converted via method +to_s+:
2415 *
2416 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2417 * $stdout << 'foo' << :bar << 2 << "\n"
2418 *
2419 * Output:
2420 *
2421 * Hello, World!
2422 * foobar2
2423 *
2424 */
2425
2426
2427VALUE
2429{
2430 rb_io_write(io, str);
2431 return io;
2432}
2433
2434#ifdef HAVE_FSYNC
2435static VALUE
2436nogvl_fsync(void *ptr)
2437{
2438 rb_io_t *fptr = ptr;
2439
2440#ifdef _WIN32
2441 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2442 return 0;
2443#endif
2444 return (VALUE)fsync(fptr->fd);
2445}
2446#endif
2447
2448VALUE
2449rb_io_flush_raw(VALUE io, int sync)
2450{
2451 rb_io_t *fptr;
2452
2453 if (!RB_TYPE_P(io, T_FILE)) {
2454 return rb_funcall(io, id_flush, 0);
2455 }
2456
2457 io = GetWriteIO(io);
2458 GetOpenFile(io, fptr);
2459
2460 if (fptr->mode & FMODE_WRITABLE) {
2461 if (io_fflush(fptr) < 0)
2462 rb_sys_fail_on_write(fptr);
2463 }
2464 if (fptr->mode & FMODE_READABLE) {
2465 io_unread(fptr, true);
2466 }
2467
2468 return io;
2469}
2470
2471/*
2472 * call-seq:
2473 * flush -> self
2474 *
2475 * Flushes data buffered in +self+ to the operating system
2476 * (but does not necessarily flush data buffered in the operating system):
2477 *
2478 * $stdout.print 'no newline' # Not necessarily flushed.
2479 * $stdout.flush # Flushed.
2480 *
2481 */
2482
2483VALUE
2484rb_io_flush(VALUE io)
2485{
2486 return rb_io_flush_raw(io, 1);
2487}
2488
2489/*
2490 * call-seq:
2491 * tell -> integer
2492 *
2493 * Returns the current position (in bytes) in +self+
2494 * (see {Position}[rdoc-ref:IO@Position]):
2495 *
2496 * f = File.open('t.txt')
2497 * f.tell # => 0
2498 * f.gets # => "First line\n"
2499 * f.tell # => 12
2500 * f.close
2501 *
2502 * Related: IO#pos=, IO#seek.
2503 */
2504
2505static VALUE
2506rb_io_tell(VALUE io)
2507{
2508 rb_io_t *fptr;
2509 rb_off_t pos;
2510
2511 GetOpenFile(io, fptr);
2512 pos = io_tell(fptr);
2513 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2514 pos -= fptr->rbuf.len;
2515 return OFFT2NUM(pos);
2516}
2517
2518static VALUE
2519rb_io_seek(VALUE io, VALUE offset, int whence)
2520{
2521 rb_io_t *fptr;
2522 rb_off_t pos;
2523
2524 pos = NUM2OFFT(offset);
2525 GetOpenFile(io, fptr);
2526 pos = io_seek(fptr, pos, whence);
2527 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2528 if (fptr->readconv) clear_readconv(fptr);
2529
2530 return INT2FIX(0);
2531}
2532
2533static int
2534interpret_seek_whence(VALUE vwhence)
2535{
2536 if (vwhence == sym_SET)
2537 return SEEK_SET;
2538 if (vwhence == sym_CUR)
2539 return SEEK_CUR;
2540 if (vwhence == sym_END)
2541 return SEEK_END;
2542#ifdef SEEK_DATA
2543 if (vwhence == sym_DATA)
2544 return SEEK_DATA;
2545#endif
2546#ifdef SEEK_HOLE
2547 if (vwhence == sym_HOLE)
2548 return SEEK_HOLE;
2549#endif
2550 return NUM2INT(vwhence);
2551}
2552
2553/*
2554 * call-seq:
2555 * seek(offset, whence = IO::SEEK_SET) -> 0
2556 *
2557 * Seeks to the position given by integer +offset+
2558 * (see {Position}[rdoc-ref:IO@Position])
2559 * and constant +whence+, which is one of:
2560 *
2561 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2562 * Repositions the stream to its current position plus the given +offset+:
2563 *
2564 * f = File.open('t.txt')
2565 * f.tell # => 0
2566 * f.seek(20, :CUR) # => 0
2567 * f.tell # => 20
2568 * f.seek(-10, :CUR) # => 0
2569 * f.tell # => 10
2570 * f.close
2571 *
2572 * - +:END+ or <tt>IO::SEEK_END</tt>:
2573 * Repositions the stream to its end plus the given +offset+:
2574 *
2575 * f = File.open('t.txt')
2576 * f.tell # => 0
2577 * f.seek(0, :END) # => 0 # Repositions to stream end.
2578 * f.tell # => 52
2579 * f.seek(-20, :END) # => 0
2580 * f.tell # => 32
2581 * f.seek(-40, :END) # => 0
2582 * f.tell # => 12
2583 * f.close
2584 *
2585 * - +:SET+ or <tt>IO::SEEK_SET</tt>:
2586 * Repositions the stream to the given +offset+:
2587 *
2588 * f = File.open('t.txt')
2589 * f.tell # => 0
2590 * f.seek(20, :SET) # => 0
2591 * f.tell # => 20
2592 * f.seek(40, :SET) # => 0
2593 * f.tell # => 40
2594 * f.close
2595 *
2596 * Related: IO#pos=, IO#tell.
2597 *
2598 */
2599
2600static VALUE
2601rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2602{
2603 VALUE offset, ptrname;
2604 int whence = SEEK_SET;
2605
2606 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2607 whence = interpret_seek_whence(ptrname);
2608 }
2609
2610 return rb_io_seek(io, offset, whence);
2611}
2612
2613/*
2614 * call-seq:
2615 * pos = new_position -> new_position
2616 *
2617 * Seeks to the given +new_position+ (in bytes);
2618 * see {Position}[rdoc-ref:IO@Position]:
2619 *
2620 * f = File.open('t.txt')
2621 * f.tell # => 0
2622 * f.pos = 20 # => 20
2623 * f.tell # => 20
2624 * f.close
2625 *
2626 * Related: IO#seek, IO#tell.
2627 *
2628 */
2629
2630static VALUE
2631rb_io_set_pos(VALUE io, VALUE offset)
2632{
2633 rb_io_t *fptr;
2634 rb_off_t pos;
2635
2636 pos = NUM2OFFT(offset);
2637 GetOpenFile(io, fptr);
2638 pos = io_seek(fptr, pos, SEEK_SET);
2639 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2640 if (fptr->readconv) clear_readconv(fptr);
2641
2642 return OFFT2NUM(pos);
2643}
2644
2645/*
2646 * call-seq:
2647 * rewind -> 0
2648 *
2649 * Repositions the stream to its beginning,
2650 * setting both the position and the line number to zero;
2651 * see {Position}[rdoc-ref:IO@Position]
2652 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2653 *
2654 * f = File.open('t.txt')
2655 * f.tell # => 0
2656 * f.lineno # => 0
2657 * f.gets # => "First line\n"
2658 * f.tell # => 12
2659 * f.lineno # => 1
2660 * f.rewind # => 0
2661 * f.tell # => 0
2662 * f.lineno # => 0
2663 * f.close
2664 *
2665 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2666 *
2667 */
2668
2669static VALUE
2670rb_io_rewind(VALUE io)
2671{
2672 rb_io_t *fptr;
2673
2674 GetOpenFile(io, fptr);
2675 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2676 if (io == ARGF.current_file) {
2677 ARGF.lineno -= fptr->lineno;
2678 }
2679 fptr->lineno = 0;
2680 if (fptr->readconv) {
2681 clear_readconv(fptr);
2682 }
2683
2684 return INT2FIX(0);
2685}
2686
2687static int
2688fptr_wait_readable(rb_io_t *fptr)
2689{
2690 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2691
2692 if (result)
2693 rb_io_check_closed(fptr);
2694
2695 return result;
2696}
2697
2698static int
2699io_fillbuf(rb_io_t *fptr)
2700{
2701 ssize_t r;
2702
2703 if (fptr->rbuf.ptr == NULL) {
2704 fptr->rbuf.off = 0;
2705 fptr->rbuf.len = 0;
2706 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2707 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2708 }
2709 if (fptr->rbuf.len == 0) {
2710 retry:
2711 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2712
2713 if (r < 0) {
2714 if (fptr_wait_readable(fptr))
2715 goto retry;
2716
2717 int e = errno;
2718 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2719 if (!NIL_P(fptr->pathv)) {
2720 rb_str_append(path, fptr->pathv);
2721 }
2722
2723 rb_syserr_fail_path(e, path);
2724 }
2725 if (r > 0) rb_io_check_closed(fptr);
2726 fptr->rbuf.off = 0;
2727 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2728 if (r == 0)
2729 return -1; /* EOF */
2730 }
2731 return 0;
2732}
2733
2734/*
2735 * call-seq:
2736 * eof -> true or false
2737 *
2738 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2739 * see {Position}[rdoc-ref:IO@Position]:
2740 *
2741 * f = File.open('t.txt')
2742 * f.eof # => false
2743 * f.seek(0, :END) # => 0
2744 * f.eof # => true
2745 * f.close
2746 *
2747 * Raises an exception unless the stream is opened for reading;
2748 * see {Mode}[rdoc-ref:File@Access+Modes].
2749 *
2750 * If +self+ is a stream such as pipe or socket, this method
2751 * blocks until the other end sends some data or closes it:
2752 *
2753 * r, w = IO.pipe
2754 * Thread.new { sleep 1; w.close }
2755 * r.eof? # => true # After 1-second wait.
2756 *
2757 * r, w = IO.pipe
2758 * Thread.new { sleep 1; w.puts "a" }
2759 * r.eof? # => false # After 1-second wait.
2760 *
2761 * r, w = IO.pipe
2762 * r.eof? # blocks forever
2763 *
2764 * Note that this method reads data to the input byte buffer. So
2765 * IO#sysread may not behave as you intend with IO#eof?, unless you
2766 * call IO#rewind first (which is not available for some streams).
2767 */
2768
2769VALUE
2771{
2772 rb_io_t *fptr;
2773
2774 GetOpenFile(io, fptr);
2776
2777 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2778 if (READ_DATA_PENDING(fptr)) return Qfalse;
2779 READ_CHECK(fptr);
2780#if RUBY_CRLF_ENVIRONMENT
2781 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2782 return RBOOL(eof(fptr->fd));
2783 }
2784#endif
2785 return RBOOL(io_fillbuf(fptr) < 0);
2786}
2787
2788/*
2789 * call-seq:
2790 * sync -> true or false
2791 *
2792 * Returns the current sync mode of the stream.
2793 * When sync mode is true, all output is immediately flushed to the underlying
2794 * operating system and is not buffered by Ruby internally. See also #fsync.
2795 *
2796 * f = File.open('t.tmp', 'w')
2797 * f.sync # => false
2798 * f.sync = true
2799 * f.sync # => true
2800 * f.close
2801 *
2802 */
2803
2804static VALUE
2805rb_io_sync(VALUE io)
2806{
2807 rb_io_t *fptr;
2808
2809 io = GetWriteIO(io);
2810 GetOpenFile(io, fptr);
2811 return RBOOL(fptr->mode & FMODE_SYNC);
2812}
2813
2814#ifdef HAVE_FSYNC
2815
2816/*
2817 * call-seq:
2818 * sync = boolean -> boolean
2819 *
2820 * Sets the _sync_ _mode_ for the stream to the given value;
2821 * returns the given value.
2822 *
2823 * Values for the sync mode:
2824 *
2825 * - +true+: All output is immediately flushed to the
2826 * underlying operating system and is not buffered internally.
2827 * - +false+: Output may be buffered internally.
2828 *
2829 * Example;
2830 *
2831 * f = File.open('t.tmp', 'w')
2832 * f.sync # => false
2833 * f.sync = true
2834 * f.sync # => true
2835 * f.close
2836 *
2837 * Related: IO#fsync.
2838 *
2839 */
2840
2841static VALUE
2842rb_io_set_sync(VALUE io, VALUE sync)
2843{
2844 rb_io_t *fptr;
2845
2846 io = GetWriteIO(io);
2847 GetOpenFile(io, fptr);
2848 if (RTEST(sync)) {
2849 fptr->mode |= FMODE_SYNC;
2850 }
2851 else {
2852 fptr->mode &= ~FMODE_SYNC;
2853 }
2854 return sync;
2855}
2856
2857/*
2858 * call-seq:
2859 * fsync -> 0
2860 *
2861 * Immediately writes to disk all data buffered in the stream,
2862 * via the operating system's <tt>fsync(2)</tt>.
2863
2864 * Note this difference:
2865 *
2866 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2867 * but does not guarantee that the operating system actually writes the data to disk.
2868 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2869 * and that data is written to disk.
2870 *
2871 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2872 *
2873 */
2874
2875static VALUE
2876rb_io_fsync(VALUE io)
2877{
2878 rb_io_t *fptr;
2879
2880 io = GetWriteIO(io);
2881 GetOpenFile(io, fptr);
2882
2883 if (io_fflush(fptr) < 0)
2884 rb_sys_fail_on_write(fptr);
2885
2886 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2887 rb_sys_fail_path(fptr->pathv);
2888
2889 return INT2FIX(0);
2890}
2891#else
2892# define rb_io_fsync rb_f_notimplement
2893# define rb_io_sync rb_f_notimplement
2894static VALUE
2895rb_io_set_sync(VALUE io, VALUE sync)
2896{
2897 rb_notimplement();
2899}
2900#endif
2901
2902#ifdef HAVE_FDATASYNC
2903static VALUE
2904nogvl_fdatasync(void *ptr)
2905{
2906 rb_io_t *fptr = ptr;
2907
2908 return (VALUE)fdatasync(fptr->fd);
2909}
2910
2911/*
2912 * call-seq:
2913 * fdatasync -> 0
2914 *
2915 * Immediately writes to disk all data buffered in the stream,
2916 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2917 * otherwise via <tt>fsync(2)</tt>, if supported;
2918 * otherwise raises an exception.
2919 *
2920 */
2921
2922static VALUE
2923rb_io_fdatasync(VALUE io)
2924{
2925 rb_io_t *fptr;
2926
2927 io = GetWriteIO(io);
2928 GetOpenFile(io, fptr);
2929
2930 if (io_fflush(fptr) < 0)
2931 rb_sys_fail_on_write(fptr);
2932
2933 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2934 return INT2FIX(0);
2935
2936 /* fall back */
2937 return rb_io_fsync(io);
2938}
2939#else
2940#define rb_io_fdatasync rb_io_fsync
2941#endif
2942
2943/*
2944 * call-seq:
2945 * fileno -> integer
2946 *
2947 * Returns the integer file descriptor for the stream:
2948 *
2949 * $stdin.fileno # => 0
2950 * $stdout.fileno # => 1
2951 * $stderr.fileno # => 2
2952 * File.open('t.txt').fileno # => 10
2953 * f.close
2954 *
2955 */
2956
2957static VALUE
2958rb_io_fileno(VALUE io)
2959{
2960 rb_io_t *fptr = RFILE(io)->fptr;
2961 int fd;
2962
2963 rb_io_check_closed(fptr);
2964 fd = fptr->fd;
2965 return INT2FIX(fd);
2966}
2967
2968int
2970{
2971 if (RB_TYPE_P(io, T_FILE)) {
2972 rb_io_t *fptr = RFILE(io)->fptr;
2973 rb_io_check_closed(fptr);
2974 return fptr->fd;
2975 }
2976 else {
2977 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2978 if (!UNDEF_P(fileno)) {
2979 return RB_NUM2INT(fileno);
2980 }
2981 }
2982
2983 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2984
2986}
2987
2988int
2989rb_io_mode(VALUE io)
2990{
2991 rb_io_t *fptr;
2992 GetOpenFile(io, fptr);
2993 return fptr->mode;
2994}
2995
2996/*
2997 * call-seq:
2998 * pid -> integer or nil
2999 *
3000 * Returns the process ID of a child process associated with the stream,
3001 * which will have been set by IO#popen, or +nil+ if the stream was not
3002 * created by IO#popen:
3003 *
3004 * pipe = IO.popen("-")
3005 * if pipe
3006 * $stderr.puts "In parent, child pid is #{pipe.pid}"
3007 * else
3008 * $stderr.puts "In child, pid is #{$$}"
3009 * end
3010 *
3011 * Output:
3012 *
3013 * In child, pid is 26209
3014 * In parent, child pid is 26209
3015 *
3016 */
3017
3018static VALUE
3019rb_io_pid(VALUE io)
3020{
3021 rb_io_t *fptr;
3022
3023 GetOpenFile(io, fptr);
3024 if (!fptr->pid)
3025 return Qnil;
3026 return PIDT2NUM(fptr->pid);
3027}
3028
3029/*
3030 * :markup: markdown
3031 *
3032 * call-seq:
3033 * path -> string or nil
3034 *
3035 * Returns the string path associated with `self`,
3036 * or `nil` if there is no associated path:
3037 *
3038 * ```ruby
3039 * path = 'doc/maintainers.md'
3040 * fd = File.open(path).fileno # => 6
3041 * IO.new(fd, path: path).path # => "doc/maintainers.md"
3042 * IO.new(fd).path # => nil
3043 * ```
3044 *
3045 */
3046
3047VALUE
3049{
3050 rb_io_t *fptr = RFILE(io)->fptr;
3051
3052 if (!fptr)
3053 return Qnil;
3054
3055 return rb_obj_dup(fptr->pathv);
3056}
3057
3058/*
3059 * call-seq:
3060 * inspect -> string
3061 *
3062 * Returns a string representation of +self+:
3063 *
3064 * f = File.open('t.txt')
3065 * f.inspect # => "#<File:t.txt>"
3066 * f.close
3067 *
3068 */
3069
3070static VALUE
3071rb_io_inspect(VALUE obj)
3072{
3073 rb_io_t *fptr;
3074 VALUE result;
3075 static const char closed[] = " (closed)";
3076
3077 fptr = RFILE(obj)->fptr;
3078 if (!fptr) return rb_any_to_s(obj);
3079 result = rb_str_new_cstr("#<");
3080 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3081 rb_str_cat2(result, ":");
3082 if (NIL_P(fptr->pathv)) {
3083 if (fptr->fd < 0) {
3084 rb_str_cat(result, closed+1, strlen(closed)-1);
3085 }
3086 else {
3087 rb_str_catf(result, "fd %d", fptr->fd);
3088 }
3089 }
3090 else {
3091 rb_str_append(result, fptr->pathv);
3092 if (fptr->fd < 0) {
3093 rb_str_cat(result, closed, strlen(closed));
3094 }
3095 }
3096 return rb_str_cat2(result, ">");
3097}
3098
3099/*
3100 * call-seq:
3101 * to_io -> self
3102 *
3103 * Returns +self+.
3104 *
3105 */
3106
3107static VALUE
3108rb_io_to_io(VALUE io)
3109{
3110 return io;
3111}
3112
3113/* reading functions */
3114static rb_len_t
3115read_buffered_data(char *ptr, rb_len_t len, rb_io_t *fptr)
3116{
3117 int n;
3118
3119 n = READ_DATA_PENDING_COUNT(fptr);
3120 if (n <= 0) return 0;
3121 if (n > len) n = (int)len;
3122 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3123 fptr->rbuf.off += n;
3124 fptr->rbuf.len -= n;
3125 return n;
3126}
3127
3128static rb_len_t
3129io_bufread(char *ptr, rb_len_t len, rb_io_t *fptr, rb_len_t *read_len)
3130{
3131 rb_len_t offset = 0;
3132 rb_len_t n = len;
3133 rb_len_t c;
3134
3135 *read_len = 0;
3136 if (READ_DATA_PENDING(fptr) == 0) {
3137 while (n > 0) {
3138 again:
3139 rb_io_check_closed(fptr);
3140 c = rb_io_read_memory(fptr, ptr+offset, n);
3141 if (c == 0) break;
3142 if (c < 0) {
3143 if (fptr_wait_readable(fptr))
3144 goto again;
3145 return -1;
3146 }
3147 offset += c;
3148 *read_len = offset;
3149 if ((n -= c) <= 0) break;
3150 }
3151 return len - n;
3152 }
3153
3154 while (n > 0) {
3155 c = read_buffered_data(ptr+offset, n, fptr);
3156 if (c > 0) {
3157 offset += c;
3158 *read_len = offset;
3159 if ((n -= c) <= 0) break;
3160 }
3161 rb_io_check_closed(fptr);
3162 if (io_fillbuf(fptr) < 0) {
3163 break;
3164 }
3165 }
3166 return len - n;
3167}
3168
3169static int io_setstrbuf(VALUE *str, rb_len_t len);
3170
3172 char *str_ptr;
3173 rb_len_t offset;
3174 rb_len_t len;
3175 rb_len_t read_len;
3176 rb_io_t *fptr;
3177};
3178
3179static VALUE
3180bufread_body(VALUE arg)
3181{
3182 struct bufread_arg *p = (struct bufread_arg *)arg;
3183 p->len = io_bufread(p->str_ptr + p->offset, p->len, p->fptr, &p->read_len);
3184 return Qundef;
3185}
3186
3187static VALUE
3188bufread_timeout(VALUE arg, VALUE error)
3189{
3190 struct bufread_arg *p = (struct bufread_arg *)arg;
3191
3192 if (p->offset + p->read_len > 0) {
3193 VALUE str = rb_str_new(p->str_ptr, p->offset + p->read_len);
3194 io_restore_read_buffer(str, p->fptr);
3195 }
3196 rb_exc_raise(error);
3198}
3199
3200static VALUE
3201bufread_call(VALUE arg)
3202{
3203 struct bufread_arg *p = (struct bufread_arg *)arg;
3204
3205 if (NIL_P(p->fptr->timeout)) {
3206 return bufread_body(arg);
3207 }
3208 return rb_rescue2(bufread_body, arg, bufread_timeout, arg,
3209 rb_eIOTimeoutError, (VALUE)0);
3210}
3211
3212static rb_len_t
3213io_fread(VALUE str, rb_len_t offset, rb_len_t size, rb_io_t *fptr)
3214{
3215 rb_len_t len;
3216 struct bufread_arg arg;
3217
3218 io_setstrbuf(&str, offset + size);
3219 arg.str_ptr = RSTRING_PTR(str);
3220 arg.offset = offset;
3221 arg.len = size;
3222 arg.read_len = 0;
3223 arg.fptr = fptr;
3224 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3225 len = arg.len;
3226 if (len < 0) rb_sys_fail_path(fptr->pathv);
3227 return len;
3228}
3229
3230static rb_len_t
3231remain_size(rb_io_t *fptr)
3232{
3233 struct stat st;
3234 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3235 rb_off_t pos;
3236
3237 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3238#if defined(__HAIKU__)
3239 && (st.st_dev > 3)
3240#endif
3241 )
3242 {
3243 if (io_fflush(fptr) < 0)
3244 rb_sys_fail_on_write(fptr);
3245 pos = lseek(fptr->fd, 0, SEEK_CUR);
3246 if (st.st_size >= pos && pos >= 0) {
3247 siz += st.st_size - pos;
3248 if (siz > RB_LEN_MAX) {
3249 rb_raise(rb_eIOError, "file too big for single read");
3250 }
3251 }
3252 }
3253 else {
3254 siz += BUFSIZ;
3255 }
3256 return (rb_len_t)siz;
3257}
3258
3259static VALUE
3260io_enc_str(VALUE str, rb_io_t *fptr)
3261{
3262 rb_enc_associate(str, io_read_encoding(fptr));
3263 return str;
3264}
3265
3266static void
3267make_readconv(rb_io_t *fptr, int size)
3268{
3269 if (!fptr->readconv) {
3270 int ecflags;
3271 VALUE ecopts;
3272 const char *sname, *dname;
3273 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3274 ecopts = fptr->encs.ecopts;
3275 if (fptr->encs.enc2) {
3276 sname = rb_enc_name(fptr->encs.enc2);
3277 dname = rb_enc_name(io_read_encoding(fptr));
3278 }
3279 else {
3280 sname = dname = "";
3281 }
3282 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3283 if (!fptr->readconv)
3284 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3285 fptr->cbuf.off = 0;
3286 fptr->cbuf.len = 0;
3287 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3288 fptr->cbuf.capa = size;
3289 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3290 }
3291}
3292
3293#define MORE_CHAR_SUSPENDED Qtrue
3294#define MORE_CHAR_FINISHED Qnil
3295static VALUE
3296fill_cbuf(rb_io_t *fptr, int ec_flags)
3297{
3298 const unsigned char *ss, *sp, *se;
3299 unsigned char *ds, *dp, *de;
3301 int putbackable;
3302 int cbuf_len0;
3303 VALUE exc;
3304
3305 ec_flags |= ECONV_PARTIAL_INPUT;
3306
3307 if (fptr->cbuf.len == fptr->cbuf.capa)
3308 return MORE_CHAR_SUSPENDED; /* cbuf full */
3309 if (fptr->cbuf.len == 0)
3310 fptr->cbuf.off = 0;
3311 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3312 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3313 fptr->cbuf.off = 0;
3314 }
3315
3316 cbuf_len0 = fptr->cbuf.len;
3317
3318 while (1) {
3319 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3320 se = sp + fptr->rbuf.len;
3321 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3322 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3323 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3324 fptr->rbuf.off += (int)(sp - ss);
3325 fptr->rbuf.len -= (int)(sp - ss);
3326 fptr->cbuf.len += (int)(dp - ds);
3327
3328 putbackable = rb_econv_putbackable(fptr->readconv);
3329 if (putbackable) {
3330 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3331 fptr->rbuf.off -= putbackable;
3332 fptr->rbuf.len += putbackable;
3333 }
3334
3335 exc = rb_econv_make_exception(fptr->readconv);
3336 if (!NIL_P(exc))
3337 return exc;
3338
3339 if (cbuf_len0 != fptr->cbuf.len)
3340 return MORE_CHAR_SUSPENDED;
3341
3342 if (res == econv_finished) {
3343 return MORE_CHAR_FINISHED;
3344 }
3345
3346 if (res == econv_source_buffer_empty) {
3347 if (fptr->rbuf.len == 0) {
3348 READ_CHECK(fptr);
3349 if (io_fillbuf(fptr) < 0) {
3350 if (!fptr->readconv) {
3351 return MORE_CHAR_FINISHED;
3352 }
3353 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3354 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3355 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3356 fptr->cbuf.len += (int)(dp - ds);
3358 break;
3359 }
3360 }
3361 }
3362 }
3363 if (cbuf_len0 != fptr->cbuf.len)
3364 return MORE_CHAR_SUSPENDED;
3365
3366 return MORE_CHAR_FINISHED;
3367}
3368
3369static VALUE
3370more_char(rb_io_t *fptr)
3371{
3372 VALUE v;
3373 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3374 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3375 rb_exc_raise(v);
3376 return v;
3377}
3378
3379static VALUE
3380io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3381{
3382 VALUE str = Qnil;
3383 if (strp) {
3384 str = *strp;
3385 if (NIL_P(str)) {
3386 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3387 }
3388 else {
3389 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3390 }
3391 rb_enc_associate(str, fptr->encs.enc);
3392 }
3393 fptr->cbuf.off += len;
3394 fptr->cbuf.len -= len;
3395 /* xxx: set coderange */
3396 if (fptr->cbuf.len == 0)
3397 fptr->cbuf.off = 0;
3398 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3399 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3400 fptr->cbuf.off = 0;
3401 }
3402 return str;
3403}
3404
3405static int
3406io_setstrbuf(VALUE *str, rb_len_t len)
3407{
3408 if (NIL_P(*str)) {
3409 *str = rb_str_new(0, len);
3410 return TRUE;
3411 }
3412 else {
3413 VALUE s = StringValue(*str);
3414 rb_str_modify(s);
3415
3416 rb_len_t clen = RSTRING_LEN(s);
3417 if (clen >= len) {
3418 return FALSE;
3419 }
3420 len -= clen;
3421 }
3422 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3424 }
3425 return FALSE;
3426}
3427
3428#define MAX_REALLOC_GAP 4096
3429static void
3430io_shrink_read_string(VALUE str, rb_len_t n)
3431{
3432 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3433 rb_str_resize(str, n);
3434 }
3435}
3436
3437static void
3438io_set_read_length(VALUE str, rb_len_t n, int shrinkable)
3439{
3440 if (RSTRING_LEN(str) != n) {
3441 rb_str_modify(str);
3442 rb_str_set_len(str, n);
3443 if (shrinkable) io_shrink_read_string(str, n);
3444 }
3445}
3446
3447static VALUE
3448read_all(rb_io_t *fptr, rb_len_t siz, VALUE str)
3449{
3450 rb_len_t bytes;
3451 rb_len_t n;
3452 rb_len_t pos;
3453 rb_encoding *enc;
3454 int cr;
3455 int shrinkable;
3456
3457 if (NEED_READCONV(fptr)) {
3458 int first = !NIL_P(str);
3459 SET_BINARY_MODE(fptr);
3460 shrinkable = io_setstrbuf(&str,0);
3461 make_readconv(fptr, 0);
3462 while (1) {
3463 VALUE v;
3464 if (fptr->cbuf.len) {
3465 if (first) rb_str_set_len(str, first = 0);
3466 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3467 }
3468 v = fill_cbuf(fptr, 0);
3469 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3470 if (fptr->cbuf.len) {
3471 if (first) rb_str_set_len(str, first = 0);
3472 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3473 }
3474 rb_exc_raise(v);
3475 }
3476 if (v == MORE_CHAR_FINISHED) {
3477 clear_readconv(fptr);
3478 if (first) rb_str_set_len(str, first = 0);
3479 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3480 return io_enc_str(str, fptr);
3481 }
3482 }
3483 }
3484
3485 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3486 bytes = 0;
3487 pos = 0;
3488
3489 enc = io_read_encoding(fptr);
3490 cr = 0;
3491
3492 if (siz == 0) {
3493 siz = BUFSIZ;
3494 }
3495 else {
3496 // If `siz` is set, we got it from `stat(2)`.
3497 // We attempt to read one extra byte because:
3498 // - If the file was appended to since then, we'll continue reading.
3499 // - If the file is still the same length, we won't issue a second `io_fread`.
3500 siz++;
3501 }
3502 shrinkable = io_setstrbuf(&str, siz);
3503 for (;;) {
3504 READ_CHECK(fptr);
3505 n = io_fread(str, bytes, siz - bytes, fptr);
3506 if (n == 0 && bytes == 0) {
3507 rb_str_set_len(str, 0);
3508 break;
3509 }
3510 bytes += n;
3511 rb_str_set_len(str, bytes);
3512 if (cr != ENC_CODERANGE_BROKEN)
3513 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3514 if (bytes < siz) break;
3515 siz += BUFSIZ;
3516
3517 size_t capa = rb_str_capacity(str);
3518 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3519 if (capa < BUFSIZ) {
3520 capa = BUFSIZ;
3521 }
3522 else if (capa > IO_MAX_BUFFER_GROWTH) {
3523 capa = IO_MAX_BUFFER_GROWTH;
3524 }
3526 }
3527 }
3528 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3529 str = io_enc_str(str, fptr);
3530 ENC_CODERANGE_SET(str, cr);
3531 return str;
3532}
3533
3534void
3536{
3537 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3538 rb_sys_fail_path(fptr->pathv);
3539 }
3540}
3541
3542static VALUE
3543io_read_memory_call(VALUE arg)
3544{
3545 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3546
3547 VALUE scheduler = rb_fiber_scheduler_current();
3548 if (scheduler != Qnil) {
3549 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa);
3550
3551 if (!UNDEF_P(result)) {
3552 // This is actually returned as a pseudo-VALUE and later cast to a rb_len_t:
3554 }
3555 }
3556
3557 if (iis->nonblock) {
3558 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3559 }
3560 else {
3561 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3562 }
3563}
3564
3565static rb_len_t
3566io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3567{
3568 return (rb_len_t)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3569}
3570
3571#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3572
3573static VALUE
3574io_getpartial(VALUE io, VALUE length, VALUE str, int no_exception, int nonblock)
3575{
3576 rb_io_t *fptr;
3577 rb_len_t n, len;
3578 struct io_internal_read_struct iis;
3579 int shrinkable;
3580
3581 if ((len = NUM2LEN(length)) < 0) {
3582 rb_raise(rb_eArgError, "negative length %"PRIdLEN" given", len);
3583 }
3584
3585 shrinkable = io_setstrbuf(&str, len);
3586
3587 GetOpenFile(io, fptr);
3589
3590 if (len == 0) {
3591 io_set_read_length(str, 0, shrinkable);
3592 return str;
3593 }
3594
3595 if (!nonblock)
3596 READ_CHECK(fptr);
3597 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3598 if (n <= 0) {
3599 again:
3600 if (nonblock) {
3601 /* NOTE: The result is deliberately ignored */
3602 rb_fd_set_nonblock(fptr->fd);
3603 }
3604 io_setstrbuf(&str, len);
3605 iis.th = rb_thread_current();
3606 iis.fptr = fptr;
3607 iis.nonblock = nonblock;
3608 iis.fd = fptr->fd;
3609 iis.buf = RSTRING_PTR(str);
3610 iis.capa = len;
3611 iis.timeout = NULL;
3612 n = io_read_memory_locktmp(str, &iis);
3613 if (n < 0) {
3614 int e = errno;
3615 if (!nonblock && fptr_wait_readable(fptr))
3616 goto again;
3617 if (nonblock && (io_again_p(e))) {
3618 if (no_exception)
3619 return sym_wait_readable;
3620 else
3621 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3622 e, "read would block");
3623 }
3624 rb_syserr_fail_path(e, fptr->pathv);
3625 }
3626 }
3627 io_set_read_length(str, n, shrinkable);
3628
3629 if (n == 0)
3630 return Qnil;
3631 else
3632 return str;
3633}
3634
3635/*
3636 * call-seq:
3637 * readpartial(maxlen) -> string
3638 * readpartial(maxlen, out_string) -> out_string
3639 *
3640 * Reads up to +maxlen+ bytes from the stream;
3641 * returns a string (either a new string or the given +out_string+).
3642 * Its encoding is:
3643 *
3644 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3645 * - ASCII-8BIT, otherwise.
3646 *
3647 * - Contains +maxlen+ bytes from the stream, if available.
3648 * - Otherwise contains all available bytes, if any available.
3649 * - Is an empty string if +maxlen+ is zero.
3650 *
3651 * With the single non-negative integer argument +maxlen+ given,
3652 * returns a new string:
3653 *
3654 * f = File.new('t.txt')
3655 * f.readpartial(20) # => "First line\nSecond l"
3656 * f.readpartial(20) # => "ine\n\nFourth line\n"
3657 * f.readpartial(20) # => "Fifth line\n"
3658 * f.readpartial(20) # Raises EOFError.
3659 * f.close
3660 *
3661 * With both argument +maxlen+ and string argument +out_string+ given,
3662 * returns modified +out_string+:
3663 *
3664 * f = File.new('t.txt')
3665 * s = 'foo'
3666 * f.readpartial(20, s) # => "First line\nSecond l"
3667 * s = 'bar'
3668 * f.readpartial(0, s) # => ""
3669 * f.close
3670 *
3671 * This method is useful for a stream such as a pipe, a socket, or a tty.
3672 * It blocks only when no data is immediately available.
3673 * This means that it blocks only when _all_ of the following are true:
3674 *
3675 * - The byte buffer in the stream is empty.
3676 * - The content of the stream is empty.
3677 * - The stream is not at EOF.
3678 *
3679 * When blocked, the method waits for either more data or EOF on the stream:
3680 *
3681 * - If more data is read, the method returns the data.
3682 * - If EOF is reached, the method raises EOFError.
3683 *
3684 * When not blocked, the method responds immediately:
3685 *
3686 * - Returns data from the buffer if there is any.
3687 * - Otherwise returns data from the stream if there is any.
3688 * - Otherwise raises EOFError if the stream has reached EOF.
3689 *
3690 * Note that this method is similar to sysread. The differences are:
3691 *
3692 * - If the byte buffer is not empty, read from the byte buffer
3693 * instead of "sysread for buffered IO (IOError)".
3694 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3695 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3696 * readpartial retries the system call.
3697 *
3698 * The latter means that readpartial is non-blocking-flag insensitive.
3699 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3700 * if the fd is blocking mode.
3701 *
3702 * Examples:
3703 *
3704 * # # Returned Buffer Content Pipe Content
3705 * r, w = IO.pipe #
3706 * w << 'abc' # "" "abc".
3707 * r.readpartial(4096) # => "abc" "" ""
3708 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3709 *
3710 * # # Returned Buffer Content Pipe Content
3711 * r, w = IO.pipe #
3712 * w << 'abc' # "" "abc"
3713 * w.close # "" "abc" EOF
3714 * r.readpartial(4096) # => "abc" "" EOF
3715 * r.readpartial(4096) # raises EOFError
3716 *
3717 * # # Returned Buffer Content Pipe Content
3718 * r, w = IO.pipe #
3719 * w << "abc\ndef\n" # "" "abc\ndef\n"
3720 * r.gets # => "abc\n" "def\n" ""
3721 * w << "ghi\n" # "def\n" "ghi\n"
3722 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3723 * r.readpartial(4096) # => "ghi\n" "" ""
3724 *
3725 */
3726
3727static VALUE
3728io_readpartial(int argc, VALUE *argv, VALUE io)
3729{
3730 VALUE ret, length, str;
3731
3732 rb_scan_args(argc, argv, "11", &length, &str);
3733 ret = io_getpartial(io, length, str, 0, 0);
3734 if (NIL_P(ret))
3735 rb_eof_error();
3736 return ret;
3737}
3738
3739static VALUE
3740io_nonblock_eof(int no_exception)
3741{
3742 if (!no_exception) {
3743 rb_eof_error();
3744 }
3745 return Qnil;
3746}
3747
3748/* :nodoc: */
3749static VALUE
3750io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3751{
3752 int no_exception = !rb_bool_expected(ex, "exception", TRUE);
3753 VALUE ret = io_getpartial(io, length, str, no_exception, 1);
3754 if (NIL_P(ret))
3755 io_nonblock_eof(no_exception);
3756
3757 return ret;
3758}
3759
3760/* :nodoc: */
3761static VALUE
3762io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3763{
3764 rb_io_t *fptr;
3765 rb_len_t n;
3766
3767 if (!RB_TYPE_P(str, T_STRING))
3768 str = rb_obj_as_string(str);
3769 rb_bool_expected(ex, "exception", TRUE);
3770
3771 io = GetWriteIO(io);
3772 GetOpenFile(io, fptr);
3774
3775 if (io_fflush(fptr) < 0)
3776 rb_sys_fail_on_write(fptr);
3777
3778 rb_fd_set_nonblock(fptr->fd);
3779 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3780 RB_GC_GUARD(str);
3781
3782 if (n < 0) {
3783 int e = errno;
3784 if (io_again_p(e)) {
3785 if (!ex) {
3786 return sym_wait_writable;
3787 }
3788 else {
3789 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3790 }
3791 }
3792 rb_syserr_fail_path(e, fptr->pathv);
3793 }
3794
3795 return LEN2NUM(n);
3796}
3797
3798/*
3799 * call-seq:
3800 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3801 *
3802 * Reads bytes from the stream; the stream must be opened for reading
3803 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3804 *
3805 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3806 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3807 *
3808 * Returns a string (either a new string or the given +out_string+)
3809 * containing the bytes read.
3810 * The encoding of the string depends on both +maxLen+ and +out_string+:
3811 *
3812 * - +maxlen+ is +nil+: uses internal encoding of +self+
3813 * (regardless of whether +out_string+ was given).
3814 * - +maxlen+ not +nil+:
3815 *
3816 * - +out_string+ given: encoding of +out_string+ not modified.
3817 * - +out_string+ not given: ASCII-8BIT is used.
3818 *
3819 * <b>Without Argument +out_string+</b>
3820 *
3821 * When argument +out_string+ is omitted,
3822 * the returned value is a new string:
3823 *
3824 * f = File.new('t.txt')
3825 * f.read
3826 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3827 * f.rewind
3828 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3829 * f.read(30) # => "rth line\r\nFifth line\r\n"
3830 * f.read(30) # => nil
3831 * f.close
3832 *
3833 * If +maxlen+ is zero, returns an empty string.
3834 *
3835 * <b> With Argument +out_string+</b>
3836 *
3837 * When argument +out_string+ is given,
3838 * the returned value is +out_string+, whose content is replaced:
3839 *
3840 * f = File.new('t.txt')
3841 * s = 'foo' # => "foo"
3842 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3843 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3844 * f.rewind
3845 * s = 'bar'
3846 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3847 * s # => "First line\r\nSecond line\r\n\r\nFou"
3848 * s = 'baz'
3849 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3850 * s # => "rth line\r\nFifth line\r\n"
3851 * s = 'bat'
3852 * f.read(30, s) # => nil
3853 * s # => ""
3854 * f.close
3855 *
3856 * Note that this method behaves like the fread() function in C.
3857 * This means it retries to invoke read(2) system calls to read data
3858 * with the specified maxlen (or until EOF).
3859 *
3860 * This behavior is preserved even if the stream is in non-blocking mode.
3861 * (This method is non-blocking-flag insensitive as other methods.)
3862 *
3863 * If you need the behavior like a single read(2) system call,
3864 * consider #readpartial, #read_nonblock, and #sysread.
3865 *
3866 * Related: IO#write.
3867 */
3868
3869static VALUE
3870io_read(int argc, VALUE *argv, VALUE io)
3871{
3872 rb_io_t *fptr;
3873 rb_len_t n, len;
3874 VALUE length, str;
3875 int shrinkable;
3876#if RUBY_CRLF_ENVIRONMENT
3877 int previous_mode;
3878#endif
3879
3880 rb_scan_args(argc, argv, "02", &length, &str);
3881
3882 if (NIL_P(length)) {
3883 GetOpenFile(io, fptr);
3885 return read_all(fptr, remain_size(fptr), str);
3886 }
3887 len = NUM2LEN(length);
3888 if (len < 0) {
3889 rb_raise(rb_eArgError, "negative length %"PRIdLEN" given", len);
3890 }
3891
3892 shrinkable = io_setstrbuf(&str,len);
3893
3894 GetOpenFile(io, fptr);
3896 if (len == 0) {
3897 io_set_read_length(str, 0, shrinkable);
3898 return str;
3899 }
3900
3901 READ_CHECK(fptr);
3902#if RUBY_CRLF_ENVIRONMENT
3903 previous_mode = set_binary_mode_with_seek_cur(fptr);
3904#endif
3905 n = io_fread(str, 0, len, fptr);
3906 io_set_read_length(str, n, shrinkable);
3907#if RUBY_CRLF_ENVIRONMENT
3908 if (previous_mode == O_TEXT) {
3909 setmode(fptr->fd, O_TEXT);
3910 }
3911#endif
3912 if (n == 0) return Qnil;
3913
3914 return str;
3915}
3916
3917static void
3918rscheck(const char *rsptr, rb_len_t rslen, VALUE rs)
3919{
3920 if (!rs) return;
3921 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3922 rb_raise(rb_eRuntimeError, "rs modified");
3923}
3924
3925static const char *
3926search_delim(const char *p, rb_len_t len, int delim, rb_encoding *enc)
3927{
3928 if (rb_enc_mbminlen(enc) == 1) {
3929 p = memchr(p, delim, len);
3930 if (p) return p + 1;
3931 }
3932 else {
3933 const char *end = p + len;
3934 while (p < end) {
3935 int r = rb_enc_precise_mbclen(p, end, enc);
3936 if (!MBCLEN_CHARFOUND_P(r)) {
3937 p += rb_enc_mbminlen(enc);
3938 continue;
3939 }
3940 int n = MBCLEN_CHARFOUND_LEN(r);
3941 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3942 return p + n;
3943 }
3944 p += n;
3945 }
3946 }
3947 return NULL;
3948}
3949
3950static int
3951read_raw_character(rb_io_t *fptr, rb_encoding *enc, char *buf)
3952{
3953 int n = 0;
3954 int r;
3955
3956 do {
3957 if (!READ_DATA_PENDING(fptr)) {
3958 READ_CHECK(fptr);
3959 if (io_fillbuf(fptr) < 0) break;
3960 }
3961 buf[n++] = *READ_DATA_PENDING_PTR(fptr);
3962 fptr->rbuf.off++;
3963 fptr->rbuf.len--;
3964 r = rb_enc_precise_mbclen(buf, buf + n, enc);
3965 } while (MBCLEN_NEEDMORE_P(r) && n < rb_enc_mbmaxlen(enc));
3966
3967 return n;
3968}
3969
3970static void
3971unread_raw_character(rb_io_t *fptr, const char *buf, int len)
3972{
3973 if (fptr->rbuf.capa - fptr->rbuf.len < len) {
3974 if (fptr->rbuf.capa > INT_MAX - len)
3975 rb_raise(rb_eIOError, "ungetbyte failed");
3976 fptr->rbuf.capa += len;
3977 REALLOC_N(fptr->rbuf.ptr, char, fptr->rbuf.capa);
3978 }
3979 io_ungetbyte(rb_str_new(buf, len), fptr);
3980}
3981
3982static const char *
3983search_wide_delim(const char *p, long len, const char *delim, int width)
3984{
3985 const char *e = p + len;
3986 int index = 0;
3987
3988 while (index < width && delim[index] == 0) index++;
3989 if (index == width) index = 0;
3990
3991 const char *candidate = p + index;
3992 while (candidate < e) {
3993 candidate = memchr(candidate, (unsigned char)delim[index], e - candidate);
3994 if (candidate == NULL) break;
3995 const char *start = candidate - index;
3996 if ((start - p) % width == 0 && start + width <= e &&
3997 memcmp(start, delim, width) == 0) {
3998 return start;
3999 }
4000 candidate++;
4001 }
4002 return NULL;
4003}
4004
4005static int
4006appendline(rb_io_t *fptr, int delim, VALUE *strp, rb_len_t *lp, rb_encoding *enc)
4007{
4008 VALUE str = *strp;
4009 rb_len_t limit = *lp;
4010
4011 if (NEED_READCONV(fptr)) {
4012 SET_BINARY_MODE(fptr);
4013 make_readconv(fptr, 0);
4014 do {
4015 const char *p, *e;
4016 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
4017 if (searchlen) {
4018 p = READ_CHAR_PENDING_PTR(fptr);
4019 if (0 < limit && limit < searchlen)
4020 searchlen = (int)limit;
4021 e = search_delim(p, searchlen, delim, enc);
4022 if (e) {
4023 int len = (int)(e-p);
4024 if (NIL_P(str))
4025 *strp = str = rb_str_new(p, len);
4026 else
4027 rb_str_buf_cat(str, p, len);
4028 fptr->cbuf.off += len;
4029 fptr->cbuf.len -= len;
4030 limit -= len;
4031 *lp = limit;
4032 return delim;
4033 }
4034
4035 if (NIL_P(str))
4036 *strp = str = rb_str_new(p, searchlen);
4037 else
4038 rb_str_buf_cat(str, p, searchlen);
4039 fptr->cbuf.off += searchlen;
4040 fptr->cbuf.len -= searchlen;
4041 limit -= searchlen;
4042
4043 if (limit == 0) {
4044 *lp = limit;
4045 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4046 }
4047 }
4048 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4049 clear_readconv(fptr);
4050 *lp = limit;
4051 return EOF;
4052 }
4053
4054 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4055 if (rb_enc_mbminlen(enc) != 1) {
4056 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4057 int len;
4058
4059 if (limit < 0) {
4060 int width = rb_enc_mbminlen(enc);
4061 int delim_len = rb_enc_codelen(delim, enc);
4062
4063 if (delim_len == width) {
4064 rb_enc_mbcput(delim, buf, enc);
4065 for (;;) {
4066 if (!READ_DATA_PENDING(fptr)) {
4067 READ_CHECK(fptr);
4068 if (io_fillbuf(fptr) < 0) return EOF;
4069 }
4070 long pending = READ_DATA_PENDING_COUNT(fptr);
4071 long complete = pending - pending % width;
4072 const char *p = READ_DATA_PENDING_PTR(fptr);
4073 const char *q = complete ? search_wide_delim(p, complete, buf, width) : NULL;
4074 long take = q ? q - p + width : complete;
4075
4076 if (take > 0) {
4077 if (NIL_P(str))
4078 *strp = str = rb_str_buf_new(0);
4079 rb_str_buf_cat(str, p, take);
4080 fptr->rbuf.off += (int)take;
4081 fptr->rbuf.len -= (int)take;
4082 }
4083 if (q) return delim;
4084 if (complete == pending) continue;
4085
4086 len = read_raw_character(fptr, enc, buf);
4087 if (len == 0) return EOF;
4088 if (NIL_P(str))
4089 *strp = str = rb_str_buf_new(0);
4090 rb_str_buf_cat(str, buf, len);
4091 int r = rb_enc_precise_mbclen(buf, buf + len, enc);
4092 if (MBCLEN_CHARFOUND_P(r) &&
4093 rb_enc_mbc_to_codepoint(buf, buf + len, enc) == (unsigned int)delim)
4094 return delim;
4095 }
4096 }
4097 }
4098
4099 while ((len = read_raw_character(fptr, enc, buf)) > 0) {
4100 if (NIL_P(str))
4101 *strp = str = rb_str_buf_new(0);
4102 rb_str_buf_cat(str, buf, len);
4103 if (limit > 0) {
4104 if (len > limit) {
4105 *lp = 0;
4106 return (unsigned char)buf[len - 1];
4107 }
4108 *lp = limit -= len;
4109 }
4110 int r = rb_enc_precise_mbclen(buf, buf + len, enc);
4111 if (MBCLEN_CHARFOUND_P(r) &&
4112 rb_enc_mbc_to_codepoint(buf, buf + len, enc) == (unsigned int)delim)
4113 return delim;
4114 if (limit == 0)
4115 return (unsigned char)buf[len - 1];
4116 }
4117 *lp = limit;
4118 return EOF;
4119 }
4120 do {
4121 rb_len_t pending = READ_DATA_PENDING_COUNT(fptr);
4122 if (pending > 0) {
4123 const char *p = READ_DATA_PENDING_PTR(fptr);
4124 const char *e;
4125 rb_len_t last;
4126
4127 if (limit > 0 && pending > limit) pending = limit;
4128 e = search_delim(p, pending, delim, enc);
4129 if (e) pending = e - p;
4130 if (!NIL_P(str)) {
4131 last = RSTRING_LEN(str);
4132 rb_str_resize(str, last + pending);
4133 }
4134 else {
4135 last = 0;
4136 *strp = str = rb_str_buf_new(pending);
4137 rb_str_set_len(str, pending);
4138 }
4139 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
4140 limit -= pending;
4141 *lp = limit;
4142 if (e) return delim;
4143 if (limit == 0)
4144 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4145 }
4146 READ_CHECK(fptr);
4147 } while (io_fillbuf(fptr) >= 0);
4148 *lp = limit;
4149 return EOF;
4150}
4151
4152static inline int
4153swallow(rb_io_t *fptr, int term)
4154{
4155 if (NEED_READCONV(fptr)) {
4156 rb_encoding *enc = io_read_encoding(fptr);
4157 int needconv = rb_enc_mbminlen(enc) != 1;
4158 SET_BINARY_MODE(fptr);
4159 make_readconv(fptr, 0);
4160 do {
4161 size_t cnt;
4162 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4163 const char *p = READ_CHAR_PENDING_PTR(fptr);
4164 int i;
4165 if (!needconv) {
4166 if (*p != term) return TRUE;
4167 i = (int)cnt;
4168 while (--i && *++p == term);
4169 }
4170 else {
4171 const char *e = p + cnt;
4172 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
4173 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4174 i = (int)(e - p);
4175 }
4176 io_shift_cbuf(fptr, (int)cnt - i, NULL);
4177 }
4178 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4179 return FALSE;
4180 }
4181
4182 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4183 rb_encoding *enc = io_read_encoding(fptr);
4184 int widechar = rb_enc_mbminlen(enc) != 1;
4185 if (widechar) {
4186 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4187 int len;
4188
4189 while ((len = read_raw_character(fptr, enc, buf)) > 0) {
4190 if (rb_enc_ascget(buf, buf + len, NULL, enc) != term) {
4191 unread_raw_character(fptr, buf, len);
4192 return TRUE;
4193 }
4194 }
4195 return FALSE;
4196 }
4197 do {
4198 size_t cnt;
4199 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4200 char buf[1024];
4201 const char *p = READ_DATA_PENDING_PTR(fptr);
4202 int i;
4203 if (cnt > sizeof buf) cnt = sizeof buf;
4204 if (*p != term) return TRUE;
4205 i = (int)cnt;
4206 while (--i && *++p == term);
4207 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4208 rb_sys_fail_path(fptr->pathv);
4209 }
4210 READ_CHECK(fptr);
4211 } while (io_fillbuf(fptr) == 0);
4212 return FALSE;
4213}
4214
4215static VALUE
4216rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4217{
4218 VALUE str = Qnil;
4219 rb_len_t len = 0;
4220 rb_len_t pos = 0;
4221 int cr = 0;
4222
4223 do {
4224 int pending = READ_DATA_PENDING_COUNT(fptr);
4225
4226 if (pending > 0) {
4227 const char *p = READ_DATA_PENDING_PTR(fptr);
4228 const char *e;
4229 int chomplen = 0;
4230
4231 e = memchr(p, '\n', pending);
4232 if (e) {
4233 pending = (int)(e - p + 1);
4234 if (chomp) {
4235 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4236 }
4237 }
4238 if (NIL_P(str)) {
4239 str = rb_str_new(p, pending - chomplen);
4240 fptr->rbuf.off += pending;
4241 fptr->rbuf.len -= pending;
4242 }
4243 else {
4244 rb_str_resize(str, len + pending - chomplen);
4245 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4246 fptr->rbuf.off += chomplen;
4247 fptr->rbuf.len -= chomplen;
4248 if (pending == 1 && chomplen == 1 && len > 0) {
4249 if (RSTRING_PTR(str)[len-1] == '\r') {
4250 rb_str_resize(str, --len);
4251 break;
4252 }
4253 }
4254 }
4255 len += pending - chomplen;
4256 if (cr != ENC_CODERANGE_BROKEN)
4257 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4258 if (e) break;
4259 }
4260 READ_CHECK(fptr);
4261 } while (io_fillbuf(fptr) >= 0);
4262 if (NIL_P(str)) return Qnil;
4263
4264 str = io_enc_str(str, fptr);
4265 ENC_CODERANGE_SET(str, cr);
4266 fptr->lineno++;
4267
4268 return str;
4269}
4270
4272 VALUE io;
4273 VALUE rs;
4274 rb_len_t limit;
4275 unsigned int chomp: 1;
4276};
4277
4278static void
4279extract_getline_opts(VALUE opts, struct getline_arg *args)
4280{
4281 int chomp = FALSE;
4282 if (!NIL_P(opts)) {
4283 static ID kwds[1];
4284 VALUE vchomp;
4285 if (!kwds[0]) {
4286 kwds[0] = rb_intern_const("chomp");
4287 }
4288 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4289 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4290 }
4291 args->chomp = chomp;
4292}
4293
4294static void
4295extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4296{
4297 VALUE rs = rb_rs, lim = Qnil;
4298
4299 if (argc == 1) {
4300 VALUE tmp = Qnil;
4301
4302 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4303 rs = tmp;
4304 }
4305 else {
4306 lim = argv[0];
4307 }
4308 }
4309 else if (2 <= argc) {
4310 rs = argv[0], lim = argv[1];
4311 if (!NIL_P(rs))
4312 StringValue(rs);
4313 }
4314 args->rs = rs;
4315 args->limit = NIL_P(lim) ? -1L : NUM2LEN(lim);
4316}
4317
4318static void
4319check_getline_args(VALUE *rsp, rb_len_t *limit, VALUE io)
4320{
4321 rb_io_t *fptr;
4322 VALUE rs = *rsp;
4323
4324 if (!NIL_P(rs)) {
4325 rb_encoding *enc_rs, *enc_io;
4326
4327 GetOpenFile(io, fptr);
4328 enc_rs = rb_enc_get(rs);
4329 enc_io = io_read_encoding(fptr);
4330 if (enc_io != enc_rs &&
4331 (!is_ascii_string(rs) ||
4332 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4333 if (rs == rb_default_rs) {
4334 rs = rb_enc_str_new(0, 0, enc_io);
4335 rb_str_buf_cat_ascii(rs, "\n");
4336 *rsp = rs;
4337 }
4338 else {
4339 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4340 rb_enc_name(enc_io),
4341 rb_enc_name(enc_rs));
4342 }
4343 }
4344 }
4345}
4346
4347static void
4348prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4349{
4350 VALUE opts;
4351 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4352 extract_getline_args(argc, argv, args);
4353 extract_getline_opts(opts, args);
4354 check_getline_args(&args->rs, &args->limit, io);
4355}
4356
4357static VALUE
4358rb_io_getline_0(VALUE rs, rb_len_t limit, int chomp, rb_io_t *fptr)
4359{
4360 VALUE str = Qnil;
4361 int nolimit = 0;
4362 rb_encoding *enc;
4363
4365 if (NIL_P(rs) && limit < 0) {
4366 str = read_all(fptr, 0, Qnil);
4367 if (RSTRING_LEN(str) == 0) return Qnil;
4368 }
4369 else if (limit == 0) {
4370 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4371 }
4372 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4373 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4374 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4375 return rb_io_getline_fast(fptr, enc, chomp);
4376 }
4377 else {
4378 int c, newline = -1;
4379 const char *rsptr = 0;
4380 rb_len_t rslen = 0;
4381 int rspara = 0;
4382 int extra_limit = 16;
4383 int chomp_cr = chomp;
4384
4385 SET_BINARY_MODE(fptr);
4386 enc = io_read_encoding(fptr);
4387
4388 if (!NIL_P(rs)) {
4389 rslen = RSTRING_LEN(rs);
4390 if (rslen == 0) {
4391 rsptr = "\n\n";
4392 rslen = 2;
4393 rspara = 1;
4394 swallow(fptr, '\n');
4395 rs = 0;
4396 if (!rb_enc_asciicompat(enc)) {
4397 rs = rb_usascii_str_new(rsptr, rslen);
4398 rs = rb_str_conv_enc(rs, 0, enc);
4399 OBJ_FREEZE(rs);
4400 rsptr = RSTRING_PTR(rs);
4401 rslen = RSTRING_LEN(rs);
4402 }
4403 newline = '\n';
4404 }
4405 else if (rb_enc_mbminlen(enc) == 1) {
4406 rsptr = RSTRING_PTR(rs);
4407 newline = (unsigned char)rsptr[rslen - 1];
4408 }
4409 else {
4410 rs = rb_str_conv_enc(rs, 0, enc);
4411 rsptr = RSTRING_PTR(rs);
4412 const char *e = rsptr + rslen;
4413 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4414 int n;
4415 newline = rb_enc_codepoint_len(last, e, &n, enc);
4416 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4417 }
4418 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4419 }
4420
4421 /* MS - Optimization */
4422 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4423 const char *s, *p, *pp, *e;
4424
4425 if (c == newline && RSTRING_LEN(str) >= rslen) {
4426 s = RSTRING_PTR(str);
4427 e = RSTRING_END(str);
4428 p = e - rslen;
4429 if (at_char_boundary(s, p, e, enc)) {
4430 if (!rspara) rscheck(rsptr, rslen, rs);
4431 if (memcmp(p, rsptr, rslen) == 0) {
4432 if (chomp) {
4433 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4434 rb_str_set_len(str, p - s);
4435 }
4436 break;
4437 }
4438 }
4439 }
4440 if (limit == 0) {
4441 s = RSTRING_PTR(str);
4442 p = RSTRING_END(str);
4443 pp = rb_enc_prev_char(s, p, p, enc);
4444 if (extra_limit && pp &&
4445 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4446 /* relax the limit while incomplete character.
4447 * extra_limit limits the relax length */
4448 limit = 1;
4449 extra_limit--;
4450 }
4451 else {
4452 nolimit = 1;
4453 break;
4454 }
4455 }
4456 }
4457
4458 if (rspara && c != EOF)
4459 swallow(fptr, '\n');
4460 if (!NIL_P(str))
4461 str = io_enc_str(str, fptr);
4462 }
4463
4464 if (!NIL_P(str) && !nolimit) {
4465 fptr->lineno++;
4466 }
4467
4468 return str;
4469}
4470
4471static VALUE
4472rb_io_getline_1(VALUE rs, rb_len_t limit, int chomp, VALUE io)
4473{
4474 rb_io_t *fptr;
4475 int old_lineno, new_lineno;
4476 VALUE str;
4477
4478 GetOpenFile(io, fptr);
4479 old_lineno = fptr->lineno;
4480 str = rb_io_getline_0(rs, limit, chomp, fptr);
4481 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4482 if (io == ARGF.current_file) {
4483 ARGF.lineno += new_lineno - old_lineno;
4484 ARGF.last_lineno = ARGF.lineno;
4485 }
4486 else {
4487 ARGF.last_lineno = new_lineno;
4488 }
4489 }
4490
4491 return str;
4492}
4493
4494static VALUE
4495rb_io_getline(int argc, VALUE *argv, VALUE io)
4496{
4497 struct getline_arg args;
4498
4499 prepare_getline_args(argc, argv, &args, io);
4500 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4501}
4502
4503VALUE
4505{
4506 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4507}
4508
4509VALUE
4510rb_io_gets_limit_internal(VALUE io, rb_len_t limit)
4511{
4512 rb_io_t *fptr;
4513 GetOpenFile(io, fptr);
4514 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4515}
4516
4517VALUE
4518rb_io_gets_internal(VALUE io)
4519{
4520 return rb_io_gets_limit_internal(io, -1);
4521}
4522
4523/*
4524 * call-seq:
4525 * gets(sep = $/, chomp: false) -> string or nil
4526 * gets(limit, chomp: false) -> string or nil
4527 * gets(sep, limit, chomp: false) -> string or nil
4528 *
4529 * Reads and returns a line from the stream;
4530 * assigns the return value to <tt>$_</tt>.
4531 * See {Line IO}[rdoc-ref:IO@Line+IO].
4532 *
4533 * With no arguments given, returns the next line
4534 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4535 *
4536 * f = File.open('t.txt')
4537 * f.gets # => "First line\n"
4538 * $_ # => "First line\n"
4539 * f.gets # => "\n"
4540 * f.gets # => "Fourth line\n"
4541 * f.gets # => "Fifth line\n"
4542 * f.gets # => nil
4543 * f.close
4544 *
4545 * With only string argument +sep+ given,
4546 * returns the next line as determined by line separator +sep+,
4547 * or +nil+ if none;
4548 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4549 *
4550 * f = File.new('t.txt')
4551 * f.gets('l') # => "First l"
4552 * f.gets('li') # => "ine\nSecond li"
4553 * f.gets('lin') # => "ne\n\nFourth lin"
4554 * f.gets # => "e\n"
4555 * f.close
4556 *
4557 * The two special values for +sep+ are honored:
4558 *
4559 * f = File.new('t.txt')
4560 * # Get all.
4561 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4562 * f.rewind
4563 * # Get paragraph (up to two line separators).
4564 * f.gets('') # => "First line\nSecond line\n\n"
4565 * f.close
4566 *
4567 * With only integer argument +limit+ given,
4568 * limits the number of bytes in the line;
4569 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4570 *
4571 * # No more than one line.
4572 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4573 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4574 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4575 *
4576 * With arguments +sep+ and +limit+ given,
4577 * combines the two behaviors
4578 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4579 *
4580 * Optional keyword argument +chomp+ specifies whether line separators
4581 * are to be omitted:
4582 *
4583 * f = File.open('t.txt')
4584 * # Chomp the lines.
4585 * f.gets(chomp: true) # => "First line"
4586 * f.gets(chomp: true) # => "Second line"
4587 * f.gets(chomp: true) # => ""
4588 * f.gets(chomp: true) # => "Fourth line"
4589 * f.gets(chomp: true) # => "Fifth line"
4590 * f.gets(chomp: true) # => nil
4591 * f.close
4592 *
4593 */
4594
4595static VALUE
4596rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4597{
4598 VALUE str;
4599
4600 str = rb_io_getline(argc, argv, io);
4601 rb_lastline_set(str);
4602
4603 return str;
4604}
4605
4606/*
4607 * call-seq:
4608 * lineno -> integer
4609 *
4610 * Returns the current line number for the stream;
4611 * see {Line Number}[rdoc-ref:IO@Line+Number].
4612 *
4613 */
4614
4615static VALUE
4616rb_io_lineno(VALUE io)
4617{
4618 rb_io_t *fptr;
4619
4620 GetOpenFile(io, fptr);
4622 return INT2NUM(fptr->lineno);
4623}
4624
4625/*
4626 * call-seq:
4627 * lineno = integer -> integer
4628 *
4629 * Sets and returns the line number for the stream;
4630 * see {Line Number}[rdoc-ref:IO@Line+Number].
4631 *
4632 */
4633
4634static VALUE
4635rb_io_set_lineno(VALUE io, VALUE lineno)
4636{
4637 rb_io_t *fptr;
4638
4639 GetOpenFile(io, fptr);
4641 fptr->lineno = NUM2INT(lineno);
4642 return lineno;
4643}
4644
4645/* :nodoc: */
4646static VALUE
4647io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4648{
4649 rb_len_t limit = -1;
4650 if (NIL_P(lim)) {
4651 VALUE tmp = Qnil;
4652 // If sep is specified, but it's not a string and not nil, then assume
4653 // it's the limit (it should be an integer)
4654 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4655 // If the user has specified a non-nil / non-string value
4656 // for the separator, we assume it's the limit and set the
4657 // separator to default: rb_rs.
4658 lim = sep;
4659 limit = NUM2LEN(lim);
4660 sep = rb_rs;
4661 }
4662 else {
4663 sep = tmp;
4664 }
4665 }
4666 else {
4667 if (!NIL_P(sep)) StringValue(sep);
4668 limit = NUM2LEN(lim);
4669 }
4670
4671 check_getline_args(&sep, &limit, io);
4672
4673 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4674 rb_lastline_set_up(line, 1);
4675
4676 if (NIL_P(line)) {
4677 rb_eof_error();
4678 }
4679 return line;
4680}
4681
4682static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4683
4684/*
4685 * call-seq:
4686 * readlines(sep = $/, chomp: false) -> array
4687 * readlines(limit, chomp: false) -> array
4688 * readlines(sep, limit, chomp: false) -> array
4689 *
4690 * Reads and returns all remaining line from the stream;
4691 * does not modify <tt>$_</tt>.
4692 * See {Line IO}[rdoc-ref:IO@Line+IO].
4693 *
4694 * With no arguments given, returns lines
4695 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4696 *
4697 * f = File.new('t.txt')
4698 * f.readlines
4699 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4700 * f.readlines # => []
4701 * f.close
4702 *
4703 * With only string argument +sep+ given,
4704 * returns lines as determined by line separator +sep+,
4705 * or +nil+ if none;
4706 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4707 *
4708 * f = File.new('t.txt')
4709 * f.readlines('li')
4710 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4711 * f.close
4712 *
4713 * The two special values for +sep+ are honored:
4714 *
4715 * f = File.new('t.txt')
4716 * # Get all into one string.
4717 * f.readlines(nil)
4718 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4719 * # Get paragraphs (up to two line separators).
4720 * f.rewind
4721 * f.readlines('')
4722 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4723 * f.close
4724 *
4725 * With only integer argument +limit+ given,
4726 * limits the number of bytes in each line;
4727 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4728 *
4729 * f = File.new('t.txt')
4730 * f.readlines(8)
4731 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4732 * f.close
4733 *
4734 * With arguments +sep+ and +limit+ given,
4735 * combines the two behaviors
4736 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4737 *
4738 * Optional keyword argument +chomp+ specifies whether line separators
4739 * are to be omitted:
4740 *
4741 * f = File.new('t.txt')
4742 * f.readlines(chomp: true)
4743 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4744 * f.close
4745 *
4746 */
4747
4748static VALUE
4749rb_io_readlines(int argc, VALUE *argv, VALUE io)
4750{
4751 struct getline_arg args;
4752
4753 prepare_getline_args(argc, argv, &args, io);
4754 return io_readlines(&args, io);
4755}
4756
4757static VALUE
4758io_readlines(const struct getline_arg *arg, VALUE io)
4759{
4760 VALUE line, ary;
4761
4762 if (arg->limit == 0)
4763 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4764 ary = rb_ary_new();
4765 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4766 rb_ary_push(ary, line);
4767 }
4768 return ary;
4769}
4770
4771/*
4772 * call-seq:
4773 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4774 * each_line(limit, chomp: false) {|line| ... } -> self
4775 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4776 * each_line -> enumerator
4777 *
4778 * Calls the block with each remaining line read from the stream;
4779 * returns +self+.
4780 * Does nothing if already at end-of-stream;
4781 * See {Line IO}[rdoc-ref:IO@Line+IO].
4782 *
4783 * With no arguments given, reads lines
4784 * as determined by line separator <tt>$/</tt>:
4785 *
4786 * f = File.new('t.txt')
4787 * f.each_line {|line| p line }
4788 * f.each_line {|line| fail 'Cannot happen' }
4789 * f.close
4790 *
4791 * Output:
4792 *
4793 * "First line\n"
4794 * "Second line\n"
4795 * "\n"
4796 * "Fourth line\n"
4797 * "Fifth line\n"
4798 *
4799 * With only string argument +sep+ given,
4800 * reads lines as determined by line separator +sep+;
4801 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4802 *
4803 * f = File.new('t.txt')
4804 * f.each_line('li') {|line| p line }
4805 * f.close
4806 *
4807 * Output:
4808 *
4809 * "First li"
4810 * "ne\nSecond li"
4811 * "ne\n\nFourth li"
4812 * "ne\nFifth li"
4813 * "ne\n"
4814 *
4815 * The two special values for +sep+ are honored:
4816 *
4817 * f = File.new('t.txt')
4818 * # Get all into one string.
4819 * f.each_line(nil) {|line| p line }
4820 * f.close
4821 *
4822 * Output:
4823 *
4824 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4825 *
4826 * f.rewind
4827 * # Get paragraphs (up to two line separators).
4828 * f.each_line('') {|line| p line }
4829 *
4830 * Output:
4831 *
4832 * "First line\nSecond line\n\n"
4833 * "Fourth line\nFifth line\n"
4834 *
4835 * With only integer argument +limit+ given,
4836 * limits the number of bytes in each line;
4837 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4838 *
4839 * f = File.new('t.txt')
4840 * f.each_line(8) {|line| p line }
4841 * f.close
4842 *
4843 * Output:
4844 *
4845 * "First li"
4846 * "ne\n"
4847 * "Second l"
4848 * "ine\n"
4849 * "\n"
4850 * "Fourth l"
4851 * "ine\n"
4852 * "Fifth li"
4853 * "ne\n"
4854 *
4855 * With arguments +sep+ and +limit+ given,
4856 * combines the two behaviors
4857 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4858 *
4859 * Optional keyword argument +chomp+ specifies whether line separators
4860 * are to be omitted:
4861 *
4862 * f = File.new('t.txt')
4863 * f.each_line(chomp: true) {|line| p line }
4864 * f.close
4865 *
4866 * Output:
4867 *
4868 * "First line"
4869 * "Second line"
4870 * ""
4871 * "Fourth line"
4872 * "Fifth line"
4873 *
4874 * Returns an Enumerator if no block is given.
4875 */
4876
4877static VALUE
4878rb_io_each_line(int argc, VALUE *argv, VALUE io)
4879{
4880 VALUE str;
4881 struct getline_arg args;
4882
4883 RETURN_ENUMERATOR(io, argc, argv);
4884 prepare_getline_args(argc, argv, &args, io);
4885 if (args.limit == 0)
4886 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4887 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4888 rb_yield(str);
4889 }
4890 return io;
4891}
4892
4893/*
4894 * call-seq:
4895 * each_byte {|byte| ... } -> self
4896 * each_byte -> enumerator
4897 *
4898 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4899 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4900 *
4901 * File.read('t.ja') # => "こんにちは"
4902 * f = File.new('t.ja')
4903 * a = []
4904 * f.each_byte {|b| a << b }
4905 * a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
4906 * f.close
4907 *
4908 * Returns an Enumerator if no block is given.
4909 *
4910 * Related: IO#each_char, IO#each_codepoint.
4911 *
4912 */
4913
4914static VALUE
4915rb_io_each_byte(VALUE io)
4916{
4917 rb_io_t *fptr;
4918
4919 RETURN_ENUMERATOR(io, 0, 0);
4920 GetOpenFile(io, fptr);
4921
4922 do {
4923 while (fptr->rbuf.len > 0) {
4924 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4925 fptr->rbuf.len--;
4926 rb_yield(INT2FIX(*p & 0xff));
4928 errno = 0;
4929 }
4930 READ_CHECK(fptr);
4931 } while (io_fillbuf(fptr) >= 0);
4932 return io;
4933}
4934
4935static VALUE
4936io_getc(rb_io_t *fptr, rb_encoding *enc)
4937{
4938 int r, n, cr = 0;
4939 VALUE str;
4940
4941 if (NEED_READCONV(fptr)) {
4942 rb_encoding *read_enc = io_read_encoding(fptr);
4943
4944 str = Qnil;
4945 SET_BINARY_MODE(fptr);
4946 make_readconv(fptr, 0);
4947
4948 while (1) {
4949 if (fptr->cbuf.len) {
4950 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4951 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4952 read_enc);
4953 if (!MBCLEN_NEEDMORE_P(r))
4954 break;
4955 if (fptr->cbuf.len == fptr->cbuf.capa) {
4956 rb_raise(rb_eIOError, "too long character");
4957 }
4958 }
4959
4960 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4961 if (fptr->cbuf.len == 0) {
4962 clear_readconv(fptr);
4963 return Qnil;
4964 }
4965 /* return an unit of an incomplete character just before EOF */
4966 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4967 fptr->cbuf.off += 1;
4968 fptr->cbuf.len -= 1;
4969 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4971 return str;
4972 }
4973 }
4974 if (MBCLEN_INVALID_P(r)) {
4975 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4976 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4977 read_enc);
4978 io_shift_cbuf(fptr, r, &str);
4980 }
4981 else {
4982 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4984 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4985 ISASCII(RSTRING_PTR(str)[0])) {
4986 cr = ENC_CODERANGE_7BIT;
4987 }
4988 }
4989 str = io_enc_str(str, fptr);
4990 ENC_CODERANGE_SET(str, cr);
4991 return str;
4992 }
4993
4994 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4995 if (io_fillbuf(fptr) < 0) {
4996 return Qnil;
4997 }
4998 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4999 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
5000 fptr->rbuf.off += 1;
5001 fptr->rbuf.len -= 1;
5002 cr = ENC_CODERANGE_7BIT;
5003 }
5004 else {
5005 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5006 if (MBCLEN_CHARFOUND_P(r) &&
5007 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
5008 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
5009 fptr->rbuf.off += n;
5010 fptr->rbuf.len -= n;
5012 }
5013 else if (MBCLEN_NEEDMORE_P(r)) {
5014 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
5015 fptr->rbuf.len = 0;
5016 getc_needmore:
5017 if (io_fillbuf(fptr) != -1) {
5018 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
5019 fptr->rbuf.off++;
5020 fptr->rbuf.len--;
5021 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
5022 if (MBCLEN_NEEDMORE_P(r)) {
5023 goto getc_needmore;
5024 }
5025 else if (MBCLEN_CHARFOUND_P(r)) {
5027 }
5028 }
5029 }
5030 else {
5031 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
5032 fptr->rbuf.off++;
5033 fptr->rbuf.len--;
5034 }
5035 }
5036 if (!cr) cr = ENC_CODERANGE_BROKEN;
5037 str = io_enc_str(str, fptr);
5038 ENC_CODERANGE_SET(str, cr);
5039 return str;
5040}
5041
5042/*
5043 * call-seq:
5044 * each_char {|c| ... } -> self
5045 * each_char -> enumerator
5046 *
5047 * Calls the given block with each character in the stream; returns +self+.
5048 * See {Character IO}[rdoc-ref:IO@Character+IO].
5049 *
5050 * File.read('t.ja') # => "こんにちは"
5051 * f = File.new('t.ja')
5052 * a = []
5053 * f.each_char {|c| a << c.ord }
5054 * a # => [12371, 12435, 12395, 12385, 12399]
5055 * f.close
5056 *
5057 * Returns an Enumerator if no block is given.
5058 *
5059 * Related: IO#each_byte, IO#each_codepoint.
5060 *
5061 */
5062
5063static VALUE
5064rb_io_each_char(VALUE io)
5065{
5066 rb_io_t *fptr;
5067 rb_encoding *enc;
5068 VALUE c;
5069
5070 RETURN_ENUMERATOR(io, 0, 0);
5071 GetOpenFile(io, fptr);
5073
5074 enc = io_input_encoding(fptr);
5075 READ_CHECK(fptr);
5076 while (!NIL_P(c = io_getc(fptr, enc))) {
5077 rb_yield(c);
5078 }
5079 return io;
5080}
5081
5082/*
5083 * call-seq:
5084 * each_codepoint {|c| ... } -> self
5085 * each_codepoint -> enumerator
5086 *
5087 * Calls the given block with each codepoint in the stream; returns +self+:
5088 *
5089 * File.read('t.ja') # => "こんにちは"
5090 * f = File.new('t.ja')
5091 * a = []
5092 * f.each_codepoint {|c| a << c }
5093 * a # => [12371, 12435, 12395, 12385, 12399]
5094 * f.close
5095 *
5096 * Returns an Enumerator if no block is given.
5097 *
5098 * Related: IO#each_byte, IO#each_char.
5099 *
5100 */
5101
5102static VALUE
5103rb_io_each_codepoint(VALUE io)
5104{
5105 rb_io_t *fptr;
5106 rb_encoding *enc;
5107 unsigned int c;
5108 int r, n;
5109
5110 RETURN_ENUMERATOR(io, 0, 0);
5111 GetOpenFile(io, fptr);
5113
5114 READ_CHECK(fptr);
5115 enc = io_read_encoding(fptr);
5116 if (NEED_READCONV(fptr)) {
5117 SET_BINARY_MODE(fptr);
5118 r = 1; /* no invalid char yet */
5119 for (;;) {
5120 make_readconv(fptr, 0);
5121 for (;;) {
5122 if (fptr->cbuf.len) {
5123 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
5124 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5125 enc);
5126 if (!MBCLEN_NEEDMORE_P(r))
5127 break;
5128 if (fptr->cbuf.len == fptr->cbuf.capa) {
5129 rb_raise(rb_eIOError, "too long character");
5130 }
5131 }
5132 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5133 clear_readconv(fptr);
5134 if (!MBCLEN_CHARFOUND_P(r)) {
5135 goto invalid;
5136 }
5137 return io;
5138 }
5139 }
5140 if (MBCLEN_INVALID_P(r)) {
5141 goto invalid;
5142 }
5143 n = MBCLEN_CHARFOUND_LEN(r);
5144 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
5145 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5146 enc);
5147 fptr->cbuf.off += n;
5148 fptr->cbuf.len -= n;
5149 rb_yield(UINT2NUM(c));
5151 }
5152 }
5153 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5154 while (io_fillbuf(fptr) >= 0) {
5155 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
5156 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5157 if (MBCLEN_CHARFOUND_P(r) &&
5158 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
5159 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
5160 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5161 fptr->rbuf.off += n;
5162 fptr->rbuf.len -= n;
5163 rb_yield(UINT2NUM(c));
5164 }
5165 else if (MBCLEN_INVALID_P(r)) {
5166 goto invalid;
5167 }
5168 else if (MBCLEN_NEEDMORE_P(r)) {
5169 char cbuf[8], *p = cbuf;
5170 int more = MBCLEN_NEEDMORE_LEN(r);
5171 if (more > numberof(cbuf)) goto invalid;
5172 more += n = fptr->rbuf.len;
5173 if (more > numberof(cbuf)) goto invalid;
5174 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
5175 (p += n, (more -= n) > 0)) {
5176 if (io_fillbuf(fptr) < 0) goto invalid;
5177 if ((n = fptr->rbuf.len) > more) n = more;
5178 }
5179 r = rb_enc_precise_mbclen(cbuf, p, enc);
5180 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
5181 c = rb_enc_codepoint(cbuf, p, enc);
5182 rb_yield(UINT2NUM(c));
5183 }
5184 else {
5185 continue;
5186 }
5188 }
5189 return io;
5190
5191 invalid:
5192 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
5194}
5195
5196/*
5197 * call-seq:
5198 * getc -> character or nil
5199 *
5200 * Reads and returns the next 1-character string from the stream;
5201 * returns +nil+ if already at end-of-stream.
5202 * See {Character IO}[rdoc-ref:IO@Character+IO].
5203 *
5204 * f = File.open('t.txt')
5205 * f.getc # => "F"
5206 * f.close
5207 * File.read('t.ja') # => "こんにちは"
5208 * f = File.open('t.ja')
5209 * f.getc.ord # => 12371
5210 * f.close
5211 *
5212 * Related: IO#readchar (may raise EOFError).
5213 *
5214 */
5215
5216static VALUE
5217rb_io_getc(VALUE io)
5218{
5219 rb_io_t *fptr;
5220 rb_encoding *enc;
5221
5222 GetOpenFile(io, fptr);
5224
5225 enc = io_input_encoding(fptr);
5226 READ_CHECK(fptr);
5227 return io_getc(fptr, enc);
5228}
5229
5230/*
5231 * call-seq:
5232 * readchar -> string
5233 *
5234 * Reads and returns the next 1-character string from the stream;
5235 * raises EOFError if already at end-of-stream.
5236 * See {Character IO}[rdoc-ref:IO@Character+IO].
5237 *
5238 * f = File.open('t.txt')
5239 * f.readchar # => "F"
5240 * f.close
5241 * File.read('t.ja') # => "こんにちは"
5242 * f = File.open('t.ja')
5243 * f.readchar.ord # => 12371
5244 * f.close
5245 *
5246 * Related: IO#getc (will not raise EOFError).
5247 *
5248 */
5249
5250static VALUE
5251rb_io_readchar(VALUE io)
5252{
5253 VALUE c = rb_io_getc(io);
5254
5255 if (NIL_P(c)) {
5256 rb_eof_error();
5257 }
5258 return c;
5259}
5260
5261/*
5262 * call-seq:
5263 * getbyte -> integer or nil
5264 *
5265 * Reads and returns the next byte (in range 0..255) from the stream;
5266 * returns +nil+ if already at end-of-stream.
5267 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5268 *
5269 * f = File.open('t.txt')
5270 * f.getbyte # => 70
5271 * f.close
5272 * File.read('t.ja') # => "こんにちは"
5273 * f = File.open('t.ja')
5274 * f.getbyte # => 227
5275 * f.close
5276 *
5277 * Related: IO#readbyte (may raise EOFError).
5278 */
5279
5280VALUE
5282{
5283 rb_io_t *fptr;
5284 int c;
5285
5286 GetOpenFile(io, fptr);
5288 READ_CHECK(fptr);
5289 VALUE r_stdout = rb_ractor_stdout();
5290 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5291 rb_io_t *ofp;
5292 GetOpenFile(r_stdout, ofp);
5293 if (ofp->mode & FMODE_TTY) {
5294 rb_io_flush(r_stdout);
5295 }
5296 }
5297 if (io_fillbuf(fptr) < 0) {
5298 return Qnil;
5299 }
5300 fptr->rbuf.off++;
5301 fptr->rbuf.len--;
5302 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5303 return INT2FIX(c & 0xff);
5304}
5305
5306/*
5307 * call-seq:
5308 * readbyte -> integer
5309 *
5310 * Reads and returns the next byte (in range 0..255) from the stream;
5311 * raises EOFError if already at end-of-stream.
5312 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5313 *
5314 * f = File.open('t.txt')
5315 * f.readbyte # => 70
5316 * f.close
5317 * File.read('t.ja') # => "こんにちは"
5318 * f = File.open('t.ja')
5319 * f.readbyte # => 227
5320 * f.close
5321 *
5322 * Related: IO#getbyte (will not raise EOFError).
5323 *
5324 */
5325
5326static VALUE
5327rb_io_readbyte(VALUE io)
5328{
5329 VALUE c = rb_io_getbyte(io);
5330
5331 if (NIL_P(c)) {
5332 rb_eof_error();
5333 }
5334 return c;
5335}
5336
5337/*
5338 * call-seq:
5339 * ungetbyte(integer) -> nil
5340 * ungetbyte(string) -> nil
5341 *
5342 * Pushes back ("unshifts") the given data onto the stream's buffer,
5343 * placing the data so that it is next to be read; returns +nil+.
5344 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5345 *
5346 * Note that:
5347 *
5348 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5349 * - Calling #rewind on the stream discards the pushed-back data.
5350 *
5351 * When argument +integer+ is given, uses only its low-order byte:
5352 *
5353 * File.write('t.tmp', '012')
5354 * f = File.open('t.tmp')
5355 * f.ungetbyte(0x41) # => nil
5356 * f.read # => "A012"
5357 * f.rewind
5358 * f.ungetbyte(0x4243) # => nil
5359 * f.read # => "C012"
5360 * f.close
5361 *
5362 * When argument +string+ is given, uses all bytes:
5363 *
5364 * File.write('t.tmp', '012')
5365 * f = File.open('t.tmp')
5366 * f.ungetbyte('A') # => nil
5367 * f.read # => "A012"
5368 * f.rewind
5369 * f.ungetbyte('BCDE') # => nil
5370 * f.read # => "BCDE012"
5371 * f.close
5372 *
5373 */
5374
5375VALUE
5377{
5378 rb_io_t *fptr;
5379
5380 GetOpenFile(io, fptr);
5382 switch (TYPE(b)) {
5383 case T_NIL:
5384 return Qnil;
5385 case T_FIXNUM:
5386 case T_BIGNUM: ;
5387 VALUE v = rb_int_modulo(b, INT2FIX(256));
5388 unsigned char c = NUM2INT(v) & 0xFF;
5389 b = rb_str_new((const char *)&c, 1);
5390 break;
5391 default:
5392 StringValue(b);
5393 }
5394 io_ungetbyte(b, fptr);
5395 return Qnil;
5396}
5397
5398/*
5399 * call-seq:
5400 * ungetc(integer) -> nil
5401 * ungetc(string) -> nil
5402 *
5403 * Pushes back ("unshifts") the given data onto the stream's buffer,
5404 * placing the data so that it is next to be read; returns +nil+.
5405 * See {Character IO}[rdoc-ref:IO@Character+IO].
5406 *
5407 * Note that:
5408 *
5409 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5410 * - Calling #rewind on the stream discards the pushed-back data.
5411 *
5412 * When argument +integer+ is given, interprets the integer as a character:
5413 *
5414 * File.write('t.tmp', '012')
5415 * f = File.open('t.tmp')
5416 * f.ungetc(0x41) # => nil
5417 * f.read # => "A012"
5418 * f.rewind
5419 * f.ungetc(0x0442) # => nil
5420 * f.getc.ord # => 1090
5421 * f.close
5422 *
5423 * When argument +string+ is given, uses all characters:
5424 *
5425 * File.write('t.tmp', '012')
5426 * f = File.open('t.tmp')
5427 * f.ungetc('A') # => nil
5428 * f.read # => "A012"
5429 * f.rewind
5430 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5431 * f.getc.ord # => 1090
5432 * f.getc.ord # => 1077
5433 * f.getc.ord # => 1089
5434 * f.getc.ord # => 1090
5435 * f.close
5436 *
5437 */
5438
5439VALUE
5441{
5442 rb_io_t *fptr;
5443 rb_len_t len;
5444
5445 GetOpenFile(io, fptr);
5447 if (FIXNUM_P(c)) {
5448 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5449 }
5450 else if (RB_BIGNUM_TYPE_P(c)) {
5451 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5452 }
5453 else {
5454 StringValue(c);
5455 }
5456 if (NEED_READCONV(fptr)) {
5457 SET_BINARY_MODE(fptr);
5458 len = RSTRING_LEN(c);
5459#if SIZEOF_RB_LEN_T > SIZEOF_INT
5460 if (len > INT_MAX)
5461 rb_raise(rb_eIOError, "ungetc failed");
5462#endif
5463 make_readconv(fptr, (int)len);
5464 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5465 rb_raise(rb_eIOError, "ungetc failed");
5466 if (fptr->cbuf.off < len) {
5467 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5468 fptr->cbuf.ptr+fptr->cbuf.off,
5469 char, fptr->cbuf.len);
5470 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5471 }
5472 fptr->cbuf.off -= (int)len;
5473 fptr->cbuf.len += (int)len;
5474 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5475 }
5476 else {
5477 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5478 io_ungetbyte(c, fptr);
5479 }
5480 return Qnil;
5481}
5482
5483/*
5484 * call-seq:
5485 * isatty -> true or false
5486 *
5487 * Returns +true+ if the stream is associated with a terminal device (tty),
5488 * +false+ otherwise:
5489 *
5490 * f = File.new('t.txt').isatty #=> false
5491 * f.close
5492 * f = File.new('/dev/tty').isatty #=> true
5493 * f.close
5494 *
5495 */
5496
5497static VALUE
5498rb_io_isatty(VALUE io)
5499{
5500 rb_io_t *fptr;
5501
5502 GetOpenFile(io, fptr);
5503 return RBOOL(isatty(fptr->fd) != 0);
5504}
5505
5506#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5507/*
5508 * call-seq:
5509 * close_on_exec? -> true or false
5510 *
5511 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5512 *
5513 * f = File.open('t.txt')
5514 * f.close_on_exec? # => true
5515 * f.close_on_exec = false
5516 * f.close_on_exec? # => false
5517 * f.close
5518 *
5519 */
5520
5521static VALUE
5522rb_io_close_on_exec_p(VALUE io)
5523{
5524 rb_io_t *fptr;
5525 VALUE write_io;
5526 int fd, ret;
5527
5528 write_io = GetWriteIO(io);
5529 if (io != write_io) {
5530 GetOpenFile(write_io, fptr);
5531 if (fptr && 0 <= (fd = fptr->fd)) {
5532 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5533 if (!(ret & FD_CLOEXEC)) return Qfalse;
5534 }
5535 }
5536
5537 GetOpenFile(io, fptr);
5538 if (fptr && 0 <= (fd = fptr->fd)) {
5539 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5540 if (!(ret & FD_CLOEXEC)) return Qfalse;
5541 }
5542 return Qtrue;
5543}
5544#else
5545#define rb_io_close_on_exec_p rb_f_notimplement
5546#endif
5547
5548#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5549/*
5550 * call-seq:
5551 * self.close_on_exec = bool -> true or false
5552 *
5553 * Sets a close-on-exec flag.
5554 *
5555 * f = File.open(File::NULL)
5556 * f.close_on_exec = true
5557 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5558 * f.closed? #=> false
5559 *
5560 * Ruby sets close-on-exec flags of all file descriptors by default
5561 * since Ruby 2.0.0.
5562 * So you don't need to set by yourself.
5563 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5564 * if another thread use fork() and exec() (via system() method for example).
5565 * If you really needs file descriptor inheritance to child process,
5566 * use spawn()'s argument such as fd=>fd.
5567 */
5568
5569static VALUE
5570rb_io_set_close_on_exec(VALUE io, VALUE arg)
5571{
5572 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5573 rb_io_t *fptr;
5574 VALUE write_io;
5575 int fd, ret;
5576
5577 write_io = GetWriteIO(io);
5578 if (io != write_io) {
5579 GetOpenFile(write_io, fptr);
5580 if (fptr && 0 <= (fd = fptr->fd)) {
5581 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5582 if ((ret & FD_CLOEXEC) != flag) {
5583 ret = (ret & ~FD_CLOEXEC) | flag;
5584 ret = fcntl(fd, F_SETFD, ret);
5585 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5586 }
5587 }
5588
5589 }
5590
5591 GetOpenFile(io, fptr);
5592 if (fptr && 0 <= (fd = fptr->fd)) {
5593 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5594 if ((ret & FD_CLOEXEC) != flag) {
5595 ret = (ret & ~FD_CLOEXEC) | flag;
5596 ret = fcntl(fd, F_SETFD, ret);
5597 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5598 }
5599 }
5600 return Qnil;
5601}
5602#else
5603#define rb_io_set_close_on_exec rb_f_notimplement
5604#endif
5605
5606#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5607#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5608
5609static VALUE
5610finish_writeconv(rb_io_t *fptr, int noalloc)
5611{
5612 unsigned char *ds, *dp, *de;
5614
5615 if (!fptr->wbuf.ptr) {
5616 unsigned char buf[1024];
5617
5619 while (res == econv_destination_buffer_full) {
5620 ds = dp = buf;
5621 de = buf + sizeof(buf);
5622 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5623 while (dp-ds) {
5624 size_t remaining = dp-ds;
5625 rb_len_t result = rb_io_write_memory(fptr, ds, remaining);
5626
5627 if (result > 0) {
5628 ds += result;
5629 if ((size_t)result == remaining) break;
5630 }
5631 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5632 if (fptr->fd < 0)
5633 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5634 }
5635 else {
5636 return noalloc ? Qtrue : INT2NUM(errno);
5637 }
5638 }
5639 if (res == econv_invalid_byte_sequence ||
5640 res == econv_incomplete_input ||
5642 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5643 }
5644 }
5645
5646 return Qnil;
5647 }
5648
5650 while (res == econv_destination_buffer_full) {
5651 if (fptr->wbuf.len == fptr->wbuf.capa) {
5652 if (io_fflush(fptr) < 0) {
5653 return noalloc ? Qtrue : INT2NUM(errno);
5654 }
5655 }
5656
5657 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5658 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5659 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5660 fptr->wbuf.len += (int)(dp - ds);
5661 if (res == econv_invalid_byte_sequence ||
5662 res == econv_incomplete_input ||
5664 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5665 }
5666 }
5667 return Qnil;
5668}
5669
5671 rb_io_t *fptr;
5672 int noalloc;
5673};
5674
5675static VALUE
5676finish_writeconv_sync(VALUE arg)
5677{
5678 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5679 return finish_writeconv(p->fptr, p->noalloc);
5680}
5681
5682static void*
5683nogvl_close(void *ptr)
5684{
5685 int *fd = ptr;
5686
5687 return (void*)(intptr_t)close(*fd);
5688}
5689
5690static int
5691maygvl_close(int fd, int keepgvl)
5692{
5693 if (keepgvl)
5694 return close(fd);
5695
5696 /*
5697 * close() may block for certain file types (NFS, SO_LINGER sockets,
5698 * inotify), so let other threads run.
5699 */
5700 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5701}
5702
5703static void*
5704nogvl_fclose(void *ptr)
5705{
5706 FILE *file = ptr;
5707
5708 return (void*)(intptr_t)fclose(file);
5709}
5710
5711static int
5712maygvl_fclose(FILE *file, int keepgvl)
5713{
5714 if (keepgvl)
5715 return fclose(file);
5716
5717 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5718}
5719
5720static void free_io_buffer(rb_io_buffer_t *buf);
5721
5722static void
5723fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5724{
5725 VALUE error = Qnil;
5726 int fd = fptr->fd;
5727 FILE *stdio_file = fptr->stdio_file;
5728 int mode = fptr->mode;
5729
5730 if (fptr->writeconv) {
5731 if (!NIL_P(fptr->write_lock) && !noraise) {
5732 struct finish_writeconv_arg arg;
5733 arg.fptr = fptr;
5734 arg.noalloc = noraise;
5735 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5736 }
5737 else {
5738 error = finish_writeconv(fptr, noraise);
5739 }
5740 }
5741 /* Do not flush the write buffer on close when the stream is in sync
5742 * mode. In sync mode Ruby's write buffer is not authoritative (writes go
5743 * straight to the OS), so any bytes left in the buffer are the result of
5744 * writes made while sync was disabled. Setting sync = true is therefore a
5745 * way to abandon that pending output rather than replaying it on close,
5746 * which matters after an interrupted write where the amount actually
5747 * written is indeterminate. Call flush before enabling sync if the
5748 * buffered data should still be sent. */
5749 if (fptr->wbuf.len && !(fptr->mode & FMODE_SYNC)) {
5750 if (noraise) {
5751 io_flush_buffer_sync(fptr);
5752 }
5753 else {
5754 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5755 error = INT2NUM(errno);
5756 }
5757 }
5758 }
5759
5760 int done = 0;
5761
5762 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5763 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5764 done = 1;
5765 }
5766
5767 fptr->fd = -1;
5768 fptr->stdio_file = 0;
5770
5771 // Wait for blocking operations to ensure they do not hit EBADF:
5772 rb_thread_io_close_wait(fptr);
5773
5774 if (!done && stdio_file) {
5775 // stdio_file is deallocated anyway even if fclose failed.
5776 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5777 if (!noraise) {
5778 error = INT2NUM(errno);
5779 }
5780 }
5781
5782 done = 1;
5783 }
5784
5785 VALUE scheduler = rb_fiber_scheduler_current();
5786 if (!done && fd >= 0 && scheduler != Qnil) {
5787 VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
5788
5789 if (!UNDEF_P(result)) {
5790 done = RTEST(result);
5791 }
5792 }
5793
5794 if (!done && fd >= 0) {
5795 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5796 // We assumes it is closed.
5797
5798 keepgvl |= !(mode & FMODE_WRITABLE);
5799 keepgvl |= noraise;
5800 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5801 if (!noraise) {
5802 error = INT2NUM(errno);
5803 }
5804 }
5805
5806 done = 1;
5807 }
5808
5809 if (!NIL_P(error) && !noraise) {
5810 if (RB_INTEGER_TYPE_P(error))
5811 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5812 else
5813 rb_exc_raise(error);
5814 }
5815}
5816
5817static void
5818fptr_finalize(rb_io_t *fptr, int noraise)
5819{
5820 fptr_finalize_flush(fptr, noraise, FALSE);
5821 free_io_buffer(&fptr->rbuf);
5822 free_io_buffer(&fptr->wbuf);
5823 clear_codeconv(fptr);
5824}
5825
5826static void
5827rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5828{
5829 if (fptr->finalize) {
5830 (*fptr->finalize)(fptr, noraise);
5831 }
5832 else {
5833 fptr_finalize(fptr, noraise);
5834 }
5835}
5836
5837static void
5838free_io_buffer(rb_io_buffer_t *buf)
5839{
5840 if (buf->ptr) {
5841 ruby_xfree_sized(buf->ptr, (size_t)buf->capa);
5842 buf->ptr = NULL;
5843 }
5844 buf->off = buf->len = buf->capa = 0;
5845}
5846
5847static void
5848clear_readconv(rb_io_t *fptr)
5849{
5850 if (fptr->readconv) {
5851 rb_econv_close(fptr->readconv);
5852 fptr->readconv = NULL;
5853 }
5854 free_io_buffer(&fptr->cbuf);
5855}
5856
5857static void
5858clear_writeconv(rb_io_t *fptr)
5859{
5860 if (fptr->writeconv) {
5862 fptr->writeconv = NULL;
5863 }
5864 fptr->writeconv_initialized = 0;
5865}
5866
5867static void
5868clear_codeconv(rb_io_t *fptr)
5869{
5870 clear_readconv(fptr);
5871 clear_writeconv(fptr);
5872}
5873
5874static void
5875rb_io_fptr_cleanup_all(rb_io_t *fptr)
5876{
5877 fptr->pathv = Qnil;
5878 if (0 <= fptr->fd)
5879 rb_io_fptr_cleanup(fptr, TRUE);
5880 fptr->write_lock = Qnil;
5881 free_io_buffer(&fptr->rbuf);
5882 free_io_buffer(&fptr->wbuf);
5883 clear_codeconv(fptr);
5884}
5885
5886int
5888{
5889 if (!io) return 0;
5890 rb_io_fptr_cleanup_all(io);
5891 free(io);
5892
5893 return 1;
5894}
5895
5896bool
5897rb_io_fptr_finalize_closed(struct rb_io *io)
5898{
5899 if (!io) return true;
5900 if (io->fd >= 0) return false;
5902 return true;
5903}
5904
5905size_t
5906rb_io_memsize(const rb_io_t *io)
5907{
5908 size_t size = sizeof(rb_io_t);
5909 size += io->rbuf.capa;
5910 size += io->wbuf.capa;
5911 size += io->cbuf.capa;
5912 if (io->readconv) size += rb_econv_memsize(io->readconv);
5913 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5914
5915 struct rb_io_blocking_operation *blocking_operation = 0;
5916
5917 // 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.
5918 rb_serial_t fork_generation = GET_VM()->fork_gen;
5919 if (io->fork_generation == fork_generation) {
5920 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5921 size += sizeof(struct rb_io_blocking_operation);
5922 }
5923 }
5924
5925 return size;
5926}
5927
5928#ifdef _WIN32
5929/* keep GVL while closing to prevent crash on Windows */
5930# define KEEPGVL TRUE
5931#else
5932# define KEEPGVL FALSE
5933#endif
5934
5935static rb_io_t *
5936io_close_fptr(VALUE io)
5937{
5938 rb_io_t *fptr;
5939 VALUE write_io;
5940 rb_io_t *write_fptr;
5941
5942 write_io = GetWriteIO(io);
5943 if (io != write_io) {
5944 write_fptr = RFILE(write_io)->fptr;
5945 if (write_fptr && 0 <= write_fptr->fd) {
5946 rb_io_fptr_cleanup(write_fptr, TRUE);
5947 }
5948 }
5949
5950 fptr = RFILE(io)->fptr;
5951 if (!fptr) return 0;
5952 if (fptr->fd < 0) return 0;
5953
5954 // This guards against multiple threads closing the same IO object:
5955 if (rb_thread_io_close_interrupt(fptr)) {
5956 /* calls close(fptr->fd): */
5957 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5958 }
5959
5960 rb_io_fptr_cleanup(fptr, FALSE);
5961 return fptr;
5962}
5963
5964static void
5965fptr_waitpid(rb_io_t *fptr, int nohang)
5966{
5967 int status;
5968 if (fptr->pid) {
5969 rb_last_status_clear();
5970 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5971 fptr->pid = 0;
5972 }
5973}
5974
5975VALUE
5977{
5978 rb_io_t *fptr = io_close_fptr(io);
5979 if (fptr) fptr_waitpid(fptr, 0);
5980 return Qnil;
5981}
5982
5983/*
5984 * call-seq:
5985 * close -> nil
5986 *
5987 * Closes the stream for both reading and writing
5988 * if open for either or both; returns +nil+.
5989 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5990 *
5991 * If the stream is open for writing, flushes any buffered writes
5992 * to the operating system before closing.
5993 *
5994 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5995 * (child exit status).
5996 *
5997 * It is not an error to close an IO object that has already been closed.
5998 * It just returns nil.
5999 *
6000 * Example:
6001 *
6002 * IO.popen('ruby', 'r+') do |pipe|
6003 * puts pipe.closed?
6004 * pipe.close
6005 * puts $?
6006 * puts pipe.closed?
6007 * end
6008 *
6009 * Output:
6010 *
6011 * false
6012 * pid 13760 exit 0
6013 * true
6014 *
6015 * Related: IO#close_read, IO#close_write, IO#closed?.
6016 */
6017
6018static VALUE
6019rb_io_close_m(VALUE io)
6020{
6021 rb_io_t *fptr = rb_io_get_fptr(io);
6022 if (fptr->fd < 0) {
6023 return Qnil;
6024 }
6025 rb_io_close(io);
6026 return Qnil;
6027}
6028
6029static VALUE
6030io_call_close(VALUE io)
6031{
6032 rb_check_funcall(io, rb_intern("close"), 0, 0);
6033 return io;
6034}
6035
6036static VALUE
6037ignore_closed_stream(VALUE io, VALUE exc)
6038{
6039 enum {mesg_len = sizeof(closed_stream)-1};
6040 VALUE mesg = rb_attr_get(exc, idMesg);
6041 if (!RB_TYPE_P(mesg, T_STRING) ||
6042 RSTRING_LEN(mesg) != mesg_len ||
6043 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
6044 rb_exc_raise(exc);
6045 }
6046 return io;
6047}
6048
6049static VALUE
6050io_close(VALUE io)
6051{
6052 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
6053 if (!UNDEF_P(closed) && RTEST(closed)) return io;
6054 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
6055 rb_eIOError, (VALUE)0);
6056 return io;
6057}
6058
6059/*
6060 * call-seq:
6061 * closed? -> true or false
6062 *
6063 * Returns +true+ if the stream is closed for both reading and writing,
6064 * +false+ otherwise.
6065 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6066 *
6067 * IO.popen('ruby', 'r+') do |pipe|
6068 * puts pipe.closed?
6069 * pipe.close_read
6070 * puts pipe.closed?
6071 * pipe.close_write
6072 * puts pipe.closed?
6073 * end
6074 *
6075 * Output:
6076 *
6077 * false
6078 * false
6079 * true
6080 *
6081 * Related: IO#close_read, IO#close_write, IO#close.
6082 */
6083VALUE
6085{
6086 rb_io_t *fptr;
6087 VALUE write_io;
6088 rb_io_t *write_fptr;
6089
6090 write_io = GetWriteIO(io);
6091 if (io != write_io) {
6092 write_fptr = RFILE(write_io)->fptr;
6093 if (write_fptr && 0 <= write_fptr->fd) {
6094 return Qfalse;
6095 }
6096 }
6097
6098 fptr = rb_io_get_fptr(io);
6099 return RBOOL(0 > fptr->fd);
6100}
6101
6102/*
6103 * call-seq:
6104 * close_read -> nil
6105 *
6106 * Closes the stream for reading if open for reading;
6107 * returns +nil+.
6108 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6109 *
6110 * If the stream was opened by IO.popen and is also closed for writing,
6111 * sets global variable <tt>$?</tt> (child exit status).
6112 *
6113 * Example:
6114 *
6115 * IO.popen('ruby', 'r+') do |pipe|
6116 * puts pipe.closed?
6117 * pipe.close_write
6118 * puts pipe.closed?
6119 * pipe.close_read
6120 * puts $?
6121 * puts pipe.closed?
6122 * end
6123 *
6124 * Output:
6125 *
6126 * false
6127 * false
6128 * pid 14748 exit 0
6129 * true
6130 *
6131 * Related: IO#close, IO#close_write, IO#closed?.
6132 */
6133
6134static VALUE
6135rb_io_close_read(VALUE io)
6136{
6137 rb_io_t *fptr;
6138 VALUE write_io;
6139
6140 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6141 if (fptr->fd < 0) return Qnil;
6142 if (is_socket(fptr->fd, fptr->pathv)) {
6143#ifndef SHUT_RD
6144# define SHUT_RD 0
6145#endif
6146 if (shutdown(fptr->fd, SHUT_RD) < 0)
6147 rb_sys_fail_path(fptr->pathv);
6148 fptr->mode &= ~FMODE_READABLE;
6149 if (!(fptr->mode & FMODE_WRITABLE))
6150 return rb_io_close(io);
6151 return Qnil;
6152 }
6153
6154 write_io = GetWriteIO(io);
6155 if (io != write_io) {
6156 rb_io_t *wfptr;
6157 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6158 wfptr->pid = fptr->pid;
6159 fptr->pid = 0;
6160 RFILE(io)->fptr = wfptr;
6161 /* bind to write_io temporarily to get rid of memory/fd leak */
6162 fptr->tied_io_for_writing = 0;
6163 RFILE(write_io)->fptr = fptr;
6164 rb_io_fptr_cleanup(fptr, FALSE);
6165 /* should not finalize fptr because another thread may be reading it */
6166 return Qnil;
6167 }
6168
6169 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
6170 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
6171 }
6172 return rb_io_close(io);
6173}
6174
6175/*
6176 * call-seq:
6177 * close_write -> nil
6178 *
6179 * Closes the stream for writing if open for writing;
6180 * returns +nil+.
6181 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6182 *
6183 * Flushes any buffered writes to the operating system before closing.
6184 *
6185 * If the stream was opened by IO.popen and is also closed for reading,
6186 * sets global variable <tt>$?</tt> (child exit status).
6187 *
6188 * IO.popen('ruby', 'r+') do |pipe|
6189 * puts pipe.closed?
6190 * pipe.close_read
6191 * puts pipe.closed?
6192 * pipe.close_write
6193 * puts $?
6194 * puts pipe.closed?
6195 * end
6196 *
6197 * Output:
6198 *
6199 * false
6200 * false
6201 * pid 15044 exit 0
6202 * true
6203 *
6204 * Related: IO#close, IO#close_read, IO#closed?.
6205 */
6206
6207static VALUE
6208rb_io_close_write(VALUE io)
6209{
6210 rb_io_t *fptr;
6211 VALUE write_io;
6212
6213 write_io = GetWriteIO(io);
6214 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6215 if (fptr->fd < 0) return Qnil;
6216 if (is_socket(fptr->fd, fptr->pathv)) {
6217#ifndef SHUT_WR
6218# define SHUT_WR 1
6219#endif
6220 /* Flush any buffered data before shutting down the write side.
6221 * Otherwise the buffered bytes are silently dropped here, and a
6222 * subsequent #close would try to flush them into the now
6223 * shutdown(SHUT_WR) socket and fail with EPIPE. This matches the
6224 * behaviour of the non-socket path below, which flushes via
6225 * rb_io_close(). */
6226 if (fptr->mode & FMODE_WRITABLE) {
6227 if (io_fflush(fptr) < 0)
6228 rb_sys_fail_on_write(fptr);
6229 }
6230 if (shutdown(fptr->fd, SHUT_WR) < 0)
6231 rb_sys_fail_path(fptr->pathv);
6232 fptr->mode &= ~FMODE_WRITABLE;
6233 if (!(fptr->mode & FMODE_READABLE))
6234 return rb_io_close(write_io);
6235 return Qnil;
6236 }
6237
6238 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6239 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6240 }
6241
6242 if (io != write_io) {
6243 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6244 fptr->tied_io_for_writing = 0;
6245 }
6246 rb_io_close(write_io);
6247 return Qnil;
6248}
6249
6250/*
6251 * call-seq:
6252 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6253 *
6254 * Behaves like IO#seek, except that it:
6255 *
6256 * - Uses low-level system functions.
6257 * - Returns the new position.
6258 *
6259 */
6260
6261static VALUE
6262rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6263{
6264 VALUE offset, ptrname;
6265 int whence = SEEK_SET;
6266 rb_io_t *fptr;
6267 rb_off_t pos;
6268
6269 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6270 whence = interpret_seek_whence(ptrname);
6271 }
6272 pos = NUM2OFFT(offset);
6273 GetOpenFile(io, fptr);
6274 if ((fptr->mode & FMODE_READABLE) &&
6275 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6276 rb_raise(rb_eIOError, "sysseek for buffered IO");
6277 }
6278 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6279 rb_warn("sysseek for buffered IO");
6280 }
6281 errno = 0;
6282 pos = lseek(fptr->fd, pos, whence);
6283 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6284
6285 return OFFT2NUM(pos);
6286}
6287
6288/*
6289 * call-seq:
6290 * syswrite(object) -> integer
6291 *
6292 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6293 * returns the number bytes written.
6294 * If +object+ is not a string is converted via method to_s:
6295 *
6296 * f = File.new('t.tmp', 'w')
6297 * f.syswrite('foo') # => 3
6298 * f.syswrite(30) # => 2
6299 * f.syswrite(:foo) # => 3
6300 * f.close
6301 *
6302 * This methods should not be used with other stream-writer methods.
6303 *
6304 */
6305
6306static VALUE
6307rb_io_syswrite(VALUE io, VALUE str)
6308{
6309 VALUE tmp;
6310 rb_io_t *fptr;
6311 rb_len_t n, len;
6312 const char *ptr;
6313
6314 if (!RB_TYPE_P(str, T_STRING))
6315 str = rb_obj_as_string(str);
6316
6317 io = GetWriteIO(io);
6318 GetOpenFile(io, fptr);
6320
6321 if (fptr->wbuf.len) {
6322 rb_warn("syswrite for buffered IO");
6323 }
6324
6325 tmp = rb_str_tmp_frozen_acquire(str);
6326 RSTRING_GETMEM(tmp, ptr, len);
6327 n = rb_io_write_memory(fptr, ptr, len);
6328 if (n < 0) rb_sys_fail_path(fptr->pathv);
6329 rb_str_tmp_frozen_release(str, tmp);
6330
6331 return LEN2NUM(n);
6332}
6333
6334/*
6335 * call-seq:
6336 * sysread(maxlen) -> string
6337 * sysread(maxlen, out_string) -> string
6338 *
6339 * Behaves like IO#readpartial, except that it uses low-level system functions.
6340 *
6341 * This method should not be used with other stream-reader methods.
6342 *
6343 */
6344
6345static VALUE
6346rb_io_sysread(int argc, VALUE *argv, VALUE io)
6347{
6348 VALUE len, str;
6349 rb_io_t *fptr;
6350 rb_len_t n, ilen;
6351 struct io_internal_read_struct iis;
6352 int shrinkable;
6353
6354 rb_scan_args(argc, argv, "11", &len, &str);
6355 ilen = NUM2LEN(len);
6356
6357 shrinkable = io_setstrbuf(&str, ilen);
6358 if (ilen == 0) return str;
6359
6360 GetOpenFile(io, fptr);
6362
6363 if (READ_DATA_BUFFERED(fptr)) {
6364 rb_raise(rb_eIOError, "sysread for buffered IO");
6365 }
6366
6367 rb_io_check_closed(fptr);
6368
6369 io_setstrbuf(&str, ilen);
6370 iis.th = rb_thread_current();
6371 iis.fptr = fptr;
6372 iis.nonblock = 0;
6373 iis.fd = fptr->fd;
6374 iis.buf = RSTRING_PTR(str);
6375 iis.capa = ilen;
6376 iis.timeout = NULL;
6377 n = io_read_memory_locktmp(str, &iis);
6378
6379 if (n < 0) {
6380 rb_sys_fail_path(fptr->pathv);
6381 }
6382
6383 io_set_read_length(str, n, shrinkable);
6384
6385 if (n == 0 && ilen > 0) {
6386 rb_eof_error();
6387 }
6388
6389 return str;
6390}
6391
6393 struct rb_io *io;
6394 int fd;
6395 void *buf;
6396 size_t count;
6397 rb_off_t offset;
6398};
6399
6400static VALUE
6401internal_pread_func(void *_arg)
6402{
6403 struct prdwr_internal_arg *arg = _arg;
6404
6405 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6406}
6407
6408static VALUE
6409pread_internal_call(VALUE _arg)
6410{
6411 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6412
6413 VALUE scheduler = rb_fiber_scheduler_current();
6414 if (scheduler != Qnil) {
6415 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6416
6417 if (!UNDEF_P(result)) {
6419 }
6420 }
6421
6422 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6423}
6424
6425/*
6426 * call-seq:
6427 * pread(maxlen, offset) -> string
6428 * pread(maxlen, offset, out_string) -> string
6429 *
6430 * Behaves like IO#readpartial, except that it:
6431 *
6432 * - Reads at the given +offset+ (in bytes).
6433 * - Disregards, and does not modify, the stream's position
6434 * (see {Position}[rdoc-ref:IO@Position]).
6435 * - Bypasses any user space buffering in the stream.
6436 *
6437 * Because this method does not disturb the stream's state
6438 * (its position, in particular), +pread+ allows multiple threads and processes
6439 * to use the same \IO object for reading at various offsets.
6440 *
6441 * f = File.open('t.txt')
6442 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6443 * f.pos # => 52
6444 * # Read 12 bytes at offset 0.
6445 * f.pread(12, 0) # => "First line\n"
6446 * # Read 9 bytes at offset 8.
6447 * f.pread(9, 8) # => "ne\nSecon"
6448 * f.close
6449 *
6450 * Not available on some platforms.
6451 *
6452 */
6453static VALUE
6454rb_io_pread(int argc, VALUE *argv, VALUE io)
6455{
6456 VALUE len, offset, str;
6457 rb_io_t *fptr;
6458 ssize_t n;
6459 struct prdwr_internal_arg arg;
6460 int shrinkable;
6461
6462 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6463 arg.count = NUM2SIZET(len);
6464 arg.offset = NUM2OFFT(offset);
6465
6466 shrinkable = io_setstrbuf(&str, (rb_len_t)arg.count);
6467 if (arg.count == 0) return str;
6468 arg.buf = RSTRING_PTR(str);
6469
6470 GetOpenFile(io, fptr);
6472
6473 arg.io = fptr;
6474 arg.fd = fptr->fd;
6475 rb_io_check_closed(fptr);
6476
6477 rb_str_locktmp(str);
6478 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6479
6480 if (n < 0) {
6481 rb_sys_fail_path(fptr->pathv);
6482 }
6483 io_set_read_length(str, n, shrinkable);
6484 if (n == 0 && arg.count > 0) {
6485 rb_eof_error();
6486 }
6487
6488 return str;
6489}
6490
6491static VALUE
6492internal_pwrite_func(void *_arg)
6493{
6494 struct prdwr_internal_arg *arg = _arg;
6495
6496 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6497}
6498
6499static VALUE
6500pwrite_internal_call(VALUE _arg)
6501{
6502 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6503
6504 VALUE scheduler = rb_fiber_scheduler_current();
6505 if (scheduler != Qnil) {
6506 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6507
6508 if (!UNDEF_P(result)) {
6510 }
6511 }
6512
6513 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
6514}
6515
6516/*
6517 * call-seq:
6518 * pwrite(object, offset) -> integer
6519 *
6520 * Behaves like IO#write, except that it:
6521 *
6522 * - Writes at the given +offset+ (in bytes).
6523 * - Disregards, and does not modify, the stream's position
6524 * (see {Position}[rdoc-ref:IO@Position]).
6525 * - Bypasses any user space buffering in the stream.
6526 *
6527 * Because this method does not disturb the stream's state
6528 * (its position, in particular), +pwrite+ allows multiple threads and processes
6529 * to use the same \IO object for writing at various offsets.
6530 *
6531 * f = File.open('t.tmp', 'w+')
6532 * # Write 6 bytes at offset 3.
6533 * f.pwrite('ABCDEF', 3) # => 6
6534 * f.rewind
6535 * f.read # => "\u0000\u0000\u0000ABCDEF"
6536 * f.close
6537 *
6538 * Not available on some platforms.
6539 *
6540 */
6541static VALUE
6542rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6543{
6544 rb_io_t *fptr;
6545 ssize_t n;
6546 struct prdwr_internal_arg arg;
6547 VALUE tmp;
6548
6549 if (!RB_TYPE_P(str, T_STRING))
6550 str = rb_obj_as_string(str);
6551
6552 arg.offset = NUM2OFFT(offset);
6553
6554 io = GetWriteIO(io);
6555 GetOpenFile(io, fptr);
6557
6558 arg.io = fptr;
6559 arg.fd = fptr->fd;
6560
6561 tmp = rb_str_tmp_frozen_acquire(str);
6562 arg.buf = RSTRING_PTR(tmp);
6563 arg.count = (size_t)RSTRING_LEN(tmp);
6564
6565 n = (ssize_t)pwrite_internal_call((VALUE)&arg);
6566 if (n < 0) rb_sys_fail_path(fptr->pathv);
6567 rb_str_tmp_frozen_release(str, tmp);
6568
6569 return SSIZET2NUM(n);
6570}
6571
6572VALUE
6574{
6575 rb_io_t *fptr;
6576
6577 GetOpenFile(io, fptr);
6578 if (fptr->readconv)
6580 if (fptr->writeconv)
6582 fptr->mode |= FMODE_BINMODE;
6583 fptr->mode &= ~FMODE_TEXTMODE;
6584 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6585#ifdef O_BINARY
6586 if (!fptr->readconv) {
6587 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6588 }
6589 else {
6590 setmode(fptr->fd, O_BINARY);
6591 }
6592#endif
6593 return io;
6594}
6595
6596static void
6597io_ascii8bit_binmode(rb_io_t *fptr)
6598{
6599 if (fptr->readconv) {
6600 rb_econv_close(fptr->readconv);
6601 fptr->readconv = NULL;
6602 }
6603 if (fptr->writeconv) {
6605 fptr->writeconv = NULL;
6606 }
6607 fptr->mode |= FMODE_BINMODE;
6608 fptr->mode &= ~FMODE_TEXTMODE;
6609 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6610
6611 fptr->encs.enc = rb_ascii8bit_encoding();
6612 fptr->encs.enc2 = NULL;
6613 fptr->encs.ecflags = 0;
6614 fptr->encs.ecopts = Qnil;
6615 clear_codeconv(fptr);
6616}
6617
6618VALUE
6620{
6621 rb_io_t *fptr;
6622
6623 GetOpenFile(io, fptr);
6624 io_ascii8bit_binmode(fptr);
6625
6626 return io;
6627}
6628
6629/*
6630 * call-seq:
6631 * binmode -> self
6632 *
6633 * Sets the stream's data mode as binary
6634 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6635 *
6636 * A stream's data mode may not be changed from binary to text.
6637 *
6638 */
6639
6640static VALUE
6641rb_io_binmode_m(VALUE io)
6642{
6643 VALUE write_io;
6644
6646
6647 write_io = GetWriteIO(io);
6648 if (write_io != io)
6649 rb_io_ascii8bit_binmode(write_io);
6650 return io;
6651}
6652
6653/*
6654 * call-seq:
6655 * binmode? -> true or false
6656 *
6657 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6658 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6659 *
6660 */
6661static VALUE
6662rb_io_binmode_p(VALUE io)
6663{
6664 rb_io_t *fptr;
6665 GetOpenFile(io, fptr);
6666 return RBOOL(fptr->mode & FMODE_BINMODE);
6667}
6668
6669static const char*
6670rb_io_fmode_modestr(enum rb_io_mode fmode)
6671{
6672 if (fmode & FMODE_APPEND) {
6673 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6674 return MODE_BTMODE("a+", "ab+", "at+");
6675 }
6676 return MODE_BTMODE("a", "ab", "at");
6677 }
6678 switch (fmode & FMODE_READWRITE) {
6679 default:
6680 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6681 case FMODE_READABLE:
6682 return MODE_BTMODE("r", "rb", "rt");
6683 case FMODE_WRITABLE:
6684 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6685 case FMODE_READWRITE:
6686 if (fmode & FMODE_CREATE) {
6687 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6688 }
6689 return MODE_BTMODE("r+", "rb+", "rt+");
6690 }
6691}
6692
6693static const char bom_prefix[] = "bom|";
6694static const char utf_prefix[] = "utf-";
6695enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6696enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6697
6698static int
6699io_encname_bom_p(const char *name, rb_len_t len)
6700{
6701 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6702}
6703
6704enum rb_io_mode
6705rb_io_modestr_fmode(const char *modestr)
6706{
6707 enum rb_io_mode fmode = 0;
6708 const char *m = modestr, *p = NULL;
6709
6710 switch (*m++) {
6711 case 'r':
6712 fmode |= FMODE_READABLE;
6713 break;
6714 case 'w':
6716 break;
6717 case 'a':
6719 break;
6720 default:
6721 goto error;
6722 }
6723
6724 while (*m) {
6725 switch (*m++) {
6726 case 'b':
6727 fmode |= FMODE_BINMODE;
6728 break;
6729 case 't':
6730 fmode |= FMODE_TEXTMODE;
6731 break;
6732 case '+':
6733 fmode |= FMODE_READWRITE;
6734 break;
6735 case 'x':
6736 if (modestr[0] != 'w')
6737 goto error;
6738 fmode |= FMODE_EXCL;
6739 break;
6740 default:
6741 goto error;
6742 case ':':
6743 p = strchr(m, ':');
6744 if (io_encname_bom_p(m, p ? (rb_len_t)(p - m) : (rb_len_t)strlen(m)))
6745 fmode |= FMODE_SETENC_BY_BOM;
6746 goto finished;
6747 }
6748 }
6749
6750 finished:
6751 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6752 goto error;
6753
6754 return fmode;
6755
6756 error:
6757 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6759}
6760
6761int
6762rb_io_oflags_fmode(int oflags)
6763{
6764 enum rb_io_mode fmode = 0;
6765
6766 switch (oflags & O_ACCMODE) {
6767 case O_RDONLY:
6768 fmode = FMODE_READABLE;
6769 break;
6770 case O_WRONLY:
6771 fmode = FMODE_WRITABLE;
6772 break;
6773 case O_RDWR:
6774 fmode = FMODE_READWRITE;
6775 break;
6776 }
6777
6778 if (oflags & O_APPEND) {
6779 fmode |= FMODE_APPEND;
6780 }
6781 if (oflags & O_TRUNC) {
6782 fmode |= FMODE_TRUNC;
6783 }
6784 if (oflags & O_CREAT) {
6785 fmode |= FMODE_CREATE;
6786 }
6787 if (oflags & O_EXCL) {
6788 fmode |= FMODE_EXCL;
6789 }
6790#ifdef O_BINARY
6791 if (oflags & O_BINARY) {
6792 fmode |= FMODE_BINMODE;
6793 }
6794#endif
6795
6796 return fmode;
6797}
6798
6799static int
6800rb_io_fmode_oflags(enum rb_io_mode fmode)
6801{
6802 int oflags = 0;
6803
6804 switch (fmode & FMODE_READWRITE) {
6805 case FMODE_READABLE:
6806 oflags |= O_RDONLY;
6807 break;
6808 case FMODE_WRITABLE:
6809 oflags |= O_WRONLY;
6810 break;
6811 case FMODE_READWRITE:
6812 oflags |= O_RDWR;
6813 break;
6814 }
6815
6816 if (fmode & FMODE_APPEND) {
6817 oflags |= O_APPEND;
6818 }
6819 if (fmode & FMODE_TRUNC) {
6820 oflags |= O_TRUNC;
6821 }
6822 if (fmode & FMODE_CREATE) {
6823 oflags |= O_CREAT;
6824 }
6825 if (fmode & FMODE_EXCL) {
6826 oflags |= O_EXCL;
6827 }
6828#ifdef O_BINARY
6829 if (fmode & FMODE_BINMODE) {
6830 oflags |= O_BINARY;
6831 }
6832#endif
6833
6834 return oflags;
6835}
6836
6837int
6838rb_io_modestr_oflags(const char *modestr)
6839{
6840 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6841}
6842
6843static const char*
6844rb_io_oflags_modestr(int oflags)
6845{
6846#ifdef O_BINARY
6847# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6848#else
6849# define MODE_BINARY(a,b) (a)
6850#endif
6851 int accmode;
6852 if (oflags & O_EXCL) {
6853 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6854 }
6855 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6856 if (oflags & O_APPEND) {
6857 if (accmode == O_WRONLY) {
6858 return MODE_BINARY("a", "ab");
6859 }
6860 if (accmode == O_RDWR) {
6861 return MODE_BINARY("a+", "ab+");
6862 }
6863 }
6864 switch (accmode) {
6865 default:
6866 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6867 case O_RDONLY:
6868 return MODE_BINARY("r", "rb");
6869 case O_WRONLY:
6870 return MODE_BINARY("w", "wb");
6871 case O_RDWR:
6872 if (oflags & O_TRUNC) {
6873 return MODE_BINARY("w+", "wb+");
6874 }
6875 return MODE_BINARY("r+", "rb+");
6876 }
6877}
6878
6879/*
6880 * Convert external/internal encodings to enc/enc2
6881 * NULL => use default encoding
6882 * Qnil => no encoding specified (internal only)
6883 */
6884static void
6885rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6886{
6887 int default_ext = 0;
6888
6889 if (ext == NULL) {
6890 ext = rb_default_external_encoding();
6891 default_ext = 1;
6892 }
6893 if (rb_is_ascii8bit_enc(ext)) {
6894 /* If external is ASCII-8BIT, no transcoding */
6895 intern = NULL;
6896 }
6897 else if (intern == NULL) {
6898 intern = rb_default_internal_encoding();
6899 }
6900 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6901 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6902 /* No internal encoding => use external + no transcoding */
6903 *enc = (default_ext && intern != ext) ? NULL : ext;
6904 *enc2 = NULL;
6905 }
6906 else {
6907 *enc = intern;
6908 *enc2 = ext;
6909 }
6910}
6911
6912static void
6913unsupported_encoding(const char *name, rb_encoding *enc)
6914{
6915 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6916}
6917
6918static void
6919parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6920 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6921{
6922 const char *p;
6923 char encname[ENCODING_MAXNAMELEN+1];
6924 int idx, idx2;
6925 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6926 rb_encoding *ext_enc, *int_enc;
6927 rb_len_t len;
6928
6929 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6930
6931 p = strrchr(estr, ':');
6932 len = p ? (p++ - estr) : (rb_len_t)strlen(estr);
6933 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6934 estr += bom_prefix_len;
6935 len -= bom_prefix_len;
6936 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6937 fmode |= FMODE_SETENC_BY_BOM;
6938 }
6939 else {
6940 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6941 fmode &= ~FMODE_SETENC_BY_BOM;
6942 }
6943 }
6944 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6945 idx = -1;
6946 }
6947 else {
6948 if (p) {
6949 memcpy(encname, estr, len);
6950 encname[len] = '\0';
6951 estr = encname;
6952 }
6953 idx = rb_enc_find_index(estr);
6954 }
6955 if (fmode_p) *fmode_p = fmode;
6956
6957 if (idx >= 0)
6958 ext_enc = rb_enc_from_index(idx);
6959 else {
6960 if (idx != -2)
6961 unsupported_encoding(estr, estr_enc);
6962 ext_enc = NULL;
6963 }
6964
6965 int_enc = NULL;
6966 if (p) {
6967 if (*p == '-' && *(p+1) == '\0') {
6968 /* Special case - "-" => no transcoding */
6969 int_enc = (rb_encoding *)Qnil;
6970 }
6971 else {
6972 idx2 = rb_enc_find_index(p);
6973 if (idx2 < 0)
6974 unsupported_encoding(p, estr_enc);
6975 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6976 int_enc = (rb_encoding *)Qnil;
6977 }
6978 else
6979 int_enc = rb_enc_from_index(idx2);
6980 }
6981 }
6982
6983 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6984}
6985
6986int
6987rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6988{
6989 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6990 int extracted = 0;
6991 rb_encoding *extencoding = NULL;
6992 rb_encoding *intencoding = NULL;
6993
6994 if (!NIL_P(opt)) {
6995 VALUE v;
6996 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6997 if (v != Qnil) encoding = v;
6998 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6999 if (v != Qnil) extenc = v;
7000 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
7001 if (!UNDEF_P(v)) intenc = v;
7002 }
7003 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
7004 if (!NIL_P(ruby_verbose)) {
7005 int idx = rb_to_encoding_index(encoding);
7006 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
7007 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
7008 encoding, UNDEF_P(extenc) ? "internal" : "external");
7009 }
7010 encoding = Qnil;
7011 }
7012 if (!NIL_OR_UNDEF_P(extenc)) {
7013 extencoding = rb_to_encoding(extenc);
7014 }
7015 if (!UNDEF_P(intenc)) {
7016 if (NIL_P(intenc)) {
7017 /* internal_encoding: nil => no transcoding */
7018 intencoding = (rb_encoding *)Qnil;
7019 }
7020 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
7021 char *p = StringValueCStr(tmp);
7022
7023 if (*p == '-' && *(p+1) == '\0') {
7024 /* Special case - "-" => no transcoding */
7025 intencoding = (rb_encoding *)Qnil;
7026 }
7027 else {
7028 intencoding = rb_to_encoding(intenc);
7029 }
7030 }
7031 else {
7032 intencoding = rb_to_encoding(intenc);
7033 }
7034 if (extencoding == intencoding) {
7035 intencoding = (rb_encoding *)Qnil;
7036 }
7037 }
7038 if (!NIL_P(encoding)) {
7039 extracted = 1;
7040 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
7041 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
7042 enc_p, enc2_p, fmode_p);
7043 }
7044 else {
7045 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
7046 }
7047 }
7048 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
7049 extracted = 1;
7050 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
7051 }
7052 return extracted;
7053}
7054
7055static void
7056validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
7057{
7058 enum rb_io_mode fmode = *fmode_p;
7059
7060 if ((fmode & FMODE_READABLE) &&
7061 !enc2 &&
7062 !(fmode & FMODE_BINMODE) &&
7063 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
7064 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
7065
7066 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
7067 rb_raise(rb_eArgError, "newline decorator with binary mode");
7068 }
7069 if (!(fmode & FMODE_BINMODE) &&
7070 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
7071 fmode |= FMODE_TEXTMODE;
7072 *fmode_p = fmode;
7073 }
7074#if !DEFAULT_TEXTMODE
7075 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
7076 fmode &= ~FMODE_TEXTMODE;
7077 *fmode_p = fmode;
7078 }
7079#endif
7080}
7081
7082static void
7083extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
7084{
7085 if (!NIL_P(opthash)) {
7086 VALUE v;
7087 v = rb_hash_aref(opthash, sym_textmode);
7088 if (!NIL_P(v)) {
7089 if (*fmode & FMODE_TEXTMODE)
7090 rb_raise(rb_eArgError, "textmode specified twice");
7091 if (*fmode & FMODE_BINMODE)
7092 rb_raise(rb_eArgError, "both textmode and binmode specified");
7093 if (RTEST(v))
7094 *fmode |= FMODE_TEXTMODE;
7095 }
7096 v = rb_hash_aref(opthash, sym_binmode);
7097 if (!NIL_P(v)) {
7098 if (*fmode & FMODE_BINMODE)
7099 rb_raise(rb_eArgError, "binmode specified twice");
7100 if (*fmode & FMODE_TEXTMODE)
7101 rb_raise(rb_eArgError, "both textmode and binmode specified");
7102 if (RTEST(v))
7103 *fmode |= FMODE_BINMODE;
7104 }
7105
7106 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
7107 rb_raise(rb_eArgError, "both textmode and binmode specified");
7108 }
7109}
7110
7111void
7112rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
7113 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
7114{
7115 VALUE vmode;
7116 int oflags;
7117 enum rb_io_mode fmode;
7118 rb_encoding *enc, *enc2;
7119 int ecflags;
7120 VALUE ecopts;
7121 int has_enc = 0, has_vmode = 0;
7122 VALUE intmode;
7123
7124 vmode = *vmode_p;
7125
7126 /* Set to defaults */
7127 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
7128
7129 vmode_handle:
7130 if (NIL_P(vmode)) {
7131 fmode = FMODE_READABLE;
7132 oflags = O_RDONLY;
7133 }
7134 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
7135 vmode = intmode;
7136 oflags = NUM2INT(intmode);
7137 fmode = rb_io_oflags_fmode(oflags);
7138 }
7139 else {
7140 const char *p;
7141
7142 StringValue(vmode);
7143 p = StringValueCStr(vmode);
7144 fmode = rb_io_modestr_fmode(p);
7145 oflags = rb_io_fmode_oflags(fmode);
7146 p = strchr(p, ':');
7147 if (p) {
7148 has_enc = 1;
7149 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
7150 }
7151 else {
7152 rb_encoding *e;
7153
7154 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7155 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
7156 }
7157 }
7158
7159 if (NIL_P(opthash)) {
7160 ecflags = (fmode & FMODE_READABLE) ?
7163#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7164 ecflags |= (fmode & FMODE_WRITABLE) ?
7165 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7166 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7167#endif
7168 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7169 ecopts = Qnil;
7170 if (fmode & FMODE_BINMODE) {
7171#ifdef O_BINARY
7172 oflags |= O_BINARY;
7173#endif
7174 if (!has_enc)
7175 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7176 }
7177#if DEFAULT_TEXTMODE
7178 else if (NIL_P(vmode)) {
7179 fmode |= DEFAULT_TEXTMODE;
7180 }
7181#endif
7182 }
7183 else {
7184 VALUE v;
7185 if (!has_vmode) {
7186 v = rb_hash_aref(opthash, sym_mode);
7187 if (!NIL_P(v)) {
7188 if (!NIL_P(vmode)) {
7189 rb_raise(rb_eArgError, "mode specified twice");
7190 }
7191 has_vmode = 1;
7192 vmode = v;
7193 goto vmode_handle;
7194 }
7195 }
7196 v = rb_hash_aref(opthash, sym_flags);
7197 if (!NIL_P(v)) {
7198 v = rb_to_int(v);
7199 oflags |= NUM2INT(v);
7200 vmode = INT2NUM(oflags);
7201 fmode = rb_io_oflags_fmode(oflags);
7202 }
7203 extract_binmode(opthash, &fmode);
7204 if (fmode & FMODE_BINMODE) {
7205#ifdef O_BINARY
7206 oflags |= O_BINARY;
7207#endif
7208 if (!has_enc)
7209 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7210 }
7211#if DEFAULT_TEXTMODE
7212 else if (NIL_P(vmode)) {
7213 fmode |= DEFAULT_TEXTMODE;
7214 }
7215#endif
7216 v = rb_hash_aref(opthash, sym_perm);
7217 if (!NIL_P(v)) {
7218 if (vperm_p) {
7219 if (!NIL_P(*vperm_p)) {
7220 rb_raise(rb_eArgError, "perm specified twice");
7221 }
7222 *vperm_p = v;
7223 }
7224 else {
7225 /* perm no use, just ignore */
7226 }
7227 }
7228 ecflags = (fmode & FMODE_READABLE) ?
7231#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7232 ecflags |= (fmode & FMODE_WRITABLE) ?
7233 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7234 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7235#endif
7236
7237 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7238 if (has_enc) {
7239 rb_raise(rb_eArgError, "encoding specified twice");
7240 }
7241 }
7242 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7243 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7244 }
7245
7246 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7247
7248 *vmode_p = vmode;
7249
7250 *oflags_p = oflags;
7251 *fmode_p = fmode;
7252 convconfig_p->enc = enc;
7253 convconfig_p->enc2 = enc2;
7254 convconfig_p->ecflags = ecflags;
7255 convconfig_p->ecopts = ecopts;
7256}
7257
7259 VALUE fname;
7260 int oflags;
7261 mode_t perm;
7262};
7263
7264static void *
7265sysopen_func(void *ptr)
7266{
7267 const struct sysopen_struct *data = ptr;
7268 const char *fname = RSTRING_PTR(data->fname);
7269 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7270}
7271
7272static inline int
7273rb_sysopen_internal(struct sysopen_struct *data)
7274{
7275 int fd;
7276 do {
7277 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7278 } while (fd < 0 && errno == EINTR);
7279 if (0 <= fd)
7280 rb_update_max_fd(fd);
7281 return fd;
7282}
7283
7284static int
7285rb_sysopen(VALUE fname, int oflags, mode_t perm)
7286{
7287 int fd = -1;
7288 struct sysopen_struct data;
7289
7290 data.fname = rb_str_encode_ospath(fname);
7291 StringValueCStr(data.fname);
7292 data.oflags = oflags;
7293 data.perm = perm;
7294
7295 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7296 rb_syserr_fail_path(first_errno, fname);
7297 }
7298 return fd;
7299}
7300
7301static inline FILE *
7302fdopen_internal(int fd, const char *modestr)
7303{
7304 FILE *file;
7305
7306#if defined(__sun)
7307 errno = 0;
7308#endif
7309 file = fdopen(fd, modestr);
7310 if (!file) {
7311#ifdef _WIN32
7312 if (errno == 0) errno = EINVAL;
7313#elif defined(__sun)
7314 if (errno == 0) errno = EMFILE;
7315#endif
7316 }
7317 return file;
7318}
7319
7320FILE *
7321rb_fdopen(int fd, const char *modestr)
7322{
7323 FILE *file = 0;
7324
7325 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7326 rb_syserr_fail(first_errno, 0);
7327 }
7328
7329 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7330#ifdef USE_SETVBUF
7331 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7332 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7333#endif
7334 return file;
7335}
7336
7337static int
7338io_check_tty(rb_io_t *fptr)
7339{
7340 int t = isatty(fptr->fd);
7341 if (t)
7342 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7343 return t;
7344}
7345
7346static VALUE rb_io_internal_encoding(VALUE);
7347static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7348
7349static int
7350io_strip_bom(VALUE io)
7351{
7352 VALUE b1, b2, b3, b4;
7353 rb_io_t *fptr;
7354
7355 GetOpenFile(io, fptr);
7356 if (!(fptr->mode & FMODE_READABLE)) return 0;
7357 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7358 switch (b1) {
7359 case INT2FIX(0xEF):
7360 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7361 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7362 if (b3 == INT2FIX(0xBF)) {
7363 return rb_utf8_encindex();
7364 }
7365 rb_io_ungetbyte(io, b3);
7366 }
7367 rb_io_ungetbyte(io, b2);
7368 break;
7369
7370 case INT2FIX(0xFE):
7371 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7372 if (b2 == INT2FIX(0xFF)) {
7373 return ENCINDEX_UTF_16BE;
7374 }
7375 rb_io_ungetbyte(io, b2);
7376 break;
7377
7378 case INT2FIX(0xFF):
7379 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7380 if (b2 == INT2FIX(0xFE)) {
7381 b3 = rb_io_getbyte(io);
7382 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7383 if (b4 == INT2FIX(0)) {
7384 return ENCINDEX_UTF_32LE;
7385 }
7386 rb_io_ungetbyte(io, b4);
7387 }
7388 rb_io_ungetbyte(io, b3);
7389 return ENCINDEX_UTF_16LE;
7390 }
7391 rb_io_ungetbyte(io, b2);
7392 break;
7393
7394 case INT2FIX(0):
7395 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7396 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7397 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7398 if (b4 == INT2FIX(0xFF)) {
7399 return ENCINDEX_UTF_32BE;
7400 }
7401 rb_io_ungetbyte(io, b4);
7402 }
7403 rb_io_ungetbyte(io, b3);
7404 }
7405 rb_io_ungetbyte(io, b2);
7406 break;
7407 }
7408 rb_io_ungetbyte(io, b1);
7409 return 0;
7410}
7411
7412static rb_encoding *
7413io_set_encoding_by_bom(VALUE io)
7414{
7415 int idx = io_strip_bom(io);
7416 rb_io_t *fptr;
7417 rb_encoding *extenc = NULL;
7418
7419 GetOpenFile(io, fptr);
7420 if (idx) {
7421 extenc = rb_enc_from_index(idx);
7422 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7423 rb_io_internal_encoding(io), Qnil);
7424 }
7425 else {
7426 fptr->encs.enc2 = NULL;
7427 }
7428 return extenc;
7429}
7430
7431static VALUE
7432rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7433 const struct rb_io_encoding *convconfig, mode_t perm)
7434{
7435 VALUE pathv;
7436 rb_io_t *fptr;
7437 struct rb_io_encoding cc;
7438 if (!convconfig) {
7439 /* Set to default encodings */
7440 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7441 cc.ecflags = 0;
7442 cc.ecopts = Qnil;
7443 convconfig = &cc;
7444 }
7445 validate_enc_binmode(&fmode, convconfig->ecflags,
7446 convconfig->enc, convconfig->enc2);
7447
7448 MakeOpenFile(io, fptr);
7449 fptr->mode = fmode;
7450 fptr->encs = *convconfig;
7451 pathv = rb_str_new_frozen(filename);
7452#ifdef O_TMPFILE
7453 if (!(oflags & O_TMPFILE)) {
7454 fptr->pathv = pathv;
7455 }
7456#else
7457 fptr->pathv = pathv;
7458#endif
7459 fptr->fd = rb_sysopen(pathv, oflags, perm);
7460 io_check_tty(fptr);
7461 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7462
7463 return io;
7464}
7465
7466static VALUE
7467rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7468{
7469 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7470 const char *p = strchr(modestr, ':');
7471 struct rb_io_encoding convconfig;
7472
7473 if (p) {
7474 parse_mode_enc(p+1, rb_usascii_encoding(),
7475 &convconfig.enc, &convconfig.enc2, &fmode);
7476 }
7477 else {
7478 rb_encoding *e;
7479 /* Set to default encodings */
7480
7481 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7482 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7483 }
7484
7485 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7488#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7489 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7490 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7491 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7492#endif
7493 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7494 convconfig.ecopts = Qnil;
7495
7496 return rb_file_open_generic(io, filename,
7497 rb_io_fmode_oflags(fmode),
7498 fmode,
7499 &convconfig,
7500 0666);
7501}
7502
7503VALUE
7504rb_file_open_str(VALUE fname, const char *modestr)
7505{
7506 FilePathValue(fname);
7507 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7508}
7509
7510VALUE
7511rb_file_open(const char *fname, const char *modestr)
7512{
7513 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7514}
7515
7516#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7517static struct pipe_list {
7518 rb_io_t *fptr;
7519 struct pipe_list *next;
7520} *pipe_list;
7521
7522static void
7523pipe_add_fptr(rb_io_t *fptr)
7524{
7525 struct pipe_list *list;
7526
7527 list = ALLOC(struct pipe_list);
7528 list->fptr = fptr;
7529 list->next = pipe_list;
7530 pipe_list = list;
7531}
7532
7533static void
7534pipe_del_fptr(rb_io_t *fptr)
7535{
7536 struct pipe_list **prev = &pipe_list;
7537 struct pipe_list *tmp;
7538
7539 while ((tmp = *prev) != 0) {
7540 if (tmp->fptr == fptr) {
7541 *prev = tmp->next;
7542 free(tmp);
7543 return;
7544 }
7545 prev = &tmp->next;
7546 }
7547}
7548
7549#if defined (_WIN32) || defined(__CYGWIN__)
7550static void
7551pipe_atexit(void)
7552{
7553 struct pipe_list *list = pipe_list;
7554 struct pipe_list *tmp;
7555
7556 /* The CRT calls this on whichever thread calls ExitProcess, which can be
7557 * one Ruby does not know, e.g. the console control handler on Ctrl+Break. */
7558 if (!rb_current_execution_context(false)) return;
7559
7560 while (list) {
7561 tmp = list->next;
7562 rb_io_fptr_finalize(list->fptr);
7563 list = tmp;
7564 }
7565}
7566#endif
7567
7568static void
7569pipe_finalize(rb_io_t *fptr, int noraise)
7570{
7571#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7572 int status = 0;
7573 if (fptr->stdio_file) {
7574 status = pclose(fptr->stdio_file);
7575 }
7576 fptr->fd = -1;
7577 fptr->stdio_file = 0;
7578 rb_last_status_set(status, fptr->pid);
7579#else
7580 fptr_finalize(fptr, noraise);
7581#endif
7582 pipe_del_fptr(fptr);
7583}
7584#endif
7585
7586static void
7587fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7588{
7589#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7590 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7591
7592 if (old_finalize == orig->finalize) return;
7593#endif
7594
7595 fptr->finalize = orig->finalize;
7596
7597#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7598 if (old_finalize != pipe_finalize) {
7599 struct pipe_list *list;
7600 for (list = pipe_list; list; list = list->next) {
7601 if (list->fptr == fptr) break;
7602 }
7603 if (!list) pipe_add_fptr(fptr);
7604 }
7605 else {
7606 pipe_del_fptr(fptr);
7607 }
7608#endif
7609}
7610
7611void
7613{
7615 fptr->mode |= FMODE_SYNC;
7616}
7617
7618
7619int
7620rb_pipe(int *pipes)
7621{
7622 int ret;
7623 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7624 if (ret == 0) {
7625 rb_update_max_fd(pipes[0]);
7626 rb_update_max_fd(pipes[1]);
7627 }
7628 return ret;
7629}
7630
7631#ifdef _WIN32
7632#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7633#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7634#endif
7635
7636#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7637struct popen_arg {
7638 VALUE execarg_obj;
7639 struct rb_execarg *eargp;
7640 int modef;
7641 int pair[2];
7642 int write_pair[2];
7643};
7644#endif
7645
7646#ifdef HAVE_WORKING_FORK
7647# ifndef __EMSCRIPTEN__
7648static void
7649popen_redirect(struct popen_arg *p)
7650{
7651 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7652 close(p->write_pair[1]);
7653 if (p->write_pair[0] != 0) {
7654 dup2(p->write_pair[0], 0);
7655 close(p->write_pair[0]);
7656 }
7657 close(p->pair[0]);
7658 if (p->pair[1] != 1) {
7659 dup2(p->pair[1], 1);
7660 close(p->pair[1]);
7661 }
7662 }
7663 else if (p->modef & FMODE_READABLE) {
7664 close(p->pair[0]);
7665 if (p->pair[1] != 1) {
7666 dup2(p->pair[1], 1);
7667 close(p->pair[1]);
7668 }
7669 }
7670 else {
7671 close(p->pair[1]);
7672 if (p->pair[0] != 0) {
7673 dup2(p->pair[0], 0);
7674 close(p->pair[0]);
7675 }
7676 }
7677}
7678# endif
7679
7680#if defined(__linux__)
7681/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7682 * Since /proc may not be available, linux_get_maxfd is just a hint.
7683 * This function, linux_get_maxfd, must be async-signal-safe.
7684 * I.e. opendir() is not usable.
7685 *
7686 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7687 * However they are easy to re-implement in async-signal-safe manner.
7688 * (Also note that there is missing/memcmp.c.)
7689 */
7690static int
7691linux_get_maxfd(void)
7692{
7693 int fd;
7694 char buf[4096], *p, *np, *e;
7695 ssize_t ss;
7696 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7697 if (fd < 0) return fd;
7698 ss = read(fd, buf, sizeof(buf));
7699 if (ss < 0) goto err;
7700 p = buf;
7701 e = buf + ss;
7702 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7703 (np = memchr(p, '\n', e-p)) != NULL) {
7704 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7705 int fdsize;
7706 p += sizeof("FDSize:")-1;
7707 *np = '\0';
7708 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7709 close(fd);
7710 return fdsize;
7711 }
7712 p = np+1;
7713 }
7714 /* fall through */
7715
7716 err:
7717 close(fd);
7718 return (int)ss;
7719}
7720#endif
7721
7722/* This function should be async-signal-safe. */
7723void
7724rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7725{
7726#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7727 int fd, ret;
7728 int max = (int)max_file_descriptor;
7729# ifdef F_MAXFD
7730 /* F_MAXFD is available since NetBSD 2.0. */
7731 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7732 if (ret != -1)
7733 maxhint = max = ret;
7734# elif defined(__linux__)
7735 ret = linux_get_maxfd();
7736 if (maxhint < ret)
7737 maxhint = ret;
7738 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7739# endif
7740 if (max < maxhint)
7741 max = maxhint;
7742 for (fd = lowfd; fd <= max; fd++) {
7743 if (!NIL_P(noclose_fds) &&
7744 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7745 continue;
7746 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7747 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7748 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7749 }
7750# define CONTIGUOUS_CLOSED_FDS 20
7751 if (ret != -1) {
7752 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7753 max = fd + CONTIGUOUS_CLOSED_FDS;
7754 }
7755 }
7756#endif
7757}
7758
7759# ifndef __EMSCRIPTEN__
7760static int
7761popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7762{
7763 struct popen_arg *p = (struct popen_arg*)pp;
7764
7765 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7766}
7767# endif
7768#endif
7769
7770#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7771static VALUE
7772rb_execarg_fixup_v(VALUE execarg_obj)
7773{
7774 rb_execarg_parent_start(execarg_obj);
7775 return Qnil;
7776}
7777#else
7778char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7779#endif
7780
7781#ifndef __EMSCRIPTEN__
7782static VALUE
7783pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7784 const struct rb_io_encoding *convconfig)
7785{
7786 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7787 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7788 rb_pid_t pid = 0;
7789 rb_io_t *fptr;
7790 VALUE port;
7791 rb_io_t *write_fptr;
7792 VALUE write_port;
7793#if defined(HAVE_WORKING_FORK)
7794 int status;
7795 char errmsg[80] = { '\0' };
7796#endif
7797#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7798 int state;
7799 struct popen_arg arg;
7800#endif
7801 int e = 0;
7802#if defined(HAVE_SPAWNV)
7803# define DO_SPAWN(cmd, args) ((args) ? \
7804 spawnv(P_NOWAIT, (cmd), (args)) : \
7805 spawn(P_NOWAIT, (cmd)))
7806# if !defined(HAVE_WORKING_FORK)
7807 char **args = NULL;
7808# endif
7809#endif
7810#if !defined(HAVE_WORKING_FORK)
7811 struct rb_execarg sarg, *sargp = &sarg;
7812#endif
7813 FILE *fp = 0;
7814 int fd = -1;
7815 int write_fd = -1;
7816#if !defined(HAVE_WORKING_FORK)
7817 const char *cmd = 0;
7818
7819 if (prog)
7820 cmd = StringValueCStr(prog);
7821#endif
7822
7823#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7824 arg.execarg_obj = execarg_obj;
7825 arg.eargp = eargp;
7826 arg.modef = fmode;
7827 arg.pair[0] = arg.pair[1] = -1;
7828 arg.write_pair[0] = arg.write_pair[1] = -1;
7829# if !defined(HAVE_WORKING_FORK)
7830 if (eargp && !eargp->use_shell) {
7831 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7832 }
7833# endif
7834 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7836 if (rb_pipe(arg.write_pair) < 0)
7837 rb_sys_fail_str(prog);
7838 if (rb_pipe(arg.pair) < 0) {
7839 e = errno;
7840 close(arg.write_pair[0]);
7841 close(arg.write_pair[1]);
7842 rb_syserr_fail_str(e, prog);
7843 }
7844 if (eargp) {
7845 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7846 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7847 }
7848 break;
7849 case FMODE_READABLE:
7850 if (rb_pipe(arg.pair) < 0)
7851 rb_sys_fail_str(prog);
7852 if (eargp)
7853 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7854 break;
7855 case FMODE_WRITABLE:
7856 if (rb_pipe(arg.pair) < 0)
7857 rb_sys_fail_str(prog);
7858 if (eargp)
7859 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7860 break;
7861 default:
7862 rb_sys_fail_str(prog);
7863 }
7864 if (!NIL_P(execarg_obj)) {
7865 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7866 if (state) {
7867 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7868 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7869 if (0 <= arg.pair[0]) close(arg.pair[0]);
7870 if (0 <= arg.pair[1]) close(arg.pair[1]);
7871 rb_execarg_parent_end(execarg_obj);
7872 rb_jump_tag(state);
7873 }
7874
7875# if defined(HAVE_WORKING_FORK)
7876 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7877# else
7878 rb_execarg_run_options(eargp, sargp, NULL, 0);
7879 while ((pid = DO_SPAWN(cmd, args)) < 0) {
7880 /* exec failed */
7881 switch (e = errno) {
7882 case EAGAIN:
7883# if EWOULDBLOCK != EAGAIN
7884 case EWOULDBLOCK:
7885# endif
7886 rb_thread_sleep(1);
7887 continue;
7888 }
7889 break;
7890 }
7891 if (eargp)
7892 rb_execarg_run_options(sargp, NULL, NULL, 0);
7893# endif
7894 rb_execarg_parent_end(execarg_obj);
7895 }
7896 else {
7897# if defined(HAVE_WORKING_FORK)
7898 pid = rb_call_proc__fork();
7899 if (pid == 0) { /* child */
7900 popen_redirect(&arg);
7901 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7902 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7903 return Qnil;
7904 }
7905# else
7906 rb_notimplement();
7907# endif
7908 }
7909
7910 /* parent */
7911 if (pid < 0) {
7912# if defined(HAVE_WORKING_FORK)
7913 e = errno;
7914# endif
7915 close(arg.pair[0]);
7916 close(arg.pair[1]);
7918 close(arg.write_pair[0]);
7919 close(arg.write_pair[1]);
7920 }
7921# if defined(HAVE_WORKING_FORK)
7922 if (errmsg[0])
7923 rb_syserr_fail(e, errmsg);
7924# endif
7925 rb_syserr_fail_str(e, prog);
7926 }
7927 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7928 close(arg.pair[1]);
7929 fd = arg.pair[0];
7930 close(arg.write_pair[0]);
7931 write_fd = arg.write_pair[1];
7932 }
7933 else if (fmode & FMODE_READABLE) {
7934 close(arg.pair[1]);
7935 fd = arg.pair[0];
7936 }
7937 else {
7938 close(arg.pair[0]);
7939 fd = arg.pair[1];
7940 }
7941#else
7942 cmd = rb_execarg_commandline(eargp, &prog);
7943 if (!NIL_P(execarg_obj)) {
7944 rb_execarg_parent_start(execarg_obj);
7945 rb_execarg_run_options(eargp, sargp, NULL, 0);
7946 }
7947 fp = popen(cmd, modestr);
7948 e = errno;
7949 if (eargp) {
7950 rb_execarg_parent_end(execarg_obj);
7951 rb_execarg_run_options(sargp, NULL, NULL, 0);
7952 }
7953 if (!fp) rb_syserr_fail_path(e, prog);
7954 fd = fileno(fp);
7955#endif
7956
7957 port = io_alloc(rb_cIO);
7958 MakeOpenFile(port, fptr);
7959 fptr->fd = fd;
7960 fptr->stdio_file = fp;
7961 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7962 if (convconfig) {
7963 fptr->encs = *convconfig;
7964#if RUBY_CRLF_ENVIRONMENT
7967 }
7968#endif
7969 }
7970 else {
7971 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7973 }
7974#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7975 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7976 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7977 }
7978#endif
7979 }
7980 fptr->pid = pid;
7981
7982 if (0 <= write_fd) {
7983 write_port = io_alloc(rb_cIO);
7984 MakeOpenFile(write_port, write_fptr);
7985 write_fptr->fd = write_fd;
7986 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7987 fptr->mode &= ~FMODE_WRITABLE;
7988 fptr->tied_io_for_writing = write_port;
7989 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7990 }
7991
7992#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7993 fptr->finalize = pipe_finalize;
7994 pipe_add_fptr(fptr);
7995#endif
7996 return port;
7997}
7998#else
7999static VALUE
8000pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
8001 const struct rb_io_encoding *convconfig)
8002{
8003 rb_raise(rb_eNotImpError, "popen() is not available");
8004}
8005#endif
8006
8007static int
8008is_popen_fork(VALUE prog)
8009{
8010 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
8011#if !defined(HAVE_WORKING_FORK)
8012 rb_raise(rb_eNotImpError,
8013 "fork() function is unimplemented on this machine");
8014#else
8015 return TRUE;
8016#endif
8017 }
8018 return FALSE;
8019}
8020
8021static VALUE
8022pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
8023 const struct rb_io_encoding *convconfig)
8024{
8025 int argc = 1;
8026 VALUE *argv = &prog;
8027 VALUE execarg_obj = Qnil;
8028
8029 if (!is_popen_fork(prog))
8030 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
8031 return pipe_open(execarg_obj, modestr, fmode, convconfig);
8032}
8033
8034static VALUE
8035pipe_close(VALUE io)
8036{
8037 rb_io_t *fptr = io_close_fptr(io);
8038 if (fptr) {
8039 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
8040 }
8041 return Qnil;
8042}
8043
8044static VALUE popen_finish(VALUE port, VALUE klass);
8045
8046/*
8047 * call-seq:
8048 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
8049 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
8050 *
8051 * Executes the given command +cmd+ as a subprocess
8052 * whose $stdin and $stdout are connected to a new stream +io+.
8053 *
8054 * This method has potential security vulnerabilities if called with untrusted input;
8055 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
8056 *
8057 * If no block is given, returns the new stream,
8058 * which depending on given +mode+ may be open for reading, writing, or both.
8059 * The stream should be explicitly closed (eventually) to avoid resource leaks.
8060 *
8061 * If a block is given, the stream is passed to the block
8062 * (again, open for reading, writing, or both);
8063 * when the block exits, the stream is closed,
8064 * the block's value is returned,
8065 * and the global variable <tt>$?</tt> is set to the child's exit status.
8066 *
8067 * Optional argument +mode+ may be any valid \IO mode.
8068 * See {Access Modes}[rdoc-ref:File@Access+Modes].
8069 *
8070 * Required argument +cmd+ determines which of the following occurs:
8071 *
8072 * - The process forks.
8073 * - A specified program runs in a shell.
8074 * - A specified program runs with specified arguments.
8075 * - A specified program runs with specified arguments and a specified +argv0+.
8076 *
8077 * Each of these is detailed below.
8078 *
8079 * The optional hash argument +env+ specifies name/value pairs that are to be added
8080 * to the environment variables for the subprocess:
8081 *
8082 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
8083 * pipe.puts 'puts ENV["FOO"]'
8084 * pipe.close_write
8085 * pipe.gets
8086 * end => "bar\n"
8087 *
8088 * Optional keyword arguments +opts+ specify:
8089 *
8090 * - {Open options}[rdoc-ref:IO@Open+Options].
8091 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8092 * - Options for Kernel#spawn.
8093 *
8094 * <b>Forked Process</b>
8095 *
8096 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
8097 * IO.popen('-') do |pipe|
8098 * if pipe
8099 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
8100 * else
8101 * $stderr.puts "In child, pid is #{$$}\n"
8102 * end
8103 * end
8104 *
8105 * Output:
8106 *
8107 * In parent, child pid is 26253
8108 * In child, pid is 26253
8109 *
8110 * Note that this is not supported on all platforms.
8111 *
8112 * <b>Shell Subprocess</b>
8113 *
8114 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
8115 * the program named +cmd+ is run as a shell command:
8116 *
8117 * IO.popen('uname') do |pipe|
8118 * pipe.readlines
8119 * end
8120 *
8121 * Output:
8122 *
8123 * ["Linux\n"]
8124 *
8125 * Another example:
8126 *
8127 * IO.popen('/bin/sh', 'r+') do |pipe|
8128 * pipe.puts('ls')
8129 * pipe.close_write
8130 * $stderr.puts pipe.readlines.size
8131 * end
8132 *
8133 * Output:
8134 *
8135 * 213
8136 *
8137 * <b>Program Subprocess</b>
8138 *
8139 * When argument +cmd+ is an array of strings,
8140 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
8141 *
8142 * IO.popen(['du', '..', '.']) do |pipe|
8143 * $stderr.puts pipe.readlines.size
8144 * end
8145 *
8146 * Output:
8147 *
8148 * 1111
8149 *
8150 * <b>Program Subprocess with <tt>argv0</tt></b>
8151 *
8152 * When argument +cmd+ is an array whose first element is a 2-element string array
8153 * and whose remaining elements (if any) are strings:
8154 *
8155 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
8156 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
8157 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
8158 *
8159 * Example (sets <tt>$0</tt> to 'foo'):
8160 *
8161 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
8162 *
8163 * <b>Some Special Examples</b>
8164 *
8165 * # Set IO encoding.
8166 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
8167 * euc_jp_string = nkf_io.read
8168 * }
8169 *
8170 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
8171 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
8172 * ls_result_with_error = io.read
8173 * end
8174 *
8175 * # Use mixture of spawn options and IO options.
8176 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
8177 * ls_result_with_error = io.read
8178 * end
8179 *
8180 * f = IO.popen("uname")
8181 * p f.readlines
8182 * f.close
8183 * puts "Parent is #{Process.pid}"
8184 * IO.popen("date") {|f| puts f.gets }
8185 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
8186 * p $?
8187 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
8188 * f.puts "bar"; f.close_write; puts f.gets
8189 * }
8190 *
8191 * Output (from last section):
8192 *
8193 * ["Linux\n"]
8194 * Parent is 21346
8195 * Thu Jan 15 22:41:19 JST 2009
8196 * 21346 is here, f is #<IO:fd 3>
8197 * 21352 is here, f is nil
8198 * #<Process::Status: pid 21352 exit 0>
8199 * <foo>bar;zot;
8200 *
8201 * Raises exceptions that IO.pipe and Kernel.spawn raise.
8202 *
8203 */
8204
8205static VALUE
8206rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
8207{
8208 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
8209
8210 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8211 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8212 switch (argc) {
8213 case 2:
8214 pmode = argv[1];
8215 case 1:
8216 pname = argv[0];
8217 break;
8218 default:
8219 {
8220 int ex = !NIL_P(opt);
8221 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8222 }
8223 }
8224 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8225}
8226
8227VALUE
8228rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8229{
8230 const char *modestr;
8231 VALUE tmp, execarg_obj = Qnil;
8232 int oflags;
8233 enum rb_io_mode fmode;
8234 struct rb_io_encoding convconfig;
8235
8236 tmp = rb_check_array_type(pname);
8237 if (!NIL_P(tmp)) {
8238 rb_len_t len = RARRAY_LEN(tmp);
8239#if SIZEOF_RB_LEN_T > SIZEOF_INT
8240 if (len > INT_MAX) {
8241 rb_raise(rb_eArgError, "too many arguments");
8242 }
8243#endif
8244 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8245 RB_GC_GUARD(tmp);
8246 }
8247 else {
8248 StringValue(pname);
8249 execarg_obj = Qnil;
8250 if (!is_popen_fork(pname))
8251 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8252 }
8253 if (!NIL_P(execarg_obj)) {
8254 if (!NIL_P(opt))
8255 opt = rb_execarg_extract_options(execarg_obj, opt);
8256 if (!NIL_P(env))
8257 rb_execarg_setenv(execarg_obj, env);
8258 }
8259 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8260 modestr = rb_io_oflags_modestr(oflags);
8261
8262 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8263}
8264
8265static VALUE
8266popen_finish(VALUE port, VALUE klass)
8267{
8268 if (NIL_P(port)) {
8269 /* child */
8270 if (rb_block_given_p()) {
8271 rb_protect(rb_yield, Qnil, NULL);
8272 rb_io_flush(rb_ractor_stdout());
8273 rb_io_flush(rb_ractor_stderr());
8274 _exit(EXIT_SUCCESS);
8275 }
8276 return Qnil;
8277 }
8278 RBASIC_SET_CLASS(port, klass);
8279 if (rb_block_given_p()) {
8280 return rb_ensure(rb_yield, port, pipe_close, port);
8281 }
8282 return port;
8283}
8284
8285#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8286struct popen_writer_arg {
8287 char *const *argv;
8288 struct popen_arg popen;
8289};
8290
8291static int
8292exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8293{
8294 struct popen_writer_arg *pw = arg;
8295 pw->popen.modef = FMODE_WRITABLE;
8296 popen_redirect(&pw->popen);
8297 execv(pw->argv[0], pw->argv);
8298 strlcpy(errmsg, strerror(errno), buflen);
8299 return -1;
8300}
8301#endif
8302
8303FILE *
8304ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8305{
8306#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8307# ifdef HAVE_WORKING_FORK
8308 struct popen_writer_arg pw;
8309 int *const write_pair = pw.popen.pair;
8310# else
8311 int write_pair[2];
8312# endif
8313
8314 *pid = -1;
8315 if (cloexec_pipe(write_pair, 0, false) == 0) {
8316# ifdef HAVE_WORKING_FORK
8317 pw.argv = argv;
8318 int status;
8319 char errmsg[80] = {'\0'};
8320 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8321# else
8322 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8323 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8324# endif
8325 close(write_pair[0]);
8326 if (*pid < 0) {
8327 close(write_pair[1]);
8328 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8329 }
8330 else {
8331 return fdopen(write_pair[1], "w");
8332 }
8333 }
8334#endif
8335 return NULL;
8336}
8337
8338static VALUE
8339rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8340{
8341 int oflags;
8342 enum rb_io_mode fmode;
8343 struct rb_io_encoding convconfig;
8344 mode_t perm;
8345
8346 FilePathValue(fname);
8347
8348 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8349 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8350
8351 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8352
8353 return io;
8354}
8355
8356/*
8357 * Document-method: File::open
8358 *
8359 * :markup: markdown
8360 *
8361 * call-seq:
8362 * File.open(path, mode = 'r', permissions = 0666, **options) -> file
8363 * File.open(path, mode = 'r', permissions = 0666, **options) {|file| ... } -> object
8364 *
8365 * Creates a new \File object via File.new with the given arguments.
8366 *
8367 * With no block given, returns the \File object.
8368 *
8369 * With a block given, calls the block with the \File object,
8370 * closes the \File object, and returns the block's value:
8371 *
8372 * ```ruby
8373 * File.open('doc/maintainers.md') {|file| file.size } # => 14900
8374 * ```
8375 *
8376 * Note that the \File object is automatically closed
8377 * even if the block raises an exception.
8378 */
8379
8380/*
8381 * Document-method: IO::open
8382 *
8383 * :markup: markdown
8384 *
8385 * call-seq:
8386 * IO.open(fd, mode = 'r', **options) -> io
8387 * IO.open(fd, mode = 'r', **options) {|io| ... } -> object
8388 *
8389 * Creates a new \IO object via IO.new with the given arguments.
8390 *
8391 * With no block given, returns the \IO object.
8392 *
8393 * With a block given, calls the block with the \IO object,
8394 * closes the \IO object, and returns the block’s value:
8395 *
8396 * ```ruby
8397 * fd = File.sysopen('doc/maintainers.md') # => 6
8398 * IO.open(fd) {|io| io.read.size } # => 14897
8399 * ```
8400 */
8401
8402static VALUE
8403rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8404{
8406
8407 if (rb_block_given_p()) {
8408 return rb_ensure(rb_yield, io, io_close, io);
8409 }
8410
8411 return io;
8412}
8413
8414/*
8415 * call-seq:
8416 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8417 *
8418 * Opens the file at the given path with the given mode and permissions;
8419 * returns the integer file descriptor.
8420 *
8421 * If the file is to be readable, it must exist;
8422 * if the file is to be writable and does not exist,
8423 * it is created with the given permissions:
8424 *
8425 * File.write('t.tmp', '') # => 0
8426 * IO.sysopen('t.tmp') # => 8
8427 * IO.sysopen('t.tmp', 'w') # => 9
8428 *
8429 *
8430 */
8431
8432static VALUE
8433rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8434{
8435 VALUE fname, vmode, vperm;
8436 VALUE intmode;
8437 int oflags, fd;
8438 mode_t perm;
8439
8440 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8441 FilePathValue(fname);
8442
8443 if (NIL_P(vmode))
8444 oflags = O_RDONLY;
8445 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8446 oflags = NUM2INT(intmode);
8447 else {
8448 StringValue(vmode);
8449 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8450 }
8451 if (NIL_P(vperm)) perm = 0666;
8452 else perm = NUM2MODET(vperm);
8453
8454 RB_GC_GUARD(fname) = rb_str_new4(fname);
8455 fd = rb_sysopen(fname, oflags, perm);
8456 return INT2NUM(fd);
8457}
8458
8459/*
8460 * call-seq:
8461 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8462 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8463 *
8464 * Creates an IO object connected to the given file.
8465 *
8466 * With no block given, file stream is returned:
8467 *
8468 * open('t.txt') # => #<File:t.txt>
8469 *
8470 * With a block given, calls the block with the open file stream,
8471 * then closes the stream:
8472 *
8473 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8474 *
8475 * Output:
8476 *
8477 * #<File:t.txt>
8478 *
8479 * See File.open for details.
8480 *
8481 */
8482
8483static VALUE
8484rb_f_open(int argc, VALUE *argv, VALUE _)
8485{
8486 ID to_open = 0;
8487 int redirect = FALSE;
8488
8489 if (argc >= 1) {
8490 CONST_ID(to_open, "to_open");
8491 if (rb_respond_to(argv[0], to_open)) {
8492 redirect = TRUE;
8493 }
8494 else {
8495 VALUE tmp = argv[0];
8496 FilePathValue(tmp);
8497 if (NIL_P(tmp)) {
8498 redirect = TRUE;
8499 }
8500 else {
8501 argv[0] = tmp;
8502 }
8503 }
8504 }
8505 if (redirect) {
8506 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8507
8508 if (rb_block_given_p()) {
8509 return rb_ensure(rb_yield, io, io_close, io);
8510 }
8511 return io;
8512 }
8513 return rb_io_s_open(argc, argv, rb_cFile);
8514}
8515
8516static VALUE
8517rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8518 const struct rb_io_encoding *convconfig, mode_t perm)
8519{
8520 return rb_file_open_generic(io_alloc(klass), filename,
8521 oflags, fmode, convconfig, perm);
8522}
8523
8524static VALUE
8525rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8526{
8527 int oflags;
8528 enum rb_io_mode fmode;
8529 struct rb_io_encoding convconfig;
8530 mode_t perm;
8531
8532 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8533 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8534 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8535}
8536
8537static VALUE
8538io_reopen(VALUE io, VALUE nfile)
8539{
8540 rb_io_t *fptr, *orig;
8541 int fd, fd2;
8542 rb_off_t pos = 0;
8543
8544 nfile = rb_io_get_io(nfile);
8545 GetOpenFile(io, fptr);
8546 GetOpenFile(nfile, orig);
8547
8548 if (fptr == orig) return io;
8549 if (RUBY_IO_EXTERNAL_P(fptr)) {
8550 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8551 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8552 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8553 rb_raise(rb_eArgError,
8554 "%s can't change access mode from \"%s\" to \"%s\"",
8555 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8556 rb_io_fmode_modestr(orig->mode));
8557 }
8558 }
8559 flush_before_seek(fptr, true);
8560 /* in flush_before_seek, clear_codeconv called only if rbuf is filled */
8561 clear_codeconv(fptr);
8562 if (orig->mode & FMODE_READABLE) {
8563 pos = io_tell(orig);
8564 }
8565 if (orig->mode & FMODE_WRITABLE) {
8566 if (io_fflush(orig) < 0)
8567 rb_sys_fail_on_write(fptr);
8568 }
8569
8570 /* copy rb_io_t structure */
8571 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8572 fptr->encs = orig->encs;
8573 fptr->pid = orig->pid;
8574 fptr->lineno = orig->lineno;
8575 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8576 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8577 fptr_copy_finalizer(fptr, orig);
8578
8579 fd = fptr->fd;
8580 fd2 = orig->fd;
8581 if (fd != fd2) {
8582 // Interrupt all usage of the old file descriptor:
8583 rb_thread_io_close_interrupt(fptr);
8584 rb_thread_io_close_wait(fptr);
8585
8586 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8587 /* need to keep FILE objects of stdin, stdout and stderr */
8588 if (rb_cloexec_dup2(fd2, fd) < 0)
8589 rb_sys_fail_path(orig->pathv);
8590 rb_update_max_fd(fd);
8591 }
8592 else {
8593 fclose(fptr->stdio_file);
8594 fptr->stdio_file = 0;
8595 fptr->fd = -1;
8596 if (rb_cloexec_dup2(fd2, fd) < 0)
8597 rb_sys_fail_path(orig->pathv);
8598 rb_update_max_fd(fd);
8599 fptr->fd = fd;
8600 }
8601
8602 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8603 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8604 rb_sys_fail_path(fptr->pathv);
8605 }
8606 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8607 rb_sys_fail_path(orig->pathv);
8608 }
8609 }
8610 }
8611
8612 if (fptr->mode & FMODE_BINMODE) {
8613 rb_io_binmode(io);
8614 }
8615
8616 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8617 return io;
8618}
8619
8620#ifdef _WIN32
8621int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8622#else
8623static int
8624rb_freopen(VALUE fname, const char *mode, FILE *fp)
8625{
8626 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8627 RB_GC_GUARD(fname);
8628 return errno;
8629 }
8630 return 0;
8631}
8632#endif
8633
8634/*
8635 * call-seq:
8636 * reopen(other_io) -> self
8637 * reopen(path, mode = 'r', **opts) -> self
8638 *
8639 * Reassociates the stream with another stream,
8640 * which may be of a different class.
8641 * This method may be used to redirect an existing stream
8642 * to a new destination.
8643 *
8644 * With argument +other_io+ given, reassociates with that stream:
8645 *
8646 * # Redirect $stdin from a file.
8647 * f = File.open('t.txt')
8648 * $stdin.reopen(f)
8649 * f.close
8650 *
8651 * # Redirect $stdout to a file.
8652 * f = File.open('t.tmp', 'w')
8653 * $stdout.reopen(f)
8654 * f.close
8655 *
8656 * With argument +path+ given, reassociates with a new stream to that file path:
8657 *
8658 * $stdin.reopen('t.txt')
8659 * $stdout.reopen('t.tmp', 'w')
8660 *
8661 * Optional keyword arguments +opts+ specify:
8662 *
8663 * - {Open Options}[rdoc-ref:IO@Open+Options].
8664 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8665 *
8666 */
8667
8668static VALUE
8669rb_io_reopen(int argc, VALUE *argv, VALUE file)
8670{
8671 VALUE fname, nmode, opt;
8672 int oflags;
8673 rb_io_t *fptr;
8674
8675 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8676 VALUE tmp = rb_io_check_io(fname);
8677 if (!NIL_P(tmp)) {
8678 return io_reopen(file, tmp);
8679 }
8680 }
8681
8682 FilePathValue(fname);
8683 rb_io_taint_check(file);
8684 fptr = RFILE(file)->fptr;
8686
8687 if (!NIL_P(nmode) || !NIL_P(opt)) {
8688 enum rb_io_mode fmode;
8689 struct rb_io_encoding convconfig;
8690
8691 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8692 if (RUBY_IO_EXTERNAL_P(fptr) &&
8693 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8694 (fptr->mode & FMODE_READWRITE)) {
8695 rb_raise(rb_eArgError,
8696 "%s can't change access mode from \"%s\" to \"%s\"",
8697 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8698 rb_io_fmode_modestr(fmode));
8699 }
8700 fptr->mode = fmode;
8701 fptr->encs = convconfig;
8702 }
8703 else {
8704 oflags = rb_io_fmode_oflags(fptr->mode);
8705 }
8706
8707 fptr->pathv = fname;
8708 if (fptr->fd < 0) {
8709 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8710 fptr->stdio_file = 0;
8711 return file;
8712 }
8713
8714 if (fptr->mode & FMODE_WRITABLE) {
8715 if (io_fflush(fptr) < 0)
8716 rb_sys_fail_on_write(fptr);
8717 }
8718 fptr->rbuf.off = fptr->rbuf.len = 0;
8719 clear_codeconv(fptr);
8720
8721 if (fptr->stdio_file) {
8722 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8723 rb_io_oflags_modestr(oflags),
8724 fptr->stdio_file);
8725 if (e) rb_syserr_fail_path(e, fptr->pathv);
8726 fptr->fd = fileno(fptr->stdio_file);
8727 rb_fd_fix_cloexec(fptr->fd);
8728#ifdef USE_SETVBUF
8729 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8730 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8731#endif
8732 if (fptr->stdio_file == stderr) {
8733 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8734 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8735 }
8736 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8737 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8738 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8739 }
8740 }
8741 else {
8742 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8743 int err = 0;
8744 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8745 err = errno;
8746 (void)close(tmpfd);
8747 if (err) {
8748 rb_syserr_fail_path(err, fptr->pathv);
8749 }
8750 }
8751
8752 return file;
8753}
8754
8755/* :nodoc: */
8756static VALUE
8757rb_io_init_copy(VALUE dest, VALUE io)
8758{
8759 rb_io_t *fptr, *orig;
8760 int fd;
8761 VALUE write_io;
8762 rb_off_t pos;
8763
8764 io = rb_io_get_io(io);
8765 if (!OBJ_INIT_COPY(dest, io)) return dest;
8766 GetOpenFile(io, orig);
8767 MakeOpenFile(dest, fptr);
8768
8769 rb_io_flush(io);
8770
8771 /* copy rb_io_t structure */
8772 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8773 fptr->encs = orig->encs;
8774 fptr->pid = orig->pid;
8775 fptr->lineno = orig->lineno;
8776 fptr->timeout = orig->timeout;
8777
8778 ccan_list_head_init(&fptr->blocking_operations);
8779 fptr->closing_ec = NULL;
8780 fptr->wakeup_mutex = Qnil;
8781 fptr->fork_generation = GET_VM()->fork_gen;
8782
8783 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8784 fptr_copy_finalizer(fptr, orig);
8785
8786 fd = ruby_dup(orig->fd);
8787 fptr->fd = fd;
8788 pos = io_tell(orig);
8789 if (0 <= pos)
8790 io_seek(fptr, pos, SEEK_SET);
8791 if (fptr->mode & FMODE_BINMODE) {
8792 rb_io_binmode(dest);
8793 }
8794
8795 write_io = GetWriteIO(io);
8796 if (io != write_io) {
8797 write_io = rb_obj_dup(write_io);
8798 fptr->tied_io_for_writing = write_io;
8799 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8800 }
8801
8802 return dest;
8803}
8804
8805/*
8806 * call-seq:
8807 * printf(format_string, *objects) -> nil
8808 *
8809 * Formats and writes +objects+ to the stream.
8810 *
8811 * For details on +format_string+, see
8812 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8813 *
8814 */
8815
8816VALUE
8817rb_io_printf(int argc, const VALUE *argv, VALUE out)
8818{
8819 rb_io_write(out, rb_f_sprintf(argc, argv));
8820 return Qnil;
8821}
8822
8823/*
8824 * call-seq:
8825 * printf(format_string, *objects) -> nil
8826 * printf(io, format_string, *objects) -> nil
8827 *
8828 * Equivalent to:
8829 *
8830 * io.write(sprintf(format_string, *objects))
8831 *
8832 * For details on +format_string+, see
8833 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8834 *
8835 * With the single argument +format_string+, formats +objects+ into the string,
8836 * then writes the formatted string to $stdout:
8837 *
8838 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8839 *
8840 * Output (on $stdout):
8841 *
8842 * 0024 24 24.00#
8843 *
8844 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8845 * then writes the formatted string to +io+:
8846 *
8847 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8848 *
8849 * Output (on $stderr):
8850 *
8851 * 0024 24 24.00# => nil
8852 *
8853 * With no arguments, does nothing.
8854 *
8855 */
8856
8857static VALUE
8858rb_f_printf(int argc, VALUE *argv, VALUE _)
8859{
8860 VALUE out;
8861
8862 if (argc == 0) return Qnil;
8863 if (RB_TYPE_P(argv[0], T_STRING)) {
8864 out = rb_ractor_stdout();
8865 }
8866 else {
8867 out = argv[0];
8868 argv++;
8869 argc--;
8870 }
8871 rb_io_write(out, rb_f_sprintf(argc, argv));
8872
8873 return Qnil;
8874}
8875
8876extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
8877
8878static void
8879deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8880{
8881 rb_deprecated_str_setter(val, id, &val);
8882 if (!NIL_P(val)) {
8883 if (rb_str_equal(val, rb_default_rs)) {
8884 val = rb_default_rs;
8885 }
8886 else {
8887 val = rb_str_frozen_bare_string(val);
8888 }
8889 }
8890 *var = val;
8891}
8892
8893/*
8894 * call-seq:
8895 * print(*objects) -> nil
8896 *
8897 * Writes the given objects to the stream; returns +nil+.
8898 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8899 * (<tt>$\</tt>), if it is not +nil+.
8900 * See {Line IO}[rdoc-ref:IO@Line+IO].
8901 *
8902 * With argument +objects+ given, for each object:
8903 *
8904 * - Converts via its method +to_s+ if not a string.
8905 * - Writes to the stream.
8906 * - If not the last object, writes the output field separator
8907 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8908 *
8909 * With default separators:
8910 *
8911 * f = File.open('t.tmp', 'w+')
8912 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8913 * p $OUTPUT_RECORD_SEPARATOR
8914 * p $OUTPUT_FIELD_SEPARATOR
8915 * f.print(*objects)
8916 * f.rewind
8917 * p f.read
8918 * f.close
8919 *
8920 * Output:
8921 *
8922 * nil
8923 * nil
8924 * "00.00/10+0izerozero"
8925 *
8926 * With specified separators:
8927 *
8928 * $\ = "\n"
8929 * $, = ','
8930 * f.rewind
8931 * f.print(*objects)
8932 * f.rewind
8933 * p f.read
8934 *
8935 * Output:
8936 *
8937 * "0,0.0,0/1,0+0i,zero,zero\n"
8938 *
8939 * With no argument given, writes the content of <tt>$_</tt>
8940 * (which is usually the most recent user input):
8941 *
8942 * f = File.open('t.tmp', 'w+')
8943 * gets # Sets $_ to the most recent user input.
8944 * f.print
8945 * f.close
8946 *
8947 */
8948
8949VALUE
8950rb_io_print(int argc, const VALUE *argv, VALUE out)
8951{
8952 int i;
8953 VALUE line;
8954
8955 /* if no argument given, print `$_' */
8956 if (argc == 0) {
8957 argc = 1;
8958 line = rb_lastline_get();
8959 argv = &line;
8960 }
8961 if (argc > 1 && !NIL_P(rb_output_fs)) {
8962 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8963 }
8964 for (i=0; i<argc; i++) {
8965 if (!NIL_P(rb_output_fs) && i>0) {
8966 rb_io_write(out, rb_output_fs);
8967 }
8968 rb_io_write(out, argv[i]);
8969 }
8970 if (argc > 0 && !NIL_P(rb_output_rs)) {
8971 rb_io_write(out, rb_output_rs);
8972 }
8973
8974 return Qnil;
8975}
8976
8977/*
8978 * call-seq:
8979 * print(*objects) -> nil
8980 *
8981 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8982 * this method is the straightforward way to write to <tt>$stdout</tt>.
8983 *
8984 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8985 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8986 * (<tt>$\</tt>), if it is not +nil+.
8987 *
8988 * With argument +objects+ given, for each object:
8989 *
8990 * - Converts via its method +to_s+ if not a string.
8991 * - Writes to <tt>stdout</tt>.
8992 * - If not the last object, writes the output field separator
8993 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8994 *
8995 * With default separators:
8996 *
8997 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8998 * $OUTPUT_RECORD_SEPARATOR
8999 * $OUTPUT_FIELD_SEPARATOR
9000 * print(*objects)
9001 *
9002 * Output:
9003 *
9004 * nil
9005 * nil
9006 * 00.00/10+0izerozero
9007 *
9008 * With specified separators:
9009 *
9010 * $OUTPUT_RECORD_SEPARATOR = "\n"
9011 * $OUTPUT_FIELD_SEPARATOR = ','
9012 * print(*objects)
9013 *
9014 * Output:
9015 *
9016 * 0,0.0,0/1,0+0i,zero,zero
9017 *
9018 * With no argument given, writes the content of <tt>$_</tt>
9019 * (which is usually the most recent user input):
9020 *
9021 * gets # Sets $_ to the most recent user input.
9022 * print # Prints $_.
9023 *
9024 */
9025
9026static VALUE
9027rb_f_print(int argc, const VALUE *argv, VALUE _)
9028{
9029 rb_io_print(argc, argv, rb_ractor_stdout());
9030 return Qnil;
9031}
9032
9033/*
9034 * call-seq:
9035 * putc(object) -> object
9036 *
9037 * Writes a character to the stream.
9038 * See {Character IO}[rdoc-ref:IO@Character+IO].
9039 *
9040 * If +object+ is numeric, converts to integer if necessary,
9041 * then writes the character whose code is the
9042 * least significant byte;
9043 * if +object+ is a string, writes the first character:
9044 *
9045 * $stdout.putc "A"
9046 * $stdout.putc 65
9047 *
9048 * Output:
9049 *
9050 * AA
9051 *
9052 */
9053
9054static VALUE
9055rb_io_putc(VALUE io, VALUE ch)
9056{
9057 VALUE str;
9058 if (RB_TYPE_P(ch, T_STRING)) {
9059 str = rb_str_substr(ch, 0, 1);
9060 }
9061 else {
9062 char c = NUM2CHR(ch);
9063 str = rb_str_new(&c, 1);
9064 }
9065 rb_io_write(io, str);
9066 return ch;
9067}
9068
9069#define forward(obj, id, argc, argv) \
9070 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9071#define forward_public(obj, id, argc, argv) \
9072 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9073#define forward_current(id, argc, argv) \
9074 forward_public(ARGF.current_file, id, argc, argv)
9075
9076/*
9077 * call-seq:
9078 * putc(int) -> int
9079 *
9080 * Equivalent to:
9081 *
9082 * $stdout.putc(int)
9083 *
9084 * See IO#putc for important information regarding multi-byte characters.
9085 *
9086 */
9087
9088static VALUE
9089rb_f_putc(VALUE recv, VALUE ch)
9090{
9091 VALUE r_stdout = rb_ractor_stdout();
9092 if (recv == r_stdout) {
9093 return rb_io_putc(recv, ch);
9094 }
9095 return forward(r_stdout, rb_intern("putc"), 1, &ch);
9096}
9097
9098
9099int
9100rb_str_end_with_asciichar(VALUE str, int c)
9101{
9102 rb_len_t len = RSTRING_LEN(str);
9103 const char *ptr = RSTRING_PTR(str);
9104 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
9105 int n;
9106
9107 if (len == 0) return 0;
9108 if ((n = rb_enc_mbminlen(enc)) == 1) {
9109 return ptr[len - 1] == c;
9110 }
9111 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
9112}
9113
9114static VALUE
9115io_puts_ary(VALUE ary, VALUE out, int recur)
9116{
9117 VALUE tmp;
9118 rb_len_t i;
9119
9120 if (recur) {
9121 tmp = rb_str_new2("[...]");
9122 rb_io_puts(1, &tmp, out);
9123 return Qtrue;
9124 }
9125 ary = rb_check_array_type(ary);
9126 if (NIL_P(ary)) return Qfalse;
9127 for (i=0; i<RARRAY_LEN(ary); i++) {
9128 tmp = RARRAY_AREF(ary, i);
9129 rb_io_puts(1, &tmp, out);
9130 }
9131 return Qtrue;
9132}
9133
9134/*
9135 * call-seq:
9136 * puts(*objects) -> nil
9137 *
9138 * Writes the given +objects+ to the stream, which must be open for writing;
9139 * returns +nil+.\
9140 * Writes a newline after each that does not already end with a newline sequence.
9141 * If called without arguments, writes a newline.
9142 * See {Line IO}[rdoc-ref:IO@Line+IO].
9143 *
9144 * Note that each added newline is the character <tt>"\n"</tt>,
9145 * not the output record separator (<tt>$\</tt>).
9146 *
9147 * Treatment for each object:
9148 *
9149 * - String: writes the string.
9150 * - Neither string nor array: writes <tt>object.to_s</tt>.
9151 * - Array: writes each element of the array; arrays may be nested.
9152 *
9153 * To keep these examples brief, we define this helper method:
9154 *
9155 * def show(*objects)
9156 * # Puts objects to file.
9157 * f = File.new('t.tmp', 'w+')
9158 * f.puts(objects)
9159 * # Return file content.
9160 * f.rewind
9161 * p f.read
9162 * f.close
9163 * end
9164 *
9165 * # Strings without newlines.
9166 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
9167 * # Strings, some with newlines.
9168 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
9169 *
9170 * # Neither strings nor arrays:
9171 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
9172 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
9173 *
9174 * # Array of strings.
9175 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
9176 * # Nested arrays.
9177 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
9178 *
9179 */
9180
9181VALUE
9182rb_io_puts(int argc, const VALUE *argv, VALUE out)
9183{
9184 VALUE line, args[2];
9185
9186 /* if no argument given, print newline. */
9187 if (argc == 0) {
9188 rb_io_write(out, rb_default_rs);
9189 return Qnil;
9190 }
9191 for (int i = 0; i < argc; i++) {
9192 // Convert the argument to a string:
9193 if (RB_TYPE_P(argv[i], T_STRING)) {
9194 line = argv[i];
9195 }
9196 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9197 continue;
9198 }
9199 else {
9200 line = rb_obj_as_string(argv[i]);
9201 }
9202
9203 // Write the line:
9204 int n = 0;
9205 if (RSTRING_LEN(line) == 0) {
9206 args[n++] = rb_default_rs;
9207 }
9208 else {
9209 args[n++] = line;
9210 if (!rb_str_end_with_asciichar(line, '\n')) {
9211 args[n++] = rb_default_rs;
9212 }
9213 }
9214
9215 rb_io_writev(out, n, args);
9216 }
9217
9218 return Qnil;
9219}
9220
9221/*
9222 * call-seq:
9223 * puts(*objects) -> nil
9224 *
9225 * Equivalent to
9226 *
9227 * $stdout.puts(objects)
9228 */
9229
9230static VALUE
9231rb_f_puts(int argc, VALUE *argv, VALUE recv)
9232{
9233 VALUE r_stdout = rb_ractor_stdout();
9234 if (recv == r_stdout) {
9235 return rb_io_puts(argc, argv, recv);
9236 }
9237 return forward(r_stdout, rb_intern("puts"), argc, argv);
9238}
9239
9240static VALUE
9241rb_p_write(VALUE str)
9242{
9243 VALUE args[2];
9244 args[0] = str;
9245 args[1] = rb_default_rs;
9246 VALUE r_stdout = rb_ractor_stdout();
9247 if (RB_TYPE_P(r_stdout, T_FILE) &&
9248 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9249 io_writev(2, args, r_stdout);
9250 }
9251 else {
9252 rb_io_writev(r_stdout, 2, args);
9253 }
9254 return Qnil;
9255}
9256
9257void
9258rb_p(VALUE obj) /* for debug print within C code */
9259{
9260 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9261}
9262
9263static VALUE
9264rb_p_result(int argc, const VALUE *argv)
9265{
9266 VALUE ret = Qnil;
9267
9268 if (argc == 1) {
9269 ret = argv[0];
9270 }
9271 else if (argc > 1) {
9272 ret = rb_ary_new4(argc, argv);
9273 }
9274 VALUE r_stdout = rb_ractor_stdout();
9275 if (RB_TYPE_P(r_stdout, T_FILE)) {
9276 rb_uninterruptible(rb_io_flush, r_stdout);
9277 }
9278 return ret;
9279}
9280
9281/*
9282 * call-seq:
9283 * p(object) -> obj
9284 * p(*objects) -> array of objects
9285 * p -> nil
9286 *
9287 * For each object +obj+, executes:
9288 *
9289 * $stdout.write(obj.inspect, "\n")
9290 *
9291 * With one object given, returns the object;
9292 * with multiple objects given, returns an array containing the objects;
9293 * with no object given, returns +nil+.
9294 *
9295 * Examples:
9296 *
9297 * r = Range.new(0, 4)
9298 * p r # => 0..4
9299 * p [r, r, r] # => [0..4, 0..4, 0..4]
9300 * p # => nil
9301 *
9302 * Output:
9303 *
9304 * 0..4
9305 * [0..4, 0..4, 0..4]
9306 *
9307 * Kernel#p is designed for debugging purposes.
9308 * Ruby implementations may define Kernel#p to be uninterruptible
9309 * in whole or in part.
9310 * On CRuby, Kernel#p's writing of data is uninterruptible.
9311 */
9312
9313static VALUE
9314rb_f_p(int argc, VALUE *argv, VALUE self)
9315{
9316 int i;
9317 for (i=0; i<argc; i++) {
9318 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9319 rb_uninterruptible(rb_p_write, inspected);
9320 }
9321 return rb_p_result(argc, argv);
9322}
9323
9324/*
9325 * call-seq:
9326 * display(port = $>) -> nil
9327 *
9328 * Writes +self+ on the given port:
9329 *
9330 * 1.display
9331 * "cat".display
9332 * [ 4, 5, 6 ].display
9333 * puts
9334 *
9335 * Output:
9336 *
9337 * 1cat[4, 5, 6]
9338 *
9339 */
9340
9341static VALUE
9342rb_obj_display(int argc, VALUE *argv, VALUE self)
9343{
9344 VALUE out;
9345
9346 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9347 rb_io_write(out, self);
9348
9349 return Qnil;
9350}
9351
9352static int
9353rb_stderr_to_original_p(VALUE err)
9354{
9355 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9356}
9357
9358void
9359rb_write_error2(const char *mesg, rb_len_t len)
9360{
9361 VALUE out = rb_ractor_stderr();
9362 if (rb_stderr_to_original_p(out)) {
9363#ifdef _WIN32
9364 if (isatty(fileno(stderr))) {
9365 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9366 }
9367#endif
9368 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9369 /* failed to write to stderr, what can we do? */
9370 return;
9371 }
9372 }
9373 else {
9374 rb_io_write(out, rb_str_new(mesg, len));
9375 }
9376}
9377
9378void
9379rb_write_error(const char *mesg)
9380{
9381 rb_write_error2(mesg, strlen(mesg));
9382}
9383
9384void
9385rb_write_error_str(VALUE mesg)
9386{
9387 VALUE out = rb_ractor_stderr();
9388 /* a stopgap measure for the time being */
9389 if (rb_stderr_to_original_p(out)) {
9390 size_t len = (size_t)RSTRING_LEN(mesg);
9391#ifdef _WIN32
9392 if (isatty(fileno(stderr))) {
9393 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9394 }
9395#endif
9396 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9397 RB_GC_GUARD(mesg);
9398 return;
9399 }
9400 }
9401 else {
9402 /* may unlock GVL, and */
9403 rb_io_write(out, mesg);
9404 }
9405}
9406
9407int
9408rb_stderr_tty_p(void)
9409{
9410 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9411 return isatty(fileno(stderr));
9412 return 0;
9413}
9414
9415static void
9416must_respond_to(ID mid, VALUE val, ID id)
9417{
9418 if (!rb_respond_to(val, mid)) {
9419 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9420 rb_id2str(id), rb_id2str(mid),
9421 rb_obj_class(val));
9422 }
9423}
9424
9425static void
9426stdin_setter(VALUE val, ID id, VALUE *ptr)
9427{
9429}
9430
9431static VALUE
9432stdin_getter(ID id, VALUE *ptr)
9433{
9434 return rb_ractor_stdin();
9435}
9436
9437static void
9438stdout_setter(VALUE val, ID id, VALUE *ptr)
9439{
9440 must_respond_to(id_write, val, id);
9442}
9443
9444static VALUE
9445stdout_getter(ID id, VALUE *ptr)
9446{
9447 return rb_ractor_stdout();
9448}
9449
9450static void
9451stderr_setter(VALUE val, ID id, VALUE *ptr)
9452{
9453 must_respond_to(id_write, val, id);
9455}
9456
9457static VALUE
9458stderr_getter(ID id, VALUE *ptr)
9459{
9460 return rb_ractor_stderr();
9461}
9462
9463static VALUE
9464allocate_and_open_new_file(VALUE klass)
9465{
9466 VALUE self = io_alloc(klass);
9467 rb_io_make_open_file(self);
9468 return self;
9469}
9470
9471VALUE
9472rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9473{
9474 int state;
9475 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9476 if (state) {
9477 /* if we raised an exception allocating an IO object, but the caller
9478 intended to transfer ownership of this FD to us, close the fd before
9479 raising the exception. Otherwise, we would leak a FD - the caller
9480 expects GC to close the file, but we never got around to assigning
9481 it to a rb_io. */
9482 if (!(mode & FMODE_EXTERNAL)) {
9483 maygvl_close(descriptor, 0);
9484 }
9485 rb_jump_tag(state);
9486 }
9487
9488
9489 rb_io_t *io = RFILE(self)->fptr;
9490 io->self = self;
9491 io->fd = descriptor;
9492 io->mode = mode;
9493
9494 /* At this point, Ruby fully owns the descriptor, and will close it when
9495 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9496 in the rest of this method. */
9497
9498 if (NIL_P(path)) {
9499 io->pathv = Qnil;
9500 }
9501 else {
9502 StringValue(path);
9503 io->pathv = rb_str_new_frozen(path);
9504 }
9505
9506 io->timeout = timeout;
9507
9508 ccan_list_head_init(&io->blocking_operations);
9509 io->closing_ec = NULL;
9510 io->wakeup_mutex = Qnil;
9511 io->fork_generation = GET_VM()->fork_gen;
9512
9513 if (encoding) {
9514 io->encs = *encoding;
9515 }
9516
9517 rb_update_max_fd(descriptor);
9518
9519 return self;
9520}
9521
9522static VALUE
9523prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9524{
9525 VALUE path_value = Qnil;
9526 rb_encoding *e;
9527 struct rb_io_encoding convconfig;
9528
9529 if (path) {
9530 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9531 }
9532
9533 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9534 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9535 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9538#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9539 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9540 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9541 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9542#endif
9543 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9544 convconfig.ecopts = Qnil;
9545
9546 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9547 rb_io_t*io = RFILE(self)->fptr;
9548
9549 if (!io_check_tty(io)) {
9550#ifdef __CYGWIN__
9551 io->mode |= FMODE_BINMODE;
9552 setmode(fd, O_BINARY);
9553#endif
9554 }
9555
9556 return self;
9557}
9558
9559VALUE
9560rb_io_fdopen(int fd, int oflags, const char *path)
9561{
9562 VALUE klass = rb_cIO;
9563
9564 if (path && strcmp(path, "-")) klass = rb_cFile;
9565 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9566}
9567
9568static VALUE
9569prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9570{
9571 rb_io_t *fptr;
9572 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9573
9574 GetOpenFile(io, fptr);
9576#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9577 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9578 if (fmode & FMODE_READABLE) {
9580 }
9581#endif
9582 fptr->stdio_file = f;
9583
9584 return io;
9585}
9586
9587VALUE
9588rb_io_prep_stdin(void)
9589{
9590 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9591}
9592
9593VALUE
9594rb_io_prep_stdout(void)
9595{
9596 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9597}
9598
9599VALUE
9600rb_io_prep_stderr(void)
9601{
9602 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9603}
9604
9605FILE *
9607{
9608 if (!fptr->stdio_file) {
9609 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9610 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9611 }
9612 return fptr->stdio_file;
9613}
9614
9615static inline void
9616rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9617{
9618 buf->ptr = NULL;
9619 buf->off = 0;
9620 buf->len = 0;
9621 buf->capa = 0;
9622}
9623
9624static inline rb_io_t *
9625rb_io_fptr_new(void)
9626{
9627 rb_io_t *fp = ALLOC(rb_io_t);
9628 fp->self = Qnil;
9629 fp->fd = -1;
9630 fp->stdio_file = NULL;
9631 fp->mode = 0;
9632 fp->pid = 0;
9633 fp->lineno = 0;
9634 fp->pathv = Qnil;
9635 fp->finalize = 0;
9636 rb_io_buffer_init(&fp->wbuf);
9637 rb_io_buffer_init(&fp->rbuf);
9638 rb_io_buffer_init(&fp->cbuf);
9639 fp->readconv = NULL;
9640 fp->writeconv = NULL;
9642 fp->writeconv_pre_ecflags = 0;
9644 fp->writeconv_initialized = 0;
9645 fp->tied_io_for_writing = 0;
9646 fp->encs.enc = NULL;
9647 fp->encs.enc2 = NULL;
9648 fp->encs.ecflags = 0;
9649 fp->encs.ecopts = Qnil;
9650 fp->write_lock = Qnil;
9651 fp->timeout = Qnil;
9652 ccan_list_head_init(&fp->blocking_operations);
9653 fp->closing_ec = NULL;
9654 fp->wakeup_mutex = Qnil;
9655 fp->fork_generation = GET_VM()->fork_gen;
9656 return fp;
9657}
9658
9659rb_io_t *
9660rb_io_make_open_file(VALUE obj)
9661{
9662 rb_io_t *fp = 0;
9663
9664 Check_Type(obj, T_FILE);
9665 if (RFILE(obj)->fptr) {
9666 rb_io_close(obj);
9667 rb_io_fptr_finalize(RFILE(obj)->fptr);
9668 RFILE(obj)->fptr = 0;
9669 }
9670 fp = rb_io_fptr_new();
9671 fp->self = obj;
9672 RFILE(obj)->fptr = fp;
9673 return fp;
9674}
9675
9676static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9677
9678/*
9679 * call-seq:
9680 * IO.new(fd, mode = 'r', **opts) -> io
9681 *
9682 * Creates and returns a new \IO object (file stream) from a file descriptor.
9683 *
9684 * \IO.new may be useful for interaction with low-level libraries.
9685 * For higher-level interactions, it may be simpler to create
9686 * the file stream using File.open.
9687 *
9688 * Argument +fd+ must be a valid file descriptor (integer):
9689 *
9690 * path = 't.tmp'
9691 * fd = IO.sysopen(path) # => 3
9692 * IO.new(fd) # => #<IO:fd 3>
9693 *
9694 * The new \IO object does not inherit encoding
9695 * (because the integer file descriptor does not have an encoding):
9696 *
9697 * File.read('t.ja') # => "こんにちは"
9698 * fd = IO.sysopen('t.ja', 'rb')
9699 * io = IO.new(fd)
9700 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9701 *
9702 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9703 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9704 *
9705 * IO.new(fd, 'w') # => #<IO:fd 3>
9706 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9707 *
9708 * Optional keyword arguments +opts+ specify:
9709 *
9710 * - {Open Options}[rdoc-ref:IO@Open+Options].
9711 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9712 *
9713 * Examples:
9714 *
9715 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9716 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9717 *
9718 */
9719
9720static VALUE
9721rb_io_initialize(int argc, VALUE *argv, VALUE io)
9722{
9723 VALUE fnum, vmode;
9724 VALUE opt;
9725
9726 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9727 return io_initialize(io, fnum, vmode, opt);
9728}
9729
9730static VALUE
9731io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9732{
9733 rb_io_t *fp;
9734 int fd, oflags = O_RDONLY;
9735 enum rb_io_mode fmode;
9736 struct rb_io_encoding convconfig;
9737#if defined(HAVE_FCNTL) && defined(F_GETFL)
9738 int ofmode;
9739#else
9740 struct stat st;
9741#endif
9742
9743 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9744
9745 fd = NUM2INT(fnum);
9746 if (rb_reserved_fd_p(fd)) {
9747 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9748 }
9749#if defined(HAVE_FCNTL) && defined(F_GETFL)
9750 oflags = fcntl(fd, F_GETFL);
9751 if (oflags == -1) rb_sys_fail(0);
9752#else
9753 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9754#endif
9755 rb_update_max_fd(fd);
9756#if defined(HAVE_FCNTL) && defined(F_GETFL)
9757 ofmode = rb_io_oflags_fmode(oflags);
9758 if (NIL_P(vmode)) {
9759 fmode = ofmode;
9760 }
9761 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9762 VALUE error = INT2FIX(EINVAL);
9764 }
9765#endif
9766 VALUE path = Qnil;
9767
9768 if (!NIL_P(opt)) {
9769 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9770 fmode |= FMODE_EXTERNAL;
9771 }
9772
9773 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9774 if (!NIL_P(path)) {
9775 StringValue(path);
9776 path = rb_str_new_frozen(path);
9777 }
9778 }
9779
9780 MakeOpenFile(io, fp);
9781 fp->self = io;
9782 fp->fd = fd;
9783 fp->mode = fmode;
9784 fp->encs = convconfig;
9785 fp->pathv = path;
9786 fp->timeout = Qnil;
9787 ccan_list_head_init(&fp->blocking_operations);
9788 fp->closing_ec = NULL;
9789 fp->wakeup_mutex = Qnil;
9790 fp->fork_generation = GET_VM()->fork_gen;
9791 clear_codeconv(fp);
9792 io_check_tty(fp);
9793 if (fileno(stdin) == fd)
9794 fp->stdio_file = stdin;
9795 else if (fileno(stdout) == fd)
9796 fp->stdio_file = stdout;
9797 else if (fileno(stderr) == fd)
9798 fp->stdio_file = stderr;
9799
9800 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9801 return io;
9802}
9803
9804/*
9805 * call-seq:
9806 * set_encoding_by_bom -> encoding or nil
9807 *
9808 * If the stream begins with a BOM
9809 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9810 * consumes the BOM and sets the external encoding accordingly;
9811 * returns the result encoding if found, or +nil+ otherwise:
9812 *
9813 * File.write('t.tmp', "\u{FEFF}abc")
9814 * io = File.open('t.tmp', 'rb')
9815 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9816 * io.close
9817 *
9818 * File.write('t.tmp', 'abc')
9819 * io = File.open('t.tmp', 'rb')
9820 * io.set_encoding_by_bom # => nil
9821 * io.close
9822 *
9823 * Raises an exception if the stream is not binmode
9824 * or its encoding has already been set.
9825 *
9826 */
9827
9828static VALUE
9829rb_io_set_encoding_by_bom(VALUE io)
9830{
9831 rb_io_t *fptr;
9832
9833 GetOpenFile(io, fptr);
9834 if (!(fptr->mode & FMODE_BINMODE)) {
9835 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9836 }
9837 if (fptr->encs.enc2) {
9838 rb_raise(rb_eArgError, "encoding conversion is set");
9839 }
9840 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9841 rb_raise(rb_eArgError, "encoding is set to %s already",
9842 rb_enc_name(fptr->encs.enc));
9843 }
9844 if (!io_set_encoding_by_bom(io)) return Qnil;
9845 return rb_enc_from_encoding(fptr->encs.enc);
9846}
9847
9848/*
9849 * :markup: markdown
9850 *
9851 * call-seq:
9852 * File.new(path, mode = 'r', permissions = 0666, **options) -> file
9853 *
9854 * Opens the file as specified by the given arguments.
9855 * Creates and returns a new open \File object for that file;
9856 * the opened file is in non-synchronous mode.
9857 *
9858 * Argument `path` must the string path to an existing filesystem entry:
9859 *
9860 * ```ruby
9861 * file = File.new('doc/maintainers.md') # => #<File:doc/maintainers.md>
9862 * file.close # Clean up.
9863 * tty = File.new('/dev/tty') # => #<File:/dev/tty>
9864 * tty.close # Clean up.
9865 * ```
9866 *
9867 * Note that the caller is responsible for closing the file;
9868 * see File.open for automatic closing.
9869 *
9870 * Optional argument `mode` (defaults to `'r'`) must specify a valid mode;
9871 * see [Access Modes](rdoc-ref:File@Access+Modes):
9872 *
9873 * ```ruby
9874 * file = File.new('t.tmp', 'w') # => #<File:t.tmp>
9875 * file.close # Clean up.
9876 * file = File.new('t.tmp', File::RDONLY) # => #<File:t.tmp>
9877 * file.close # Clean up.
9878 * ```
9879 *
9880 * Optional argument `permissions` (defaults to `0666`) must specify valid permissions;
9881 * see [File Permissions](rdoc-ref:File@File+Permissions):
9882 *
9883 * ```ruby
9884 * file = File.new('t.tmp', 'w', 0644) # => #<File:t.tmp>
9885 * file.close # Clean up.
9886 * file = File.new('t.tmp', 'w', 0444) # => #<File:t.tmp>
9887 * file.close # Clean up.
9888 * ```
9889 *
9890 * Optional keyword arguments `options` specify:
9891 *
9892 * - [Open Options](rdoc-ref:IO@Open+Options).
9893 * - [Encoding options](rdoc-ref:encodings.rdoc@Encoding+Options).
9894 *
9895 */
9896
9897static VALUE
9898rb_file_initialize(int argc, VALUE *argv, VALUE io)
9899{
9900 if (RFILE(io)->fptr) {
9901 rb_raise(rb_eRuntimeError, "reinitializing File");
9902 }
9903 VALUE fname, vmode, vperm, opt;
9904 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9905 if (posargc < 3) { /* perm is File only */
9906 VALUE fd = rb_check_to_int(fname);
9907
9908 if (!NIL_P(fd)) {
9909 return io_initialize(io, fd, vmode, opt);
9910 }
9911 }
9912 return rb_open_file(io, fname, vmode, vperm, opt);
9913}
9914
9915/* :nodoc: */
9916static VALUE
9917rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9918{
9919 if (rb_block_given_p()) {
9920 VALUE cname = rb_obj_as_string(klass);
9921
9922 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9923 cname, cname);
9924 }
9925 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9926}
9927
9928
9929/*
9930 * call-seq:
9931 * IO.for_fd(fd, mode = 'r', **opts) -> io
9932 *
9933 * Synonym for IO.new.
9934 *
9935 */
9936
9937static VALUE
9938rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9939{
9940 VALUE io = rb_obj_alloc(klass);
9941 rb_io_initialize(argc, argv, io);
9942 return io;
9943}
9944
9945/*
9946 * call-seq:
9947 * ios.autoclose? -> true or false
9948 *
9949 * Returns +true+ if the underlying file descriptor of _ios_ will be
9950 * closed at its finalization or at calling #close, otherwise +false+.
9951 */
9952
9953static VALUE
9954rb_io_autoclose_p(VALUE io)
9955{
9956 rb_io_t *fptr = RFILE(io)->fptr;
9957 rb_io_check_closed(fptr);
9958 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9959}
9960
9961/*
9962 * call-seq:
9963 * io.autoclose = bool -> true or false
9964 *
9965 * Sets auto-close flag.
9966 *
9967 * f = File.open(File::NULL)
9968 * IO.for_fd(f.fileno).close
9969 * f.gets # raises Errno::EBADF
9970 *
9971 * f = File.open(File::NULL)
9972 * g = IO.for_fd(f.fileno)
9973 * g.autoclose = false
9974 * g.close
9975 * f.gets # won't cause Errno::EBADF
9976 */
9977
9978static VALUE
9979rb_io_set_autoclose(VALUE io, VALUE autoclose)
9980{
9981 rb_io_t *fptr;
9982 GetOpenFile(io, fptr);
9983 if (!RTEST(autoclose))
9984 fptr->mode |= FMODE_EXTERNAL;
9985 else
9986 fptr->mode &= ~FMODE_EXTERNAL;
9987 return autoclose;
9988}
9989
9990static VALUE
9991io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9992{
9993 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9994
9995 if (!RB_TEST(result)) {
9996 return Qnil;
9997 }
9998
9999 int mask = RB_NUM2INT(result);
10000
10001 if (mask & event) {
10002 if (return_io)
10003 return io;
10004 else
10005 return result;
10006 }
10007 else {
10008 return Qfalse;
10009 }
10010}
10011
10012/*
10013 * call-seq:
10014 * io.wait_readable -> truthy or falsy
10015 * io.wait_readable(timeout) -> truthy or falsy
10016 *
10017 * Waits until IO is readable and returns a truthy value, or a falsy
10018 * value when times out. Returns a truthy value immediately when
10019 * buffered data is available.
10020 */
10021
10022static VALUE
10023io_wait_readable(int argc, VALUE *argv, VALUE io)
10024{
10025 rb_io_t *fptr;
10026
10027 RB_IO_POINTER(io, fptr);
10029
10030 if (rb_io_read_pending(fptr)) return Qtrue;
10031
10032 rb_check_arity(argc, 0, 1);
10033 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
10034
10035 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
10036}
10037
10038/*
10039 * call-seq:
10040 * io.wait_writable -> truthy or falsy
10041 * io.wait_writable(timeout) -> truthy or falsy
10042 *
10043 * Waits until IO is writable and returns a truthy value or a falsy
10044 * value when times out.
10045 */
10046static VALUE
10047io_wait_writable(int argc, VALUE *argv, VALUE io)
10048{
10049 rb_io_t *fptr;
10050
10051 RB_IO_POINTER(io, fptr);
10053
10054 rb_check_arity(argc, 0, 1);
10055 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
10056
10057 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
10058}
10059
10060/*
10061 * call-seq:
10062 * io.wait_priority -> truthy or falsy
10063 * io.wait_priority(timeout) -> truthy or falsy
10064 *
10065 * Waits until IO is priority and returns a truthy value or a falsy
10066 * value when times out. Priority data is sent and received using
10067 * the Socket::MSG_OOB flag and is typically limited to streams.
10068 */
10069static VALUE
10070io_wait_priority(int argc, VALUE *argv, VALUE io)
10071{
10072 rb_io_t *fptr = NULL;
10073
10074 RB_IO_POINTER(io, fptr);
10076
10077 if (rb_io_read_pending(fptr)) return Qtrue;
10078
10079 rb_check_arity(argc, 0, 1);
10080 VALUE timeout = argc == 1 ? argv[0] : Qnil;
10081
10082 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
10083}
10084
10085static int
10086wait_mode_sym(VALUE mode)
10087{
10088 if (mode == ID2SYM(rb_intern("r"))) {
10089 return RB_WAITFD_IN;
10090 }
10091 if (mode == ID2SYM(rb_intern("read"))) {
10092 return RB_WAITFD_IN;
10093 }
10094 if (mode == ID2SYM(rb_intern("readable"))) {
10095 return RB_WAITFD_IN;
10096 }
10097 if (mode == ID2SYM(rb_intern("w"))) {
10098 return RB_WAITFD_OUT;
10099 }
10100 if (mode == ID2SYM(rb_intern("write"))) {
10101 return RB_WAITFD_OUT;
10102 }
10103 if (mode == ID2SYM(rb_intern("writable"))) {
10104 return RB_WAITFD_OUT;
10105 }
10106 if (mode == ID2SYM(rb_intern("rw"))) {
10107 return RB_WAITFD_IN|RB_WAITFD_OUT;
10108 }
10109 if (mode == ID2SYM(rb_intern("read_write"))) {
10110 return RB_WAITFD_IN|RB_WAITFD_OUT;
10111 }
10112 if (mode == ID2SYM(rb_intern("readable_writable"))) {
10113 return RB_WAITFD_IN|RB_WAITFD_OUT;
10114 }
10115
10116 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
10117}
10118
10119static inline enum rb_io_event
10120io_event_from_value(VALUE value)
10121{
10122 int events = RB_NUM2INT(value);
10123
10124 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
10125
10126 return events;
10127}
10128
10129/*
10130 * call-seq:
10131 * io.wait(events, timeout) -> event mask, false or nil
10132 * io.wait(*event_symbols[, timeout]) -> self, true, or false
10133 *
10134 * Waits until the IO becomes ready for the specified events and returns the
10135 * subset of events that become ready, or a falsy value when times out.
10136 *
10137 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
10138 * +IO::PRIORITY+.
10139 *
10140 * Returns an event mask (truthy value) immediately when buffered data is
10141 * available.
10142 *
10143 * The second form: if one or more event symbols (+:read+, +:write+, or
10144 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
10145 * corresponding to those symbols. In this form, +timeout+ is optional, the
10146 * order of the arguments is arbitrary, and returns +io+ if any of the
10147 * events is ready.
10148 */
10149
10150static VALUE
10151io_wait(int argc, VALUE *argv, VALUE io)
10152{
10153 VALUE timeout = Qundef;
10154 enum rb_io_event events = 0;
10155 int return_io = 0;
10156
10157 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
10158 // We'd prefer to return the actual mask, but this form would return the io itself:
10159 return_io = 1;
10160
10161 // Slow/messy path:
10162 for (int i = 0; i < argc; i += 1) {
10163 if (RB_SYMBOL_P(argv[i])) {
10164 events |= wait_mode_sym(argv[i]);
10165 }
10166 else if (UNDEF_P(timeout)) {
10167 rb_time_interval(timeout = argv[i]);
10168 }
10169 else {
10170 rb_raise(rb_eArgError, "timeout given more than once");
10171 }
10172 }
10173
10174 if (UNDEF_P(timeout)) timeout = Qnil;
10175
10176 if (events == 0) {
10177 events = RUBY_IO_READABLE;
10178 }
10179 }
10180 else /* argc == 2 and neither are symbols */ {
10181 // This is the fast path:
10182 events = io_event_from_value(argv[0]);
10183 timeout = argv[1];
10184 }
10185
10186 if (events & RUBY_IO_READABLE) {
10187 rb_io_t *fptr = NULL;
10188 RB_IO_POINTER(io, fptr);
10189
10190 if (rb_io_read_pending(fptr)) {
10191 // This was the original behaviour:
10192 if (return_io) return Qtrue;
10193 // New behaviour always returns an event mask:
10194 else return RB_INT2NUM(RUBY_IO_READABLE);
10195 }
10196 }
10197
10198 return io_wait_event(io, events, timeout, return_io);
10199}
10200
10201static void
10202argf_mark_and_move(void *ptr)
10203{
10204 struct argf *p = ptr;
10205 rb_gc_mark_and_move(&p->filename);
10206 rb_gc_mark_and_move(&p->current_file);
10207 rb_gc_mark_and_move(&p->argv);
10208 rb_gc_mark_and_move(&p->inplace);
10209 rb_gc_mark_and_move(&p->encs.ecopts);
10210}
10211
10212static size_t
10213argf_memsize(const void *ptr)
10214{
10215 const struct argf *p = ptr;
10216 size_t size = sizeof(*p);
10217 return size;
10218}
10219
10220static const rb_data_type_t argf_type = {
10221 "ARGF",
10222 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10223 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10224};
10225
10226static inline void
10227argf_init(VALUE argf, struct argf *p, VALUE v)
10228{
10229 p->filename = Qnil;
10230 p->current_file = Qnil;
10231 p->lineno = 0;
10232 RB_OBJ_WRITE(argf, &p->argv, v);
10233}
10234
10235static VALUE
10236argf_alloc(VALUE klass)
10237{
10238 struct argf *p;
10239 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10240
10241 argf_init(argf, p, Qnil);
10242 return argf;
10243}
10244
10245#undef rb_argv
10246
10247/* :nodoc: */
10248static VALUE
10249argf_initialize(VALUE argf, VALUE argv)
10250{
10251 memset(&ARGF, 0, sizeof(ARGF));
10252 argf_init(argf, &ARGF, argv);
10253
10254 return argf;
10255}
10256
10257/* :nodoc: */
10258static VALUE
10259argf_initialize_copy(VALUE argf, VALUE orig)
10260{
10261 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10262 ARGF = argf_of(orig);
10263 rb_gc_writebarrier_remember(argf);
10264 ARGF_SET(argv, rb_obj_dup(ARGF.argv));
10265 return argf;
10266}
10267
10268/*
10269 * call-seq:
10270 * ARGF.lineno = integer -> integer
10271 *
10272 * Sets the line number of ARGF as a whole to the given Integer.
10273 *
10274 * ARGF sets the line number automatically as you read data, so normally
10275 * you will not need to set it explicitly. To access the current line number
10276 * use ARGF.lineno.
10277 *
10278 * For example:
10279 *
10280 * ARGF.lineno #=> 0
10281 * ARGF.readline #=> "This is line 1\n"
10282 * ARGF.lineno #=> 1
10283 * ARGF.lineno = 0 #=> 0
10284 * ARGF.lineno #=> 0
10285 */
10286static VALUE
10287argf_set_lineno(VALUE argf, VALUE val)
10288{
10289 ARGF.lineno = NUM2INT(val);
10290 ARGF.last_lineno = ARGF.lineno;
10291 return val;
10292}
10293
10294/*
10295 * call-seq:
10296 * ARGF.lineno -> integer
10297 *
10298 * Returns the current line number of ARGF as a whole. This value
10299 * can be set manually with ARGF.lineno=.
10300 *
10301 * For example:
10302 *
10303 * ARGF.lineno #=> 0
10304 * ARGF.readline #=> "This is line 1\n"
10305 * ARGF.lineno #=> 1
10306 */
10307static VALUE
10308argf_lineno(VALUE argf)
10309{
10310 return INT2FIX(ARGF.lineno);
10311}
10312
10313static VALUE
10314argf_forward(int argc, VALUE *argv, VALUE argf)
10315{
10316 return forward_current(rb_frame_this_func(), argc, argv);
10317}
10318
10319#define next_argv() argf_next_argv(argf)
10320#define ARGF_GENERIC_INPUT_P() \
10321 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10322#define ARGF_FORWARD(argc, argv) do {\
10323 if (ARGF_GENERIC_INPUT_P())\
10324 return argf_forward((argc), (argv), argf);\
10325} while (0)
10326#define NEXT_ARGF_FORWARD(argc, argv) do {\
10327 if (!next_argv()) return Qnil;\
10328 ARGF_FORWARD((argc), (argv));\
10329} while (0)
10330
10331static void
10332argf_close(VALUE argf)
10333{
10334 VALUE file = ARGF.current_file;
10335 if (file == rb_stdin) return;
10336 if (RB_TYPE_P(file, T_FILE)) {
10337 rb_io_set_write_io(file, Qnil);
10338 }
10339 io_close(file);
10340 ARGF.init_p = -1;
10341}
10342
10343static int
10344argf_next_argv(VALUE argf)
10345{
10346 char *fn;
10347 rb_io_t *fptr;
10348 int stdout_binmode = 0;
10349 enum rb_io_mode fmode;
10350
10351 VALUE r_stdout = rb_ractor_stdout();
10352
10353 if (RB_TYPE_P(r_stdout, T_FILE)) {
10354 GetOpenFile(r_stdout, fptr);
10355 if (fptr->mode & FMODE_BINMODE)
10356 stdout_binmode = 1;
10357 }
10358
10359 if (ARGF.init_p == 0) {
10360 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10361 ARGF.next_p = 1;
10362 }
10363 else {
10364 ARGF.next_p = -1;
10365 }
10366 ARGF.init_p = 1;
10367 }
10368 else {
10369 if (NIL_P(ARGF.argv)) {
10370 ARGF.next_p = -1;
10371 }
10372 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10373 ARGF.next_p = 1;
10374 }
10375 }
10376
10377 if (ARGF.next_p == 1) {
10378 if (ARGF.init_p == 1) argf_close(argf);
10379 retry:
10380 if (RARRAY_LEN(ARGF.argv) > 0) {
10381 VALUE filename = rb_ary_shift(ARGF.argv);
10382 FilePathValue(filename);
10383 ARGF_SET(filename, filename);
10384 filename = rb_str_encode_ospath(filename);
10385 fn = StringValueCStr(filename);
10386 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10387 ARGF_SET(current_file, rb_stdin);
10388 if (ARGF.inplace) {
10389 rb_warn("Can't do inplace edit for stdio; skipping");
10390 goto retry;
10391 }
10392 }
10393 else {
10394 VALUE write_io = Qnil;
10395 int fr = rb_sysopen(filename, O_RDONLY, 0);
10396
10397 if (ARGF.inplace) {
10398 struct stat st;
10399#ifndef NO_SAFE_RENAME
10400 struct stat st2;
10401#endif
10402 VALUE str;
10403 int fw;
10404
10405 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10406 rb_io_close(r_stdout);
10407 }
10408 fstat(fr, &st);
10409 str = filename;
10410 if (!NIL_P(ARGF.inplace)) {
10411 VALUE suffix = ARGF.inplace;
10412 str = rb_str_dup(str);
10413 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10414 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10415 rb_enc_get(suffix), 0, Qnil))) {
10416 rb_str_append(str, suffix);
10417 }
10418#ifdef NO_SAFE_RENAME
10419 (void)close(fr);
10420 (void)unlink(RSTRING_PTR(str));
10421 if (rename(fn, RSTRING_PTR(str)) < 0) {
10422 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10423 filename, str, strerror(errno));
10424 goto retry;
10425 }
10426 fr = rb_sysopen(str, O_RDONLY, 0);
10427#else
10428 if (rename(fn, RSTRING_PTR(str)) < 0) {
10429 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10430 filename, str, strerror(errno));
10431 close(fr);
10432 goto retry;
10433 }
10434#endif
10435 }
10436 else {
10437#ifdef NO_SAFE_RENAME
10438 rb_fatal("Can't do inplace edit without backup");
10439#else
10440 if (unlink(fn) < 0) {
10441 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10442 filename, strerror(errno));
10443 close(fr);
10444 goto retry;
10445 }
10446#endif
10447 }
10448 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10449#ifndef NO_SAFE_RENAME
10450 fstat(fw, &st2);
10451#ifdef HAVE_FCHMOD
10452 fchmod(fw, st.st_mode);
10453#else
10454 chmod(fn, st.st_mode);
10455#endif
10456 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10457 int err;
10458#ifdef HAVE_FCHOWN
10459 err = fchown(fw, st.st_uid, st.st_gid);
10460#else
10461 err = chown(fn, st.st_uid, st.st_gid);
10462#endif
10463 if (err && getuid() == 0 && st2.st_uid == 0) {
10464 const char *wkfn = RSTRING_PTR(filename);
10465 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10466 filename, str, strerror(errno));
10467 (void)close(fr);
10468 (void)close(fw);
10469 (void)unlink(wkfn);
10470 goto retry;
10471 }
10472 }
10473#endif
10474 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10475 rb_ractor_stdout_set(write_io);
10476 if (stdout_binmode) rb_io_binmode(rb_stdout);
10477 }
10478 fmode = FMODE_READABLE;
10479 if (!ARGF.binmode) {
10480 fmode |= DEFAULT_TEXTMODE;
10481 }
10482 ARGF_SET(current_file, prep_io(fr, fmode, rb_cFile, fn));
10483 if (!NIL_P(write_io)) {
10484 rb_io_set_write_io(ARGF.current_file, write_io);
10485 }
10486 RB_GC_GUARD(filename);
10487 }
10488 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10489 GetOpenFile(ARGF.current_file, fptr);
10490 if (ARGF.encs.enc) {
10491 fptr->encs = ARGF.encs;
10492 clear_codeconv(fptr);
10493 }
10494 else {
10495 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10496 if (!ARGF.binmode) {
10498#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10499 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10500#endif
10501 }
10502 }
10503 ARGF.next_p = 0;
10504 }
10505 else {
10506 ARGF.next_p = 1;
10507 return FALSE;
10508 }
10509 }
10510 else if (ARGF.next_p == -1) {
10511 ARGF_SET(current_file, rb_stdin);
10512 ARGF_SET(filename, rb_str_new2("-"));
10513 if (ARGF.inplace) {
10514 rb_warn("Can't do inplace edit for stdio");
10515 rb_ractor_stdout_set(orig_stdout);
10516 }
10517 }
10518 if (ARGF.init_p == -1) ARGF.init_p = 1;
10519 return TRUE;
10520}
10521
10522static VALUE
10523argf_getline(int argc, VALUE *argv, VALUE argf)
10524{
10525 VALUE line;
10526 long lineno = ARGF.lineno;
10527
10528 retry:
10529 if (!next_argv()) return Qnil;
10530 if (ARGF_GENERIC_INPUT_P()) {
10531 line = forward_current(idGets, argc, argv);
10532 }
10533 else {
10534 if (argc == 0 && rb_rs == rb_default_rs) {
10535 line = rb_io_gets(ARGF.current_file);
10536 }
10537 else {
10538 line = rb_io_getline(argc, argv, ARGF.current_file);
10539 }
10540 if (NIL_P(line) && ARGF.next_p != -1) {
10541 argf_close(argf);
10542 ARGF.next_p = 1;
10543 goto retry;
10544 }
10545 }
10546 if (!NIL_P(line)) {
10547 ARGF.lineno = ++lineno;
10548 ARGF.last_lineno = ARGF.lineno;
10549 }
10550 return line;
10551}
10552
10553static VALUE
10554argf_lineno_getter(ID id, VALUE *var)
10555{
10556 VALUE argf = *var;
10557 return INT2FIX(ARGF.last_lineno);
10558}
10559
10560static void
10561argf_lineno_setter(VALUE val, ID id, VALUE *var)
10562{
10563 VALUE argf = *var;
10564 int n = NUM2INT(val);
10565 ARGF.last_lineno = ARGF.lineno = n;
10566}
10567
10568void
10569rb_reset_argf_lineno(long n)
10570{
10571 ARGF.last_lineno = ARGF.lineno = n;
10572}
10573
10574static VALUE argf_gets(int, VALUE *, VALUE);
10575
10576/*
10577 * call-seq:
10578 * gets(sep=$/ [, getline_args]) -> string or nil
10579 * gets(limit [, getline_args]) -> string or nil
10580 * gets(sep, limit [, getline_args]) -> string or nil
10581 *
10582 * Returns (and assigns to <code>$_</code>) the next line from the list
10583 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10584 * no files are present on the command line. Returns +nil+ at end of
10585 * file. The optional argument specifies the record separator. The
10586 * separator is included with the contents of each record. A separator
10587 * of +nil+ reads the entire contents, and a zero-length separator
10588 * reads the input one paragraph at a time, where paragraphs are
10589 * divided by two consecutive newlines. If the first argument is an
10590 * integer, or optional second argument is given, the returning string
10591 * would not be longer than the given value in bytes. If multiple
10592 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10593 * the contents one file at a time.
10594 *
10595 * ARGV << "testfile"
10596 * print while gets
10597 *
10598 * <em>produces:</em>
10599 *
10600 * This is line one
10601 * This is line two
10602 * This is line three
10603 * And so on...
10604 *
10605 * The style of programming using <code>$_</code> as an implicit
10606 * parameter is gradually losing favor in the Ruby community.
10607 */
10608
10609static VALUE
10610rb_f_gets(int argc, VALUE *argv, VALUE recv)
10611{
10612 if (recv == argf) {
10613 return argf_gets(argc, argv, argf);
10614 }
10615 return forward(argf, idGets, argc, argv);
10616}
10617
10618/*
10619 * call-seq:
10620 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10621 * ARGF.gets(limit [, getline_args]) -> string or nil
10622 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10623 *
10624 * Returns the next line from the current file in ARGF.
10625 *
10626 * By default lines are assumed to be separated by <code>$/</code>;
10627 * to use a different character as a separator, supply it as a String
10628 * for the _sep_ argument.
10629 *
10630 * The optional _limit_ argument specifies how many characters of each line
10631 * to return. By default all characters are returned.
10632 *
10633 * See IO.readlines for details about getline_args.
10634 *
10635 */
10636static VALUE
10637argf_gets(int argc, VALUE *argv, VALUE argf)
10638{
10639 VALUE line;
10640
10641 line = argf_getline(argc, argv, argf);
10642 rb_lastline_set(line);
10643
10644 return line;
10645}
10646
10647VALUE
10649{
10650 VALUE line;
10651
10652 if (rb_rs != rb_default_rs) {
10653 return rb_f_gets(0, 0, argf);
10654 }
10655
10656 retry:
10657 if (!next_argv()) return Qnil;
10658 line = rb_io_gets(ARGF.current_file);
10659 if (NIL_P(line) && ARGF.next_p != -1) {
10660 rb_io_close(ARGF.current_file);
10661 ARGF.next_p = 1;
10662 goto retry;
10663 }
10664 rb_lastline_set(line);
10665 if (!NIL_P(line)) {
10666 ARGF.lineno++;
10667 ARGF.last_lineno = ARGF.lineno;
10668 }
10669
10670 return line;
10671}
10672
10673static VALUE argf_readline(int, VALUE *, VALUE);
10674
10675/*
10676 * call-seq:
10677 * readline(sep = $/, chomp: false) -> string
10678 * readline(limit, chomp: false) -> string
10679 * readline(sep, limit, chomp: false) -> string
10680 *
10681 * Equivalent to method Kernel#gets, except that it raises an exception
10682 * if called at end-of-stream:
10683 *
10684 * $ cat t.txt | ruby -e "p readlines; readline"
10685 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10686 * in `readline': end of file reached (EOFError)
10687 *
10688 * Optional keyword argument +chomp+ specifies whether line separators
10689 * are to be omitted.
10690 */
10691
10692static VALUE
10693rb_f_readline(int argc, VALUE *argv, VALUE recv)
10694{
10695 if (recv == argf) {
10696 return argf_readline(argc, argv, argf);
10697 }
10698 return forward(argf, rb_intern("readline"), argc, argv);
10699}
10700
10701
10702/*
10703 * call-seq:
10704 * ARGF.readline(sep=$/) -> string
10705 * ARGF.readline(limit) -> string
10706 * ARGF.readline(sep, limit) -> string
10707 *
10708 * Returns the next line from the current file in ARGF.
10709 *
10710 * By default lines are assumed to be separated by <code>$/</code>;
10711 * to use a different character as a separator, supply it as a String
10712 * for the _sep_ argument.
10713 *
10714 * The optional _limit_ argument specifies how many characters of each line
10715 * to return. By default all characters are returned.
10716 *
10717 * An EOFError is raised at the end of the file.
10718 */
10719static VALUE
10720argf_readline(int argc, VALUE *argv, VALUE argf)
10721{
10722 VALUE line;
10723
10724 if (!next_argv()) rb_eof_error();
10725 ARGF_FORWARD(argc, argv);
10726 line = argf_gets(argc, argv, argf);
10727 if (NIL_P(line)) {
10728 rb_eof_error();
10729 }
10730
10731 return line;
10732}
10733
10734static VALUE argf_readlines(int, VALUE *, VALUE);
10735
10736/*
10737 * call-seq:
10738 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10739 * readlines(limit, chomp: false, **enc_opts) -> array
10740 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10741 *
10742 * Returns an array containing the lines returned by calling
10743 * Kernel#gets until the end-of-stream is reached;
10744 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10745 *
10746 * With only string argument +sep+ given,
10747 * returns the remaining lines as determined by line separator +sep+,
10748 * or +nil+ if none;
10749 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10750 *
10751 * # Default separator.
10752 * $ cat t.txt | ruby -e "p readlines"
10753 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10754 *
10755 * # Specified separator.
10756 * $ cat t.txt | ruby -e "p readlines 'li'"
10757 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10758 *
10759 * # Get-all separator.
10760 * $ cat t.txt | ruby -e "p readlines nil"
10761 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10762 *
10763 * # Get-paragraph separator.
10764 * $ cat t.txt | ruby -e "p readlines ''"
10765 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10766 *
10767 * With only integer argument +limit+ given,
10768 * limits the number of bytes in the line;
10769 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10770 *
10771 * $cat t.txt | ruby -e "p readlines 10"
10772 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10773 *
10774 * $cat t.txt | ruby -e "p readlines 11"
10775 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10776 *
10777 * $cat t.txt | ruby -e "p readlines 12"
10778 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10779 *
10780 * With arguments +sep+ and +limit+ given,
10781 * combines the two behaviors
10782 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10783 *
10784 * Optional keyword argument +chomp+ specifies whether line separators
10785 * are to be omitted:
10786 *
10787 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10788 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10789 *
10790 * Optional keyword arguments +enc_opts+ specify encoding options;
10791 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10792 *
10793 */
10794
10795static VALUE
10796rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10797{
10798 if (recv == argf) {
10799 return argf_readlines(argc, argv, argf);
10800 }
10801 return forward(argf, rb_intern("readlines"), argc, argv);
10802}
10803
10804/*
10805 * call-seq:
10806 * ARGF.readlines(sep = $/, chomp: false) -> array
10807 * ARGF.readlines(limit, chomp: false) -> array
10808 * ARGF.readlines(sep, limit, chomp: false) -> array
10809 *
10810 * ARGF.to_a(sep = $/, chomp: false) -> array
10811 * ARGF.to_a(limit, chomp: false) -> array
10812 * ARGF.to_a(sep, limit, chomp: false) -> array
10813 *
10814 * Reads each file in ARGF in its entirety, returning an Array containing
10815 * lines from the files. Lines are assumed to be separated by _sep_.
10816 *
10817 * lines = ARGF.readlines
10818 * lines[0] #=> "This is line one\n"
10819 *
10820 * See +IO.readlines+ for a full description of all options.
10821 */
10822static VALUE
10823argf_readlines(int argc, VALUE *argv, VALUE argf)
10824{
10825 long lineno = ARGF.lineno;
10826 VALUE lines, ary;
10827
10828 ary = rb_ary_new();
10829 while (next_argv()) {
10830 if (ARGF_GENERIC_INPUT_P()) {
10831 lines = forward_current(rb_intern("readlines"), argc, argv);
10832 }
10833 else {
10834 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10835 argf_close(argf);
10836 }
10837 ARGF.next_p = 1;
10838 rb_ary_concat(ary, lines);
10839 ARGF.lineno = lineno + RARRAY_LEN(ary);
10840 ARGF.last_lineno = ARGF.lineno;
10841 }
10842 ARGF.init_p = 0;
10843 return ary;
10844}
10845
10846/*
10847 * call-seq:
10848 * `command` -> string
10849 *
10850 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10851 * sets global variable <tt>$?</tt> to the process status.
10852 *
10853 * This method has potential security vulnerabilities if called with untrusted input;
10854 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
10855 *
10856 * Examples:
10857 *
10858 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10859 * $ `echo oops && exit 99` # => "oops\n"
10860 * $ $? # => #<Process::Status: pid 17088 exit 99>
10861 * $ $?.exitstatus # => 99
10862 *
10863 * The built-in syntax <tt>%x{...}</tt> uses this method.
10864 *
10865 */
10866
10867static VALUE
10868rb_f_backquote(VALUE obj, VALUE str)
10869{
10870 VALUE port;
10871 VALUE result;
10872 rb_io_t *fptr;
10873
10874 StringValue(str);
10875 rb_last_status_clear();
10876 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10877 if (NIL_P(port)) return rb_str_new(0,0);
10878
10879 GetOpenFile(port, fptr);
10880 result = read_all(fptr, remain_size(fptr), Qnil);
10881 rb_io_close(port);
10882 rb_io_fptr_cleanup_all(fptr);
10883 RB_GC_GUARD(port);
10884
10885 return result;
10886}
10887
10888#ifdef HAVE_SYS_SELECT_H
10889#include <sys/select.h>
10890#endif
10891
10892static VALUE
10893select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10894{
10895 VALUE res, list;
10896 rb_fdset_t *rp, *wp, *ep;
10897 rb_io_t *fptr;
10898 rb_len_t i;
10899 int max = 0, n;
10900 int pending = 0;
10901 struct timeval timerec;
10902
10903 if (!NIL_P(read)) {
10904 Check_Type(read, T_ARRAY);
10905 for (i=0; i<RARRAY_LEN(read); i++) {
10906 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10907 rb_fd_set(fptr->fd, &fds[0]);
10908 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10909 pending++;
10910 rb_fd_set(fptr->fd, &fds[3]);
10911 }
10912 if (max < fptr->fd) max = fptr->fd;
10913 }
10914 if (pending) { /* no blocking if there's buffered data */
10915 timerec.tv_sec = timerec.tv_usec = 0;
10916 tp = &timerec;
10917 }
10918 rp = &fds[0];
10919 }
10920 else
10921 rp = 0;
10922
10923 if (!NIL_P(write)) {
10924 Check_Type(write, T_ARRAY);
10925 for (i=0; i<RARRAY_LEN(write); i++) {
10926 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10927 GetOpenFile(write_io, fptr);
10928 rb_fd_set(fptr->fd, &fds[1]);
10929 if (max < fptr->fd) max = fptr->fd;
10930 }
10931 wp = &fds[1];
10932 }
10933 else
10934 wp = 0;
10935
10936 if (!NIL_P(except)) {
10937 Check_Type(except, T_ARRAY);
10938 for (i=0; i<RARRAY_LEN(except); i++) {
10939 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10940 VALUE write_io = GetWriteIO(io);
10941 GetOpenFile(io, fptr);
10942 rb_fd_set(fptr->fd, &fds[2]);
10943 if (max < fptr->fd) max = fptr->fd;
10944 if (io != write_io) {
10945 GetOpenFile(write_io, fptr);
10946 rb_fd_set(fptr->fd, &fds[2]);
10947 if (max < fptr->fd) max = fptr->fd;
10948 }
10949 }
10950 ep = &fds[2];
10951 }
10952 else {
10953 ep = 0;
10954 }
10955
10956 max++;
10957
10958 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10959 if (n < 0) {
10960 rb_sys_fail(0);
10961 }
10962 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10963
10964 res = rb_ary_new2(3);
10965 rb_ary_push(res, rp ? rb_ary_new_capa(RARRAY_LEN(read)) : rb_ary_new());
10966 rb_ary_push(res, wp ? rb_ary_new_capa(RARRAY_LEN(write)) : rb_ary_new());
10967 rb_ary_push(res, ep ? rb_ary_new_capa(RARRAY_LEN(except)) : rb_ary_new());
10968
10969 if (rp) {
10970 list = RARRAY_AREF(res, 0);
10971 for (i=0; i< RARRAY_LEN(read); i++) {
10972 VALUE obj = rb_ary_entry(read, i);
10973 VALUE io = rb_io_get_io(obj);
10974 GetOpenFile(io, fptr);
10975 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10976 rb_fd_isset(fptr->fd, &fds[3])) {
10977 rb_ary_push(list, obj);
10978 }
10979 }
10980 }
10981
10982 if (wp) {
10983 list = RARRAY_AREF(res, 1);
10984 for (i=0; i< RARRAY_LEN(write); i++) {
10985 VALUE obj = rb_ary_entry(write, i);
10986 VALUE io = rb_io_get_io(obj);
10987 VALUE write_io = GetWriteIO(io);
10988 GetOpenFile(write_io, fptr);
10989 if (rb_fd_isset(fptr->fd, &fds[1])) {
10990 rb_ary_push(list, obj);
10991 }
10992 }
10993 }
10994
10995 if (ep) {
10996 list = RARRAY_AREF(res, 2);
10997 for (i=0; i< RARRAY_LEN(except); i++) {
10998 VALUE obj = rb_ary_entry(except, i);
10999 VALUE io = rb_io_get_io(obj);
11000 VALUE write_io = GetWriteIO(io);
11001 GetOpenFile(io, fptr);
11002 if (rb_fd_isset(fptr->fd, &fds[2])) {
11003 rb_ary_push(list, obj);
11004 }
11005 else if (io != write_io) {
11006 GetOpenFile(write_io, fptr);
11007 if (rb_fd_isset(fptr->fd, &fds[2])) {
11008 rb_ary_push(list, obj);
11009 }
11010 }
11011 }
11012 }
11013
11014 return res; /* returns an empty array on interrupt */
11015}
11016
11018 VALUE read, write, except;
11019 struct timeval *timeout;
11020 rb_fdset_t fdsets[4];
11021};
11022
11023static VALUE
11024select_call(VALUE arg)
11025{
11026 struct select_args *p = (struct select_args *)arg;
11027
11028 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
11029}
11030
11031static VALUE
11032select_end(VALUE arg)
11033{
11034 struct select_args *p = (struct select_args *)arg;
11035 int i;
11036
11037 for (i = 0; i < numberof(p->fdsets); ++i)
11038 rb_fd_term(&p->fdsets[i]);
11039 return Qnil;
11040}
11041
11042static VALUE sym_normal, sym_sequential, sym_random,
11043 sym_willneed, sym_dontneed, sym_noreuse;
11044
11045#ifdef HAVE_POSIX_FADVISE
11046struct io_advise_struct {
11047 int fd;
11048 int advice;
11049 rb_off_t offset;
11050 rb_off_t len;
11051};
11052
11053static VALUE
11054io_advise_internal(void *arg)
11055{
11056 struct io_advise_struct *ptr = arg;
11057 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
11058}
11059
11060static VALUE
11061io_advise_sym_to_const(VALUE sym)
11062{
11063#ifdef POSIX_FADV_NORMAL
11064 if (sym == sym_normal)
11065 return INT2NUM(POSIX_FADV_NORMAL);
11066#endif
11067
11068#ifdef POSIX_FADV_RANDOM
11069 if (sym == sym_random)
11070 return INT2NUM(POSIX_FADV_RANDOM);
11071#endif
11072
11073#ifdef POSIX_FADV_SEQUENTIAL
11074 if (sym == sym_sequential)
11075 return INT2NUM(POSIX_FADV_SEQUENTIAL);
11076#endif
11077
11078#ifdef POSIX_FADV_WILLNEED
11079 if (sym == sym_willneed)
11080 return INT2NUM(POSIX_FADV_WILLNEED);
11081#endif
11082
11083#ifdef POSIX_FADV_DONTNEED
11084 if (sym == sym_dontneed)
11085 return INT2NUM(POSIX_FADV_DONTNEED);
11086#endif
11087
11088#ifdef POSIX_FADV_NOREUSE
11089 if (sym == sym_noreuse)
11090 return INT2NUM(POSIX_FADV_NOREUSE);
11091#endif
11092
11093 return Qnil;
11094}
11095
11096static VALUE
11097do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
11098{
11099 int rv;
11100 struct io_advise_struct ias;
11101 VALUE num_adv;
11102
11103 num_adv = io_advise_sym_to_const(advice);
11104
11105 /*
11106 * The platform doesn't support this hint. We don't raise exception, instead
11107 * silently ignore it. Because IO::advise is only hint.
11108 */
11109 if (NIL_P(num_adv))
11110 return Qnil;
11111
11112 ias.fd = fptr->fd;
11113 ias.advice = NUM2INT(num_adv);
11114 ias.offset = offset;
11115 ias.len = len;
11116
11117 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
11118 if (rv && rv != ENOSYS) {
11119 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
11120 it returns the error code. */
11121 VALUE message = rb_sprintf("%"PRIsVALUE" "
11122 "(%"PRI_OFFT_PREFIX"d, "
11123 "%"PRI_OFFT_PREFIX"d, "
11124 "%"PRIsVALUE")",
11125 fptr->pathv, offset, len, advice);
11126 rb_syserr_fail_str(rv, message);
11127 }
11128
11129 return Qnil;
11130}
11131
11132#endif /* HAVE_POSIX_FADVISE */
11133
11134static void
11135advice_arg_check(VALUE advice)
11136{
11137 if (!SYMBOL_P(advice))
11138 rb_raise(rb_eTypeError, "advice must be a Symbol");
11139
11140 if (advice != sym_normal &&
11141 advice != sym_sequential &&
11142 advice != sym_random &&
11143 advice != sym_willneed &&
11144 advice != sym_dontneed &&
11145 advice != sym_noreuse) {
11146 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
11147 }
11148}
11149
11150/*
11151 * call-seq:
11152 * advise(advice, offset = 0, len = 0) -> nil
11153 *
11154 * Invokes Posix system call
11155 * {posix_fadvise(2)}[https://man7.org/linux/man-pages/man2/posix_fadvise.2.html],
11156 * which announces an intention to access data from the current file
11157 * in a particular manner.
11158 *
11159 * The arguments and results are platform-dependent.
11160 *
11161 * The relevant data is specified by:
11162 *
11163 * - +offset+: The offset of the first byte of data.
11164 * - +len+: The number of bytes to be accessed;
11165 * if +len+ is zero, or is larger than the number of bytes remaining,
11166 * all remaining bytes will be accessed.
11167 *
11168 * Argument +advice+ is one of the following symbols:
11169 *
11170 * - +:normal+: The application has no advice to give
11171 * about its access pattern for the specified data.
11172 * If no advice is given for an open file, this is the default assumption.
11173 * - +:sequential+: The application expects to access the specified data sequentially
11174 * (with lower offsets read before higher ones).
11175 * - +:random+: The specified data will be accessed in random order.
11176 * - +:noreuse+: The specified data will be accessed only once.
11177 * - +:willneed+: The specified data will be accessed in the near future.
11178 * - +:dontneed+: The specified data will not be accessed in the near future.
11179 *
11180 * Not implemented on all platforms.
11181 *
11182 */
11183static VALUE
11184rb_io_advise(int argc, VALUE *argv, VALUE io)
11185{
11186 VALUE advice, offset, len;
11187 rb_off_t off, l;
11188 rb_io_t *fptr;
11189
11190 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
11191 advice_arg_check(advice);
11192
11193 io = GetWriteIO(io);
11194 GetOpenFile(io, fptr);
11195
11196 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
11197 l = NIL_P(len) ? 0 : NUM2OFFT(len);
11198
11199#ifdef HAVE_POSIX_FADVISE
11200 return do_io_advise(fptr, advice, off, l);
11201#else
11202 ((void)off, (void)l); /* Ignore all hint */
11203 return Qnil;
11204#endif
11205}
11206
11207static int
11208is_pos_inf(VALUE x)
11209{
11210 double f;
11211 if (!RB_FLOAT_TYPE_P(x))
11212 return 0;
11213 f = RFLOAT_VALUE(x);
11214 return isinf(f) && 0 < f;
11215}
11216
11217/*
11218 * call-seq:
11219 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11220 *
11221 * Invokes system call {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html],
11222 * which monitors multiple file descriptors,
11223 * waiting until one or more of the file descriptors
11224 * becomes ready for some class of I/O operation.
11225 *
11226 * Not implemented on all platforms.
11227 *
11228 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11229 * is an array of IO objects.
11230 *
11231 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11232 * interval in seconds.
11233 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11234 * +nil+ and +Float::INFINITY+ means no timeout.
11235 *
11236 * The method monitors the \IO objects given in all three arrays,
11237 * waiting for some to be ready;
11238 * returns a 3-element array whose elements are:
11239 *
11240 * - An array of the objects in +read_ios+ that are ready for reading.
11241 * - An array of the objects in +write_ios+ that are ready for writing.
11242 * - An array of the objects in +error_ios+ have pending exceptions.
11243 *
11244 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11245 *
11246 * \IO.select peeks the buffer of \IO objects for testing readability.
11247 * If the \IO buffer is not empty, \IO.select immediately notifies
11248 * readability. This "peek" only happens for \IO objects. It does not
11249 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11250 *
11251 * The best way to use \IO.select is invoking it after non-blocking
11252 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11253 * raise an exception which is extended by IO::WaitReadable or
11254 * IO::WaitWritable. The modules notify how the caller should wait
11255 * with \IO.select. If IO::WaitReadable is raised, the caller should
11256 * wait for reading. If IO::WaitWritable is raised, the caller should
11257 * wait for writing.
11258 *
11259 * So, blocking read (#readpartial) can be emulated using
11260 * #read_nonblock and \IO.select as follows:
11261 *
11262 * begin
11263 * result = io_like.read_nonblock(maxlen)
11264 * rescue IO::WaitReadable
11265 * IO.select([io_like])
11266 * retry
11267 * rescue IO::WaitWritable
11268 * IO.select(nil, [io_like])
11269 * retry
11270 * end
11271 *
11272 * Especially, the combination of non-blocking methods and \IO.select is
11273 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11274 * has #to_io method to return underlying IO object. IO.select calls
11275 * #to_io to obtain the file descriptor to wait.
11276 *
11277 * This means that readability notified by \IO.select doesn't mean
11278 * readability from OpenSSL::SSL::SSLSocket object.
11279 *
11280 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11281 * some data. \IO.select doesn't see the buffer. So \IO.select can
11282 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11283 *
11284 * However, several more complicated situations exist.
11285 *
11286 * SSL is a protocol which is sequence of records.
11287 * The record consists of multiple bytes.
11288 * So, the remote side of SSL sends a partial record, IO.select
11289 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11290 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11291 *
11292 * Also, the remote side can request SSL renegotiation which forces
11293 * the local SSL engine to write some data.
11294 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11295 * system call and it can block.
11296 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11297 * IO::WaitWritable instead of blocking.
11298 * So, the caller should wait for ready for writability as above
11299 * example.
11300 *
11301 * The combination of non-blocking methods and \IO.select is also useful
11302 * for streams such as tty, pipe socket socket when multiple processes
11303 * read from a stream.
11304 *
11305 * Finally, Linux kernel developers don't guarantee that
11306 * readability of select(2) means readability of following read(2) even
11307 * for a single process;
11308 * see {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html]
11309 *
11310 * Invoking \IO.select before IO#readpartial works well as usual.
11311 * However it is not the best way to use \IO.select.
11312 *
11313 * The writability notified by select(2) doesn't show
11314 * how many bytes are writable.
11315 * IO#write method blocks until given whole string is written.
11316 * So, <tt>IO#write(two or more bytes)</tt> can block after
11317 * writability is notified by \IO.select. IO#write_nonblock is required
11318 * to avoid the blocking.
11319 *
11320 * Blocking write (#write) can be emulated using #write_nonblock and
11321 * IO.select as follows: IO::WaitReadable should also be rescued for
11322 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11323 *
11324 * while 0 < string.bytesize
11325 * begin
11326 * written = io_like.write_nonblock(string)
11327 * rescue IO::WaitReadable
11328 * IO.select([io_like])
11329 * retry
11330 * rescue IO::WaitWritable
11331 * IO.select(nil, [io_like])
11332 * retry
11333 * end
11334 * string = string.byteslice(written..-1)
11335 * end
11336 *
11337 * Example:
11338 *
11339 * rp, wp = IO.pipe
11340 * mesg = "ping "
11341 * 100.times {
11342 * # IO.select follows IO#read. Not the best way to use IO.select.
11343 * rs, ws, = IO.select([rp], [wp])
11344 * if r = rs[0]
11345 * ret = r.read(5)
11346 * print ret
11347 * case ret
11348 * when /ping/
11349 * mesg = "pong\n"
11350 * when /pong/
11351 * mesg = "ping "
11352 * end
11353 * end
11354 * if w = ws[0]
11355 * w.write(mesg)
11356 * end
11357 * }
11358 *
11359 * Output:
11360 *
11361 * ping pong
11362 * ping pong
11363 * ping pong
11364 * (snipped)
11365 * ping
11366 *
11367 */
11368
11369static VALUE
11370rb_f_select(int argc, VALUE *argv, VALUE obj)
11371{
11372 VALUE scheduler = rb_fiber_scheduler_current();
11373 if (scheduler != Qnil) {
11374 // It's optionally supported.
11375 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11376 if (!UNDEF_P(result)) return result;
11377 }
11378
11379 VALUE timeout;
11380 struct select_args args;
11381 struct timeval timerec;
11382 int i;
11383
11384 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11385 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11386 args.timeout = 0;
11387 }
11388 else {
11389 timerec = rb_time_interval(timeout);
11390 args.timeout = &timerec;
11391 }
11392
11393 for (i = 0; i < numberof(args.fdsets); ++i)
11394 rb_fd_init(&args.fdsets[i]);
11395
11396 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11397}
11398
11399#ifdef IOCTL_REQ_TYPE
11400 typedef IOCTL_REQ_TYPE ioctl_req_t;
11401#else
11402 typedef int ioctl_req_t;
11403# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11404#endif
11405
11406#ifdef HAVE_IOCTL
11407struct ioctl_arg {
11408 int fd;
11409 ioctl_req_t cmd;
11410 long narg;
11411};
11412
11413static VALUE
11414nogvl_ioctl(void *ptr)
11415{
11416 struct ioctl_arg *arg = ptr;
11417
11418 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11419}
11420
11421static int
11422do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11423{
11424 int retval;
11425 struct ioctl_arg arg;
11426
11427 arg.fd = io->fd;
11428 arg.cmd = cmd;
11429 arg.narg = narg;
11430
11431 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11432
11433 return retval;
11434}
11435#endif
11436
11437#define DEFAULT_IOCTL_NARG_LEN (256)
11438
11439#if defined(__linux__) && defined(_IOC_SIZE)
11440static long
11441linux_iocparm_len(ioctl_req_t cmd)
11442{
11443 long len;
11444
11445 if ((cmd & 0xFFFF0000) == 0) {
11446 /* legacy and unstructured ioctl number. */
11447 return DEFAULT_IOCTL_NARG_LEN;
11448 }
11449
11450 len = _IOC_SIZE(cmd);
11451
11452 /* paranoia check for silly drivers which don't keep ioctl convention */
11453 if (len < DEFAULT_IOCTL_NARG_LEN)
11454 len = DEFAULT_IOCTL_NARG_LEN;
11455
11456 return len;
11457}
11458#endif
11459
11460#ifdef HAVE_IOCTL
11461static long
11462ioctl_narg_len(ioctl_req_t cmd)
11463{
11464 long len;
11465
11466#ifdef IOCPARM_MASK
11467#ifndef IOCPARM_LEN
11468#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11469#endif
11470#endif
11471#ifdef IOCPARM_LEN
11472 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11473#elif defined(__linux__) && defined(_IOC_SIZE)
11474 len = linux_iocparm_len(cmd);
11475#else
11476 /* otherwise guess at what's safe */
11477 len = DEFAULT_IOCTL_NARG_LEN;
11478#endif
11479
11480 return len;
11481}
11482#endif
11483
11484#ifdef HAVE_FCNTL
11485#ifdef __linux__
11486typedef long fcntl_arg_t;
11487#else
11488/* posix */
11489typedef int fcntl_arg_t;
11490#endif
11491
11492static long
11493fcntl_narg_len(ioctl_req_t cmd)
11494{
11495 long len;
11496
11497 switch (cmd) {
11498#ifdef F_DUPFD
11499 case F_DUPFD:
11500 len = sizeof(fcntl_arg_t);
11501 break;
11502#endif
11503#ifdef F_DUP2FD /* bsd specific */
11504 case F_DUP2FD:
11505 len = sizeof(int);
11506 break;
11507#endif
11508#ifdef F_DUPFD_CLOEXEC /* linux specific */
11509 case F_DUPFD_CLOEXEC:
11510 len = sizeof(fcntl_arg_t);
11511 break;
11512#endif
11513#ifdef F_GETFD
11514 case F_GETFD:
11515 len = 1;
11516 break;
11517#endif
11518#ifdef F_SETFD
11519 case F_SETFD:
11520 len = sizeof(fcntl_arg_t);
11521 break;
11522#endif
11523#ifdef F_GETFL
11524 case F_GETFL:
11525 len = 1;
11526 break;
11527#endif
11528#ifdef F_SETFL
11529 case F_SETFL:
11530 len = sizeof(fcntl_arg_t);
11531 break;
11532#endif
11533#ifdef F_GETOWN
11534 case F_GETOWN:
11535 len = 1;
11536 break;
11537#endif
11538#ifdef F_SETOWN
11539 case F_SETOWN:
11540 len = sizeof(fcntl_arg_t);
11541 break;
11542#endif
11543#ifdef F_GETOWN_EX /* linux specific */
11544 case F_GETOWN_EX:
11545 len = sizeof(struct f_owner_ex);
11546 break;
11547#endif
11548#ifdef F_SETOWN_EX /* linux specific */
11549 case F_SETOWN_EX:
11550 len = sizeof(struct f_owner_ex);
11551 break;
11552#endif
11553#ifdef F_GETLK
11554 case F_GETLK:
11555 len = sizeof(struct flock);
11556 break;
11557#endif
11558#ifdef F_SETLK
11559 case F_SETLK:
11560 len = sizeof(struct flock);
11561 break;
11562#endif
11563#ifdef F_SETLKW
11564 case F_SETLKW:
11565 len = sizeof(struct flock);
11566 break;
11567#endif
11568#ifdef F_READAHEAD /* bsd specific */
11569 case F_READAHEAD:
11570 len = sizeof(int);
11571 break;
11572#endif
11573#ifdef F_RDAHEAD /* Darwin specific */
11574 case F_RDAHEAD:
11575 len = sizeof(int);
11576 break;
11577#endif
11578#ifdef F_GETSIG /* linux specific */
11579 case F_GETSIG:
11580 len = 1;
11581 break;
11582#endif
11583#ifdef F_SETSIG /* linux specific */
11584 case F_SETSIG:
11585 len = sizeof(fcntl_arg_t);
11586 break;
11587#endif
11588#ifdef F_GETLEASE /* linux specific */
11589 case F_GETLEASE:
11590 len = 1;
11591 break;
11592#endif
11593#ifdef F_SETLEASE /* linux specific */
11594 case F_SETLEASE:
11595 len = sizeof(fcntl_arg_t);
11596 break;
11597#endif
11598#ifdef F_NOTIFY /* linux specific */
11599 case F_NOTIFY:
11600 len = sizeof(fcntl_arg_t);
11601 break;
11602#endif
11603
11604 default:
11605 len = 256;
11606 break;
11607 }
11608
11609 return len;
11610}
11611#else /* HAVE_FCNTL */
11612static long
11613fcntl_narg_len(ioctl_req_t cmd)
11614{
11615 return 0;
11616}
11617#endif /* HAVE_FCNTL */
11618
11619#define NARG_SENTINEL 17
11620
11621static long
11622setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11623{
11624 long narg = 0;
11625 VALUE arg = *argp;
11626
11627 if (!RTEST(arg)) {
11628 narg = 0;
11629 }
11630 else if (FIXNUM_P(arg)) {
11631 narg = FIX2LONG(arg);
11632 }
11633 else if (arg == Qtrue) {
11634 narg = 1;
11635 }
11636 else {
11637 VALUE tmp = rb_check_string_type(arg);
11638
11639 if (NIL_P(tmp)) {
11640 narg = NUM2LONG(arg);
11641 }
11642 else {
11643 char *ptr;
11644 long req_len;
11645 rb_len_t slen;
11646
11647 *argp = arg = tmp;
11648 req_len = narg_len(cmd);
11649 rb_str_modify(arg);
11650
11651 slen = RSTRING_LEN(arg);
11652 /* expand for data + sentinel. */
11653 if (slen < req_len+1) {
11654 rb_str_resize(arg, req_len+1);
11655 MEMZERO(RSTRING_PTR(arg)+slen, char, req_len-slen);
11656 slen = req_len+1;
11657 }
11658 /* a little sanity check here */
11659 ptr = RSTRING_PTR(arg);
11660 ptr[slen - 1] = NARG_SENTINEL;
11661 narg = (long)(SIGNED_VALUE)ptr;
11662 }
11663 }
11664
11665 return narg;
11666}
11667
11668static VALUE
11669finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11670{
11671 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11672 if (RB_TYPE_P(arg, T_STRING)) {
11673 char *ptr;
11674 rb_len_t slen;
11675 RSTRING_GETMEM(arg, ptr, slen);
11676 if (ptr[slen-1] != NARG_SENTINEL)
11677 rb_raise(rb_eArgError, "return value overflowed string");
11678 ptr[slen-1] = '\0';
11679 }
11680
11681 return INT2NUM(retval);
11682}
11683
11684#ifdef HAVE_IOCTL
11685static VALUE
11686rb_ioctl(VALUE io, VALUE req, VALUE arg)
11687{
11688 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11689 rb_io_t *fptr;
11690 long narg;
11691 int retval;
11692
11693 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11694 GetOpenFile(io, fptr);
11695 retval = do_ioctl(fptr, cmd, narg);
11696 return finish_narg(retval, arg, fptr);
11697}
11698
11699/*
11700 * call-seq:
11701 * ioctl(integer_cmd, argument) -> integer
11702 *
11703 * Invokes Posix system call {ioctl(2)}[https://man7.org/linux/man-pages/man2/ioctl.2.html],
11704 * which issues a low-level command to an I/O device.
11705 *
11706 * Issues a low-level command to an I/O device.
11707 * The arguments and returned value are platform-dependent.
11708 * The effect of the call is platform-dependent.
11709 *
11710 * If argument +argument+ is an integer, it is passed directly;
11711 * if it is a string, it is interpreted as a binary sequence of bytes.
11712 *
11713 * Not implemented on all platforms.
11714 *
11715 */
11716
11717static VALUE
11718rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11719{
11720 VALUE req, arg;
11721
11722 rb_scan_args(argc, argv, "11", &req, &arg);
11723 return rb_ioctl(io, req, arg);
11724}
11725#else
11726#define rb_io_ioctl rb_f_notimplement
11727#endif
11728
11729#ifdef HAVE_FCNTL
11730struct fcntl_arg {
11731 int fd;
11732 int cmd;
11733 long narg;
11734};
11735
11736static VALUE
11737nogvl_fcntl(void *ptr)
11738{
11739 struct fcntl_arg *arg = ptr;
11740
11741#if defined(F_DUPFD)
11742 if (arg->cmd == F_DUPFD)
11743 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11744#endif
11745 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11746}
11747
11748static int
11749do_fcntl(struct rb_io *io, int cmd, long narg)
11750{
11751 int retval;
11752 struct fcntl_arg arg;
11753
11754 arg.fd = io->fd;
11755 arg.cmd = cmd;
11756 arg.narg = narg;
11757
11758 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11759 if (retval != -1) {
11760 switch (cmd) {
11761#if defined(F_DUPFD)
11762 case F_DUPFD:
11763#endif
11764#if defined(F_DUPFD_CLOEXEC)
11765 case F_DUPFD_CLOEXEC:
11766#endif
11767 rb_update_max_fd(retval);
11768 }
11769 }
11770
11771 return retval;
11772}
11773
11774static VALUE
11775rb_fcntl(VALUE io, VALUE req, VALUE arg)
11776{
11777 int cmd = NUM2INT(req);
11778 rb_io_t *fptr;
11779 long narg;
11780 int retval;
11781
11782 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11783 GetOpenFile(io, fptr);
11784 retval = do_fcntl(fptr, cmd, narg);
11785 return finish_narg(retval, arg, fptr);
11786}
11787
11788/*
11789 * call-seq:
11790 * fcntl(integer_cmd, argument) -> integer
11791 *
11792 * Invokes Posix system call {fcntl(2)}[https://man7.org/linux/man-pages/man2/fcntl.2.html],
11793 * which provides a mechanism for issuing low-level commands to control or query
11794 * a file-oriented I/O stream. Arguments and results are platform
11795 * dependent.
11796 *
11797 * If +argument+ is a number, its value is passed directly;
11798 * if it is a string, it is interpreted as a binary sequence of bytes.
11799 * (Array#pack might be a useful way to build this string.)
11800 *
11801 * Not implemented on all platforms.
11802 *
11803 */
11804
11805static VALUE
11806rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11807{
11808 VALUE req, arg;
11809
11810 rb_scan_args(argc, argv, "11", &req, &arg);
11811 return rb_fcntl(io, req, arg);
11812}
11813#else
11814#define rb_io_fcntl rb_f_notimplement
11815#endif
11816
11817#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11818/*
11819 * call-seq:
11820 * syscall(integer_callno, *arguments) -> integer
11821 *
11822 * Invokes Posix system call {syscall(2)}[https://man7.org/linux/man-pages/man2/syscall.2.html],
11823 * which calls a specified function.
11824 *
11825 * Calls the operating system function identified by +integer_callno+;
11826 * returns the result of the function or raises SystemCallError if it failed.
11827 * The effect of the call is platform-dependent.
11828 * The arguments and returned value are platform-dependent.
11829 *
11830 * For each of +arguments+: if it is an integer, it is passed directly;
11831 * if it is a string, it is interpreted as a binary sequence of bytes.
11832 * There may be as many as nine such arguments.
11833 *
11834 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11835 * are platform-dependent.
11836 *
11837 * Note: Method +syscall+ is essentially unsafe and unportable.
11838 * The DL (Fiddle) library is preferred for safer and a bit
11839 * more portable programming.
11840 *
11841 * Not implemented on all platforms.
11842 *
11843 */
11844
11845static VALUE
11846rb_f_syscall(int argc, VALUE *argv, VALUE _)
11847{
11848 VALUE arg[8];
11849#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11850# define SYSCALL __syscall
11851# define NUM2SYSCALLID(x) NUM2LONG(x)
11852# define RETVAL2NUM(x) LONG2NUM(x)
11853# if SIZEOF_LONG == 8
11854 long num, retval = -1;
11855# elif SIZEOF_LONG_LONG == 8
11856 long long num, retval = -1;
11857# else
11858# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11859# endif
11860#elif defined(__linux__)
11861# define SYSCALL syscall
11862# define NUM2SYSCALLID(x) NUM2LONG(x)
11863# define RETVAL2NUM(x) LONG2NUM(x)
11864 /*
11865 * Linux man page says, syscall(2) function prototype is below.
11866 *
11867 * int syscall(int number, ...);
11868 *
11869 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11870 */
11871 long num, retval = -1;
11872#else
11873# define SYSCALL syscall
11874# define NUM2SYSCALLID(x) NUM2INT(x)
11875# define RETVAL2NUM(x) INT2NUM(x)
11876 int num, retval = -1;
11877#endif
11878 int i;
11879
11880 if (RTEST(ruby_verbose)) {
11882 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11883 }
11884
11885 if (argc == 0)
11886 rb_raise(rb_eArgError, "too few arguments for syscall");
11887 if (argc > numberof(arg))
11888 rb_raise(rb_eArgError, "too many arguments for syscall");
11889 num = NUM2SYSCALLID(argv[0]); ++argv;
11890 for (i = argc - 1; i--; ) {
11891 VALUE v = rb_check_string_type(argv[i]);
11892
11893 if (!NIL_P(v)) {
11894 StringValue(v);
11895 rb_str_modify(v);
11896 arg[i] = (VALUE)StringValueCStr(v);
11897 }
11898 else {
11899 arg[i] = (VALUE)NUM2LONG(argv[i]);
11900 }
11901 }
11902
11903 switch (argc) {
11904 case 1:
11905 retval = SYSCALL(num);
11906 break;
11907 case 2:
11908 retval = SYSCALL(num, arg[0]);
11909 break;
11910 case 3:
11911 retval = SYSCALL(num, arg[0],arg[1]);
11912 break;
11913 case 4:
11914 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11915 break;
11916 case 5:
11917 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11918 break;
11919 case 6:
11920 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11921 break;
11922 case 7:
11923 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11924 break;
11925 case 8:
11926 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11927 break;
11928 }
11929
11930 if (retval == -1)
11931 rb_sys_fail(0);
11932 return RETVAL2NUM(retval);
11933#undef SYSCALL
11934#undef NUM2SYSCALLID
11935#undef RETVAL2NUM
11936}
11937#else
11938#define rb_f_syscall rb_f_notimplement
11939#endif
11940
11941static VALUE
11942io_new_instance(VALUE args)
11943{
11944 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11945}
11946
11947static rb_encoding *
11948find_encoding(VALUE v)
11949{
11950 rb_encoding *enc = rb_find_encoding(v);
11951 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11952 return enc;
11953}
11954
11955static void
11956io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11957{
11958 rb_encoding *enc, *enc2;
11959 int ecflags = fptr->encs.ecflags;
11960 VALUE ecopts, tmp;
11961
11962 if (!NIL_P(v2)) {
11963 enc2 = find_encoding(v1);
11964 tmp = rb_check_string_type(v2);
11965 if (!NIL_P(tmp)) {
11966 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11967 /* Special case - "-" => no transcoding */
11968 enc = enc2;
11969 enc2 = NULL;
11970 }
11971 else
11972 enc = find_encoding(v2);
11973 if (enc == enc2) {
11974 /* Special case - "-" => no transcoding */
11975 enc2 = NULL;
11976 }
11977 }
11978 else {
11979 enc = find_encoding(v2);
11980 if (enc == enc2) {
11981 /* Special case - "-" => no transcoding */
11982 enc2 = NULL;
11983 }
11984 }
11985 if (enc2 == rb_ascii8bit_encoding()) {
11986 /* If external is ASCII-8BIT, no transcoding */
11987 enc = enc2;
11988 enc2 = NULL;
11989 }
11990 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11991 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11992 }
11993 else {
11994 if (NIL_P(v1)) {
11995 /* Set to default encodings */
11996 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11997 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11998 ecopts = Qnil;
11999 }
12000 else {
12001 tmp = rb_check_string_type(v1);
12002 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
12003 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
12004 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12005 }
12006 else {
12007 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
12008 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12009 }
12010 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
12011 }
12012 }
12013 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
12014 fptr->encs.enc = enc;
12015 fptr->encs.enc2 = enc2;
12016 fptr->encs.ecflags = ecflags;
12017 fptr->encs.ecopts = ecopts;
12018 clear_codeconv(fptr);
12019
12020}
12021
12023 rb_io_t *fptr;
12024 VALUE v1;
12025 VALUE v2;
12026 VALUE opt;
12027};
12028
12029static VALUE
12030io_encoding_set_v(VALUE v)
12031{
12032 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
12033 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
12034 return Qnil;
12035}
12036
12037static VALUE
12038pipe_pair_close(VALUE rw)
12039{
12040 VALUE *rwp = (VALUE *)rw;
12041 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
12042}
12043
12044/*
12045 * call-seq:
12046 * IO.pipe(**opts) -> [read_io, write_io]
12047 * IO.pipe(enc, **opts) -> [read_io, write_io]
12048 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
12049 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
12050 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
12051 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
12052 *
12053 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
12054 * connected to each other.
12055 *
12056 * If argument +enc_string+ is given, it must be a string containing one of:
12057 *
12058 * - The name of the encoding to be used as the external encoding.
12059 * - The colon-separated names of two encodings to be used as the external
12060 * and internal encodings.
12061 *
12062 * If argument +int_enc+ is given, it must be an Encoding object
12063 * or encoding name string that specifies the internal encoding to be used;
12064 * if argument +ext_enc+ is also given, it must be an Encoding object
12065 * or encoding name string that specifies the external encoding to be used.
12066 *
12067 * The string read from +read_io+ is tagged with the external encoding;
12068 * if an internal encoding is also specified, the string is converted
12069 * to, and tagged with, that encoding.
12070 *
12071 * If any encoding is specified,
12072 * optional hash arguments specify the conversion option.
12073 *
12074 * Optional keyword arguments +opts+ specify:
12075 *
12076 * - {Open Options}[rdoc-ref:IO@Open+Options].
12077 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12078 *
12079 * With no block given, returns the two endpoints in an array:
12080 *
12081 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
12082 *
12083 * With a block given, calls the block with the two endpoints;
12084 * closes both endpoints and returns the value of the block:
12085 *
12086 * IO.pipe {|read_io, write_io| p read_io; p write_io }
12087 *
12088 * Output:
12089 *
12090 * #<IO:fd 6>
12091 * #<IO:fd 7>
12092 *
12093 * Not available on all platforms.
12094 *
12095 * In the example below, the two processes close the ends of the pipe
12096 * that they are not using. This is not just a cosmetic nicety. The
12097 * read end of a pipe will not generate an end of file condition if
12098 * there are any writers with the pipe still open. In the case of the
12099 * parent process, the <tt>rd.read</tt> will never return if it
12100 * does not first issue a <tt>wr.close</tt>:
12101 *
12102 * rd, wr = IO.pipe
12103 *
12104 * if fork
12105 * wr.close
12106 * puts "Parent got: <#{rd.read}>"
12107 * rd.close
12108 * Process.wait
12109 * else
12110 * rd.close
12111 * puts 'Sending message to parent'
12112 * wr.write "Hi Dad"
12113 * wr.close
12114 * end
12115 *
12116 * <em>produces:</em>
12117 *
12118 * Sending message to parent
12119 * Parent got: <Hi Dad>
12120 *
12121 */
12122
12123static VALUE
12124rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
12125{
12126 int pipes[2], state;
12127 VALUE r, w, args[3], v1, v2;
12128 VALUE opt;
12129 rb_io_t *fptr, *fptr2;
12130 struct io_encoding_set_args ies_args;
12131 enum rb_io_mode fmode = 0;
12132 VALUE ret;
12133
12134 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
12135 if (rb_pipe(pipes) < 0)
12136 rb_sys_fail(0);
12137
12138 args[0] = klass;
12139 args[1] = INT2NUM(pipes[0]);
12140 args[2] = INT2FIX(O_RDONLY);
12141 r = rb_protect(io_new_instance, (VALUE)args, &state);
12142 if (state) {
12143 close(pipes[0]);
12144 close(pipes[1]);
12145 rb_jump_tag(state);
12146 }
12147 GetOpenFile(r, fptr);
12148
12149 ies_args.fptr = fptr;
12150 ies_args.v1 = v1;
12151 ies_args.v2 = v2;
12152 ies_args.opt = opt;
12153 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
12154 if (state) {
12155 close(pipes[1]);
12156 io_close(r);
12157 rb_jump_tag(state);
12158 }
12159
12160 args[1] = INT2NUM(pipes[1]);
12161 args[2] = INT2FIX(O_WRONLY);
12162 w = rb_protect(io_new_instance, (VALUE)args, &state);
12163 if (state) {
12164 close(pipes[1]);
12165 if (!NIL_P(r)) rb_io_close(r);
12166 rb_jump_tag(state);
12167 }
12168 GetOpenFile(w, fptr2);
12169 rb_io_synchronized(fptr2);
12170
12171 extract_binmode(opt, &fmode);
12172
12173 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
12176 }
12177
12178#if DEFAULT_TEXTMODE
12179 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12180 fptr->mode &= ~FMODE_TEXTMODE;
12181 setmode(fptr->fd, O_BINARY);
12182 }
12183#if RUBY_CRLF_ENVIRONMENT
12186 }
12187#endif
12188#endif
12189 fptr->mode |= fmode;
12190#if DEFAULT_TEXTMODE
12191 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12192 fptr2->mode &= ~FMODE_TEXTMODE;
12193 setmode(fptr2->fd, O_BINARY);
12194 }
12195#endif
12196 fptr2->mode |= fmode;
12197
12198 ret = rb_assoc_new(r, w);
12199 if (rb_block_given_p()) {
12200 VALUE rw[2];
12201 rw[0] = r;
12202 rw[1] = w;
12203 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12204 }
12205 return ret;
12206}
12207
12209 int argc;
12210 VALUE *argv;
12211 VALUE io;
12212};
12213
12214static void
12215open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12216{
12217 VALUE path, v;
12218 VALUE vmode = Qnil, vperm = Qnil;
12219
12220 path = *argv++;
12221 argc--;
12222 FilePathValue(path);
12223 arg->io = 0;
12224 arg->argc = argc;
12225 arg->argv = argv;
12226 if (NIL_P(opt)) {
12227 vmode = INT2NUM(O_RDONLY);
12228 vperm = INT2FIX(0666);
12229 }
12230 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12231 int n;
12232
12233 v = rb_to_array_type(v);
12234 n = RARRAY_LENINT(v);
12235 rb_check_arity(n, 0, 3); /* rb_io_open */
12236 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12237 }
12238 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12239}
12240
12241static VALUE
12242io_s_foreach(VALUE v)
12243{
12244 struct getline_arg *arg = (void *)v;
12245 VALUE str;
12246
12247 if (arg->limit == 0)
12248 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12249 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12250 rb_lastline_set(str);
12251 rb_yield(str);
12252 }
12254 return Qnil;
12255}
12256
12257/*
12258 * call-seq:
12259 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12260 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12261 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12262 * IO.foreach(...) -> an_enumerator
12263 *
12264 * Calls the block with each successive line read from the stream.
12265 *
12266 * The first argument must be a string that is the path to a file.
12267 *
12268 * With only argument +path+ given, parses lines from the file at the given +path+,
12269 * as determined by the default line separator,
12270 * and calls the block with each successive line:
12271 *
12272 * File.foreach('t.txt') {|line| p line }
12273 *
12274 * Output: the same as above.
12275 *
12276 * For both forms, command and path, the remaining arguments are the same.
12277 *
12278 * With argument +sep+ given, parses lines as determined by that line separator
12279 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12280 *
12281 * File.foreach('t.txt', 'li') {|line| p line }
12282 *
12283 * Output:
12284 *
12285 * "First li"
12286 * "ne\nSecond li"
12287 * "ne\n\nThird li"
12288 * "ne\nFourth li"
12289 * "ne\n"
12290 *
12291 * Each paragraph:
12292 *
12293 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12294 *
12295 * Output:
12296 *
12297 * "First line\nSecond line\n\n"
12298 * "Third line\nFourth line\n"
12299 *
12300 * With argument +limit+ given, parses lines as determined by the default
12301 * line separator and the given line-length limit
12302 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12303 *
12304 * File.foreach('t.txt', 7) {|line| p line }
12305 *
12306 * Output:
12307 *
12308 * "First l"
12309 * "ine\n"
12310 * "Second "
12311 * "line\n"
12312 * "\n"
12313 * "Third l"
12314 * "ine\n"
12315 * "Fourth l"
12316 * "line\n"
12317 *
12318 * With arguments +sep+ and +limit+ given,
12319 * combines the two behaviors
12320 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12321 *
12322 * Optional keyword arguments +opts+ specify:
12323 *
12324 * - {Open Options}[rdoc-ref:IO@Open+Options].
12325 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12326 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12327 *
12328 * Returns an Enumerator if no block is given.
12329 *
12330 */
12331
12332static VALUE
12333rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12334{
12335 VALUE opt;
12336 int orig_argc = argc;
12337 struct foreach_arg arg;
12338 struct getline_arg garg;
12339
12340 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12341 RETURN_ENUMERATOR(self, orig_argc, argv);
12342 extract_getline_args(argc-1, argv+1, &garg);
12343 open_key_args(self, argc, argv, opt, &arg);
12344 if (NIL_P(arg.io)) return Qnil;
12345 extract_getline_opts(opt, &garg);
12346 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12347 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12348}
12349
12350static VALUE
12351io_s_readlines(VALUE v)
12352{
12353 struct getline_arg *arg = (void *)v;
12354 return io_readlines(arg, arg->io);
12355}
12356
12357/*
12358 * call-seq:
12359 * IO.readlines(path, sep = $/, **opts) -> array
12360 * IO.readlines(path, limit, **opts) -> array
12361 * IO.readlines(path, sep, limit, **opts) -> array
12362 *
12363 * Returns an array of all lines read from the stream.
12364 *
12365 * The first argument must be a string that is the path to a file.
12366 *
12367 * With only argument +path+ given, parses lines from the file at the given +path+,
12368 * as determined by the default line separator,
12369 * and returns those lines in an array:
12370 *
12371 * IO.readlines('t.txt')
12372 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12373 *
12374 * With argument +sep+ given, parses lines as determined by that line separator
12375 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12376 *
12377 * # Ordinary separator.
12378 * IO.readlines('t.txt', 'li')
12379 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12380 * # Get-paragraphs separator.
12381 * IO.readlines('t.txt', '')
12382 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12383 * # Get-all separator.
12384 * IO.readlines('t.txt', nil)
12385 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12386 *
12387 * With argument +limit+ given, parses lines as determined by the default
12388 * line separator and the given line-length limit
12389 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12390 *
12391 * IO.readlines('t.txt', 7)
12392 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12393 *
12394 * With arguments +sep+ and +limit+ given,
12395 * combines the two behaviors
12396 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12397 *
12398 * Optional keyword arguments +opts+ specify:
12399 *
12400 * - {Open Options}[rdoc-ref:IO@Open+Options].
12401 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12402 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12403 *
12404 */
12405
12406static VALUE
12407rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12408{
12409 VALUE opt;
12410 struct foreach_arg arg;
12411 struct getline_arg garg;
12412
12413 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12414 extract_getline_args(argc-1, argv+1, &garg);
12415 open_key_args(io, argc, argv, opt, &arg);
12416 if (NIL_P(arg.io)) return Qnil;
12417 extract_getline_opts(opt, &garg);
12418 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12419 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12420}
12421
12422static VALUE
12423io_s_read(VALUE v)
12424{
12425 struct foreach_arg *arg = (void *)v;
12426 return io_read(arg->argc, arg->argv, arg->io);
12427}
12428
12429struct seek_arg {
12430 VALUE io;
12431 VALUE offset;
12432 int mode;
12433};
12434
12435static VALUE
12436seek_before_access(VALUE argp)
12437{
12438 struct seek_arg *arg = (struct seek_arg *)argp;
12439 rb_io_binmode(arg->io);
12440 return rb_io_seek(arg->io, arg->offset, arg->mode);
12441}
12442
12443/*
12444 * call-seq:
12445 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12446 *
12447 * Opens the stream, reads and returns some or all of its content,
12448 * and closes the stream; returns +nil+ if no bytes were read.
12449 *
12450 * The first argument must be a string that is the path to a file.
12451 *
12452 * With only argument +path+ given, reads in text mode and returns the entire content
12453 * of the file at the given path:
12454 *
12455 * File.read('t.txt')
12456 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
12457 * File.read('t.ja')
12458 * # => "こんにちは"
12459 * File.read('t.dat')
12460 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12461 *
12462 * On Windows, text mode can terminate reading and leave bytes in the file
12463 * unread when encountering certain special bytes. Consider using
12464 * IO.binread if all bytes in the file should be read.
12465 *
12466 * With argument +length+, returns +length+ bytes if available:
12467 *
12468 * File.read('t.txt', 7)
12469 * # => "First l"
12470 * File.read('t.ja', 7)
12471 * # => "\xE3\x81\x93\xE3\x82\x93\xE3"
12472 * File.read('t.dat', 7)
12473 * # => "\xFE\xFF\x99\x90\x99\x91\x99"
12474 *
12475 * Returns all bytes if +length+ is larger than the files size:
12476 *
12477 * File.read('t.txt', 700)
12478 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12479 * File.read('t.ja', 700)
12480 * # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
12481 * File.read('t.dat', 700)
12482 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12483 *
12484 * With arguments +length+ and +offset+, returns +length+ bytes
12485 * if available, beginning at the given +offset+:
12486 *
12487 * File.read('t.txt', 10, 2)
12488 * # => "rst line\r\n"
12489 * File.read('t.ja', 10, 2)
12490 * # => "\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1"
12491 * File.read('t.dat', 10, 2)
12492 * # => "\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12493 *
12494 * Returns +nil+ if +offset+ is past the end of the stream:
12495 *
12496 * File.read('t.txt', 10, 200)
12497 * # => nil
12498 *
12499 * Optional keyword arguments +opts+ specify:
12500 *
12501 * - {Open Options}[rdoc-ref:IO@Open+Options].
12502 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12503 *
12504 */
12505
12506static VALUE
12507rb_io_s_read(int argc, VALUE *argv, VALUE io)
12508{
12509 VALUE opt, offset;
12510 rb_len_t off;
12511 struct foreach_arg arg;
12512
12513 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12514 if (!NIL_P(offset) && (off = NUM2LEN(offset)) < 0) {
12515 rb_raise(rb_eArgError, "negative offset %"PRIdLEN" given", off);
12516 }
12517 open_key_args(io, argc, argv, opt, &arg);
12518 if (NIL_P(arg.io)) return Qnil;
12519 if (!NIL_P(offset)) {
12520 struct seek_arg sarg;
12521 int state = 0;
12522 sarg.io = arg.io;
12523 sarg.offset = offset;
12524 sarg.mode = SEEK_SET;
12525 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12526 if (state) {
12527 rb_io_close(arg.io);
12528 rb_jump_tag(state);
12529 }
12530 if (arg.argc == 2) arg.argc = 1;
12531 }
12532 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12533}
12534
12535/*
12536 * call-seq:
12537 * IO.binread(path, length = nil, offset = 0) -> string or nil
12538 *
12539 * Behaves like IO.read, except that the stream is opened in binary mode
12540 * with ASCII-8BIT encoding.
12541 *
12542 */
12543
12544static VALUE
12545rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12546{
12547 VALUE offset;
12548 struct foreach_arg arg;
12549 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12550 enum {
12551 oflags = O_RDONLY
12552#ifdef O_BINARY
12553 |O_BINARY
12554#endif
12555 };
12556 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12557
12558 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12559 FilePathValue(argv[0]);
12560 convconfig.enc = rb_ascii8bit_encoding();
12561 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12562 if (NIL_P(arg.io)) return Qnil;
12563 arg.argv = argv+1;
12564 arg.argc = (argc > 1) ? 1 : 0;
12565 if (!NIL_P(offset)) {
12566 struct seek_arg sarg;
12567 int state = 0;
12568 sarg.io = arg.io;
12569 sarg.offset = offset;
12570 sarg.mode = SEEK_SET;
12571 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12572 if (state) {
12573 rb_io_close(arg.io);
12574 rb_jump_tag(state);
12575 }
12576 }
12577 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12578}
12579
12580static VALUE
12581io_s_write0(VALUE v)
12582{
12583 struct write_arg *arg = (void *)v;
12584 return io_write(arg->io,arg->str,arg->nosync);
12585}
12586
12587static VALUE
12588io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12589{
12590 VALUE string, offset, opt;
12591 struct foreach_arg arg;
12592 struct write_arg warg;
12593
12594 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12595
12596 if (NIL_P(opt)) opt = rb_hash_new();
12597 else opt = rb_hash_dup(opt);
12598
12599
12600 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12601 int mode = O_WRONLY|O_CREAT;
12602#ifdef O_BINARY
12603 if (binary) mode |= O_BINARY;
12604#endif
12605 if (NIL_P(offset)) mode |= O_TRUNC;
12606 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12607 }
12608 open_key_args(klass, argc, argv, opt, &arg);
12609
12610#ifndef O_BINARY
12611 if (binary) rb_io_binmode_m(arg.io);
12612#endif
12613
12614 if (NIL_P(arg.io)) return Qnil;
12615 if (!NIL_P(offset)) {
12616 struct seek_arg sarg;
12617 int state = 0;
12618 sarg.io = arg.io;
12619 sarg.offset = offset;
12620 sarg.mode = SEEK_SET;
12621 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12622 if (state) {
12623 rb_io_close(arg.io);
12624 rb_jump_tag(state);
12625 }
12626 }
12627
12628 warg.io = arg.io;
12629 warg.str = string;
12630 warg.nosync = 0;
12631
12632 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12633}
12634
12635/*
12636 * call-seq:
12637 * IO.write(path, data, offset = 0, **opts) -> nonnegative_integer
12638 *
12639 * Opens the stream, writes the given +data+ to it,
12640 * and closes the stream; returns the number of bytes written.
12641 *
12642 * The first argument must be a string that is the path to a file.
12643 *
12644 * With only arguments +path+ and +data+ given,
12645 * writes the given data to the file at that path:
12646 *
12647 * path = 't.tmp'
12648 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n") # => 47
12649 * File.write(path, 'こんにちは') # => 15
12650 * File.write(path, "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94") # => 12
12651 *
12652 * When +offset+ is zero (the default), the entire file content is overwritten:
12653 *
12654 * File.read(path) # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12655 * File.write(path, 'foo')
12656 * File.read(path) # => "foo"
12657 *
12658 * When +offset+ in within the file content, the file content is partly overwritten,
12659 * beginning at byte +offset+:
12660 *
12661 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12662 * File.write(path, 'LINE', 6)
12663 * File.read(path) # => "First LINE\nSecond line\n\nFourth line\nFifth line\n"
12664 *
12665 * When the file contains multi-byte characters,
12666 * the effect of writing may disturb some characters:
12667 *
12668 * File.write(path, "こんにちは")
12669 * File.write(path, 'FOO', 3) # Replace one 3-byte character.
12670 * File.read(path) # => "こFOOにちは"
12671 * File.write(path, 'BAR', 7) # Replace bytes in two different 3-byte characters.
12672 * File.read(path) # => "こFOO\xE3BAR\x81\xA1は"
12673 *
12674 * If +offset+ is outside the file content,
12675 * the file is padded with null characters <tt>"\u0000"</tt>:
12676 *
12677 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12678 * File.write(path, 'FOO', 55)
12679 * File.read(path)
12680 * # => "First line\nSecond line\n\nFourth line\nFifth line\n\u0000\u0000\u0000FOO"
12681 *
12682 * Optional keyword arguments +opts+ specify:
12683 *
12684 * - {Open Options}[rdoc-ref:IO@Open+Options].
12685 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12686 *
12687 */
12688
12689static VALUE
12690rb_io_s_write(int argc, VALUE *argv, VALUE io)
12691{
12692 return io_s_write(argc, argv, io, 0);
12693}
12694
12695/*
12696 * call-seq:
12697 * IO.binwrite(path, string, offset = 0, **opts) -> integer
12698 *
12699 * Behaves like IO.write, except that the stream is opened in binary mode
12700 * with ASCII-8BIT encoding.
12701 *
12702 */
12703
12704static VALUE
12705rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12706{
12707 return io_s_write(argc, argv, io, 1);
12708}
12709
12711 VALUE src;
12712 VALUE dst;
12713 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12714 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12715
12716 rb_io_t *src_fptr;
12717 rb_io_t *dst_fptr;
12718 unsigned close_src : 1;
12719 unsigned close_dst : 1;
12720 int error_no;
12721 rb_off_t total;
12722 const char *syserr;
12723 const char *notimp;
12724 VALUE th;
12725 struct stat src_stat;
12726 struct stat dst_stat;
12727#ifdef HAVE_FCOPYFILE
12728 copyfile_state_t copyfile_state;
12729#endif
12730};
12731
12732static void *
12733exec_interrupts(void *arg)
12734{
12735 VALUE th = (VALUE)arg;
12736 rb_thread_execute_interrupts(th);
12737 return NULL;
12738}
12739
12740/*
12741 * returns TRUE if the preceding system call was interrupted
12742 * so we can continue. If the thread was interrupted, we
12743 * reacquire the GVL to execute interrupts before continuing.
12744 */
12745static int
12746maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12747{
12748 switch (errno) {
12749 case EINTR:
12750#if defined(ERESTART)
12751 case ERESTART:
12752#endif
12753 if (rb_thread_interrupted(stp->th)) {
12754 if (has_gvl)
12755 rb_thread_execute_interrupts(stp->th);
12756 else
12757 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12758 }
12759 return TRUE;
12760 }
12761 return FALSE;
12762}
12763
12765 VALUE scheduler;
12766
12767 rb_io_t *fptr;
12768 short events;
12769
12770 VALUE result;
12771};
12772
12773static void *
12774fiber_scheduler_wait_for(void * _arguments)
12775{
12776 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12777
12778 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12779
12780 return NULL;
12781}
12782
12783#if USE_POLL
12784# define IOWAIT_SYSCALL "poll"
12785STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12786STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12787static int
12788nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12789{
12791 if (scheduler != Qnil) {
12792 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12793 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12794 return RTEST(args.result);
12795 }
12796
12797 int fd = fptr->fd;
12798 if (fd == -1) return 0;
12799
12800 struct pollfd fds;
12801
12802 fds.fd = fd;
12803 fds.events = events;
12804
12805 int timeout_milliseconds = -1;
12806
12807 if (timeout) {
12808 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12809 }
12810
12811 return poll(&fds, 1, timeout_milliseconds);
12812}
12813#else /* !USE_POLL */
12814# define IOWAIT_SYSCALL "select"
12815static int
12816nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12817{
12819 if (scheduler != Qnil) {
12820 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12821 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12822 return RTEST(args.result);
12823 }
12824
12825 int fd = fptr->fd;
12826
12827 if (fd == -1) {
12828 errno = EBADF;
12829 return -1;
12830 }
12831
12832 rb_fdset_t fds;
12833 int ret;
12834
12835 rb_fd_init(&fds);
12836 rb_fd_set(fd, &fds);
12837
12838 switch (events) {
12839 case RB_WAITFD_IN:
12840 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12841 break;
12842 case RB_WAITFD_OUT:
12843 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12844 break;
12845 default:
12846 VM_UNREACHABLE(nogvl_wait_for);
12847 }
12848
12849 rb_fd_term(&fds);
12850
12851 // On timeout, this returns 0.
12852 return ret;
12853}
12854#endif /* !USE_POLL */
12855
12856static int
12857maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12858{
12859 int ret;
12860
12861 do {
12862 if (has_gvl) {
12864 }
12865 else {
12866 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12867 }
12868 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12869
12870 if (ret < 0) {
12871 stp->syserr = IOWAIT_SYSCALL;
12872 stp->error_no = errno;
12873 return ret;
12874 }
12875 return 0;
12876}
12877
12878static int
12879nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12880{
12881 int ret;
12882
12883 do {
12884 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12885 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12886
12887 if (ret < 0) {
12888 stp->syserr = IOWAIT_SYSCALL;
12889 stp->error_no = errno;
12890 return ret;
12891 }
12892 return 0;
12893}
12894
12895#ifdef USE_COPY_FILE_RANGE
12896
12897static ssize_t
12898simple_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)
12899{
12900#ifdef HAVE_COPY_FILE_RANGE
12901 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12902#else
12903 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12904#endif
12905}
12906
12907static int
12908nogvl_copy_file_range(struct copy_stream_struct *stp)
12909{
12910 ssize_t ss;
12911 rb_off_t src_size;
12912 rb_off_t copy_length, src_offset, *src_offset_ptr;
12913
12914 if (!S_ISREG(stp->src_stat.st_mode))
12915 return 0;
12916
12917 src_size = stp->src_stat.st_size;
12918 src_offset = stp->src_offset;
12919 if (src_offset >= (rb_off_t)0) {
12920 src_offset_ptr = &src_offset;
12921 }
12922 else {
12923 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12924 }
12925
12926 copy_length = stp->copy_length;
12927 if (copy_length < (rb_off_t)0) {
12928 if (src_offset < (rb_off_t)0) {
12929 rb_off_t current_offset;
12930 errno = 0;
12931 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12932 if (current_offset < (rb_off_t)0 && errno) {
12933 stp->syserr = "lseek";
12934 stp->error_no = errno;
12935 return (int)current_offset;
12936 }
12937 copy_length = src_size - current_offset;
12938 }
12939 else {
12940 copy_length = src_size - src_offset;
12941 }
12942 }
12943
12944 retry_copy_file_range:
12945# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12946 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12947 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12948# else
12949 ss = (ssize_t)copy_length;
12950# endif
12951 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12952 if (0 < ss) {
12953 stp->total += ss;
12954 copy_length -= ss;
12955 if (0 < copy_length) {
12956 goto retry_copy_file_range;
12957 }
12958 }
12959 if (ss < 0) {
12960 if (maygvl_copy_stream_continue_p(0, stp)) {
12961 goto retry_copy_file_range;
12962 }
12963 switch (errno) {
12964 case EINVAL:
12965 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12966 docker container) */
12967#ifdef ENOSYS
12968 case ENOSYS:
12969#endif
12970#ifdef EXDEV
12971 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12972#endif
12973 return 0;
12974 case EAGAIN:
12975#if EWOULDBLOCK != EAGAIN
12976 case EWOULDBLOCK:
12977#endif
12978 {
12979 int ret = nogvl_copy_stream_wait_write(stp);
12980 if (ret < 0) return ret;
12981 }
12982 goto retry_copy_file_range;
12983 case EBADF:
12984 {
12985 int e = errno;
12986 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12987
12988 if (flags != -1 && flags & O_APPEND) {
12989 return 0;
12990 }
12991 errno = e;
12992 }
12993 }
12994 stp->syserr = "copy_file_range";
12995 stp->error_no = errno;
12996 return (int)ss;
12997 }
12998 return 1;
12999}
13000#endif
13001
13002#ifdef HAVE_FCOPYFILE
13003static int
13004nogvl_fcopyfile(struct copy_stream_struct *stp)
13005{
13006 rb_off_t cur, ss = 0;
13007 const rb_off_t src_offset = stp->src_offset;
13008 int ret;
13009
13010 if (stp->copy_length >= (rb_off_t)0) {
13011 /* copy_length can't be specified in fcopyfile(3) */
13012 return 0;
13013 }
13014
13015 if (!S_ISREG(stp->src_stat.st_mode))
13016 return 0;
13017
13018 if (!S_ISREG(stp->dst_stat.st_mode))
13019 return 0;
13020 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
13021 return 0;
13022 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
13023 /* fcopyfile(3) appends src IO to dst IO and then truncates
13024 * dst IO to src IO's original size. */
13025 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
13026 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
13027 if (end > (rb_off_t)0) return 0;
13028 }
13029
13030 if (src_offset > (rb_off_t)0) {
13031 rb_off_t r;
13032
13033 /* get current offset */
13034 errno = 0;
13035 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13036 if (cur < (rb_off_t)0 && errno) {
13037 stp->error_no = errno;
13038 return 1;
13039 }
13040
13041 errno = 0;
13042 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13043 if (r < (rb_off_t)0 && errno) {
13044 stp->error_no = errno;
13045 return 1;
13046 }
13047 }
13048
13049 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
13050 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
13051 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
13052
13053 if (ret == 0) { /* success */
13054 stp->total = ss;
13055 if (src_offset > (rb_off_t)0) {
13056 rb_off_t r;
13057 errno = 0;
13058 /* reset offset */
13059 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
13060 if (r < (rb_off_t)0 && errno) {
13061 stp->error_no = errno;
13062 return 1;
13063 }
13064 }
13065 }
13066 else {
13067 switch (errno) {
13068 case ENOTSUP:
13069 case EPERM:
13070 case EINVAL:
13071 return 0;
13072 }
13073 stp->syserr = "fcopyfile";
13074 stp->error_no = errno;
13075 return (int)ret;
13076 }
13077 return 1;
13078}
13079#endif
13080
13081#ifdef HAVE_SENDFILE
13082
13083# ifdef __linux__
13084# define USE_SENDFILE
13085
13086# ifdef HAVE_SYS_SENDFILE_H
13087# include <sys/sendfile.h>
13088# endif
13089
13090static ssize_t
13091simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13092{
13093 return sendfile(out_fd, in_fd, offset, (size_t)count);
13094}
13095
13096# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
13097/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
13098 * without cpuset -l 0.
13099 */
13100# define USE_SENDFILE
13101
13102static ssize_t
13103simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13104{
13105 int r;
13106 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
13107 rb_off_t sbytes;
13108# ifdef __APPLE__
13109 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
13110 sbytes = count;
13111# else
13112 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
13113# endif
13114 if (r != 0 && sbytes == 0) return r;
13115 if (offset) {
13116 *offset += sbytes;
13117 }
13118 else {
13119 lseek(in_fd, sbytes, SEEK_CUR);
13120 }
13121 return (ssize_t)sbytes;
13122}
13123
13124# endif
13125
13126#endif
13127
13128#ifdef USE_SENDFILE
13129static int
13130nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
13131{
13132 ssize_t ss;
13133 rb_off_t src_size;
13134 rb_off_t copy_length;
13135 rb_off_t src_offset;
13136 int use_pread;
13137
13138 if (!S_ISREG(stp->src_stat.st_mode))
13139 return 0;
13140
13141 src_size = stp->src_stat.st_size;
13142#ifndef __linux__
13143 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
13144 return 0;
13145#endif
13146
13147 src_offset = stp->src_offset;
13148 use_pread = src_offset >= (rb_off_t)0;
13149
13150 copy_length = stp->copy_length;
13151 if (copy_length < (rb_off_t)0) {
13152 if (use_pread)
13153 copy_length = src_size - src_offset;
13154 else {
13155 rb_off_t cur;
13156 errno = 0;
13157 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13158 if (cur < (rb_off_t)0 && errno) {
13159 stp->syserr = "lseek";
13160 stp->error_no = errno;
13161 return (int)cur;
13162 }
13163 copy_length = src_size - cur;
13164 }
13165 }
13166
13167 retry_sendfile:
13168# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13169 /* we are limited by the 32-bit ssize_t return value on 32-bit */
13170 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13171# else
13172 ss = (ssize_t)copy_length;
13173# endif
13174 if (use_pread) {
13175 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
13176 }
13177 else {
13178 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
13179 }
13180 if (0 < ss) {
13181 stp->total += ss;
13182 copy_length -= ss;
13183 if (0 < copy_length) {
13184 goto retry_sendfile;
13185 }
13186 }
13187 if (ss < 0) {
13188 if (maygvl_copy_stream_continue_p(0, stp))
13189 goto retry_sendfile;
13190 switch (errno) {
13191 case EINVAL:
13192#ifdef ENOSYS
13193 case ENOSYS:
13194#endif
13195#ifdef EOPNOTSUP
13196 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
13197 see also: [Feature #16965] */
13198 case EOPNOTSUP:
13199#endif
13200 return 0;
13201 case EAGAIN:
13202#if EWOULDBLOCK != EAGAIN
13203 case EWOULDBLOCK:
13204#endif
13205 {
13206 int ret;
13207#ifndef __linux__
13208 /*
13209 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
13210 * select() reports regular files to always be "ready", so
13211 * there is no need to select() on it.
13212 * Other OSes may have the same limitation for sendfile() which
13213 * allow us to bypass maygvl_copy_stream_wait_read()...
13214 */
13215 ret = maygvl_copy_stream_wait_read(0, stp);
13216 if (ret < 0) return ret;
13217#endif
13218 ret = nogvl_copy_stream_wait_write(stp);
13219 if (ret < 0) return ret;
13220 }
13221 goto retry_sendfile;
13222 }
13223 stp->syserr = "sendfile";
13224 stp->error_no = errno;
13225 return (int)ss;
13226 }
13227 return 1;
13228}
13229#endif
13230
13231static ssize_t
13232maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13233{
13234 if (has_gvl)
13235 return rb_io_read_memory(fptr, buf, count);
13236 else
13237 return read(fptr->fd, buf, count);
13238}
13239
13240static ssize_t
13241maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13242{
13243 ssize_t ss;
13244 retry_read:
13245 if (offset < (rb_off_t)0) {
13246 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13247 }
13248 else {
13249 ss = pread(stp->src_fptr->fd, buf, len, offset);
13250 }
13251 if (ss == 0) {
13252 return 0;
13253 }
13254 if (ss < 0) {
13255 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13256 goto retry_read;
13257 switch (errno) {
13258 case EAGAIN:
13259#if EWOULDBLOCK != EAGAIN
13260 case EWOULDBLOCK:
13261#endif
13262 {
13263 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13264 if (ret < 0) return ret;
13265 }
13266 goto retry_read;
13267#ifdef ENOSYS
13268 case ENOSYS:
13269 stp->notimp = "pread";
13270 return ss;
13271#endif
13272 }
13273 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13274 stp->error_no = errno;
13275 }
13276 return ss;
13277}
13278
13279static int
13280nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13281{
13282 ssize_t ss;
13283 int off = 0;
13284 while (len) {
13285 ss = write(stp->dst_fptr->fd, buf+off, len);
13286 if (ss < 0) {
13287 if (maygvl_copy_stream_continue_p(0, stp))
13288 continue;
13289 if (io_again_p(errno)) {
13290 int ret = nogvl_copy_stream_wait_write(stp);
13291 if (ret < 0) return ret;
13292 continue;
13293 }
13294 stp->syserr = "write";
13295 stp->error_no = errno;
13296 return (int)ss;
13297 }
13298 off += (int)ss;
13299 len -= (int)ss;
13300 stp->total += ss;
13301 }
13302 return 0;
13303}
13304
13305static void
13306nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13307{
13308 char buf[1024*16];
13309 size_t len;
13310 ssize_t ss;
13311 int ret;
13312 rb_off_t copy_length;
13313 rb_off_t src_offset;
13314 int use_eof;
13315 int use_pread;
13316
13317 copy_length = stp->copy_length;
13318 use_eof = copy_length < (rb_off_t)0;
13319 src_offset = stp->src_offset;
13320 use_pread = src_offset >= (rb_off_t)0;
13321
13322 if (use_pread && stp->close_src) {
13323 rb_off_t r;
13324 errno = 0;
13325 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13326 if (r < (rb_off_t)0 && errno) {
13327 stp->syserr = "lseek";
13328 stp->error_no = errno;
13329 return;
13330 }
13331 src_offset = (rb_off_t)-1;
13332 use_pread = 0;
13333 }
13334
13335 while (use_eof || 0 < copy_length) {
13336 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13337 len = (size_t)copy_length;
13338 }
13339 else {
13340 len = sizeof(buf);
13341 }
13342 if (use_pread) {
13343 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13344 if (0 < ss)
13345 src_offset += ss;
13346 }
13347 else {
13348 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13349 }
13350 if (ss <= 0) /* EOF or error */
13351 return;
13352
13353 ret = nogvl_copy_stream_write(stp, buf, ss);
13354 if (ret < 0)
13355 return;
13356
13357 if (!use_eof)
13358 copy_length -= ss;
13359 }
13360}
13361
13362static void *
13363nogvl_copy_stream_func(void *arg)
13364{
13365 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13366#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13367 int ret;
13368#endif
13369
13370#ifdef USE_COPY_FILE_RANGE
13371 ret = nogvl_copy_file_range(stp);
13372 if (ret != 0)
13373 goto finish; /* error or success */
13374#endif
13375
13376#ifdef HAVE_FCOPYFILE
13377 ret = nogvl_fcopyfile(stp);
13378 if (ret != 0)
13379 goto finish; /* error or success */
13380#endif
13381
13382#ifdef USE_SENDFILE
13383 ret = nogvl_copy_stream_sendfile(stp);
13384 if (ret != 0)
13385 goto finish; /* error or success */
13386#endif
13387
13388 nogvl_copy_stream_read_write(stp);
13389
13390#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13391 finish:
13392#endif
13393 return 0;
13394}
13395
13396static VALUE
13397copy_stream_fallback_body(VALUE arg)
13398{
13399 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13400 const int buflen = 16*1024;
13401 VALUE n;
13402 VALUE buf = rb_str_buf_new(buflen);
13403 rb_off_t rest = stp->copy_length;
13404 rb_off_t off = stp->src_offset;
13405 ID read_method = id_readpartial;
13406
13407 if (!stp->src_fptr) {
13408 if (!rb_respond_to(stp->src, read_method)) {
13409 read_method = id_read;
13410 }
13411 }
13412
13413 while (1) {
13414 rb_len_t numwrote;
13415 rb_len_t l;
13416 rb_str_make_independent(buf);
13417 if (stp->copy_length < (rb_off_t)0) {
13418 l = buflen;
13419 }
13420 else {
13421 if (rest == 0) {
13422 rb_str_resize(buf, 0);
13423 break;
13424 }
13425 l = buflen < rest ? buflen : (rb_len_t)rest;
13426 }
13427 if (!stp->src_fptr) {
13428 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13429
13430 if (read_method == id_read && NIL_P(rc))
13431 break;
13432 }
13433 else {
13434 ssize_t ss;
13435 rb_str_resize(buf, buflen);
13436 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13437 rb_str_resize(buf, ss > 0 ? ss : 0);
13438 if (ss < 0)
13439 return Qnil;
13440 if (ss == 0)
13441 rb_eof_error();
13442 if (off >= (rb_off_t)0)
13443 off += ss;
13444 }
13445 n = rb_io_write(stp->dst, buf);
13446 numwrote = NUM2LEN(n);
13447 stp->total += numwrote;
13448 rest -= numwrote;
13449 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13450 break;
13451 }
13452 }
13453
13454 return Qnil;
13455}
13456
13457static VALUE
13458copy_stream_fallback(struct copy_stream_struct *stp)
13459{
13460 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13461 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13462 }
13463 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13464 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13465 rb_eEOFError, (VALUE)0);
13466 return Qnil;
13467}
13468
13469static VALUE
13470copy_stream_body(VALUE arg)
13471{
13472 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13473 VALUE src_io = stp->src, dst_io = stp->dst;
13474 const int common_oflags = 0
13475#ifdef O_NOCTTY
13476 | O_NOCTTY
13477#endif
13478 ;
13479
13480 stp->th = rb_thread_current();
13481
13482 stp->total = 0;
13483
13484 if (src_io == argf ||
13485 !(RB_TYPE_P(src_io, T_FILE) ||
13486 RB_TYPE_P(src_io, T_STRING) ||
13487 rb_respond_to(src_io, rb_intern("to_path")))) {
13488 stp->src_fptr = NULL;
13489 }
13490 else {
13491 int stat_ret;
13492 VALUE tmp_io = rb_io_check_io(src_io);
13493 if (!NIL_P(tmp_io)) {
13494 src_io = tmp_io;
13495 }
13496 else if (!RB_TYPE_P(src_io, T_FILE)) {
13497 VALUE args[2];
13498 FilePathValue(src_io);
13499 args[0] = src_io;
13500 args[1] = INT2NUM(O_RDONLY|common_oflags);
13501 src_io = rb_class_new_instance(2, args, rb_cFile);
13502 stp->src = src_io;
13503 stp->close_src = 1;
13504 }
13505 RB_IO_POINTER(src_io, stp->src_fptr);
13506 rb_io_check_byte_readable(stp->src_fptr);
13507
13508 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13509 if (stat_ret < 0) {
13510 stp->syserr = "fstat";
13511 stp->error_no = errno;
13512 return Qnil;
13513 }
13514 }
13515
13516 if (dst_io == argf ||
13517 !(RB_TYPE_P(dst_io, T_FILE) ||
13518 RB_TYPE_P(dst_io, T_STRING) ||
13519 rb_respond_to(dst_io, rb_intern("to_path")))) {
13520 stp->dst_fptr = NULL;
13521 }
13522 else {
13523 int stat_ret;
13524 VALUE tmp_io = rb_io_check_io(dst_io);
13525 if (!NIL_P(tmp_io)) {
13526 dst_io = GetWriteIO(tmp_io);
13527 }
13528 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13529 VALUE args[3];
13530 FilePathValue(dst_io);
13531 args[0] = dst_io;
13532 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13533 args[2] = INT2FIX(0666);
13534 dst_io = rb_class_new_instance(3, args, rb_cFile);
13535 stp->dst = dst_io;
13536 stp->close_dst = 1;
13537 }
13538 else {
13539 dst_io = GetWriteIO(dst_io);
13540 stp->dst = dst_io;
13541 }
13542 RB_IO_POINTER(dst_io, stp->dst_fptr);
13543 rb_io_check_writable(stp->dst_fptr);
13544
13545 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13546 if (stat_ret < 0) {
13547 stp->syserr = "fstat";
13548 stp->error_no = errno;
13549 return Qnil;
13550 }
13551 }
13552
13553#ifdef O_BINARY
13554 if (stp->src_fptr)
13555 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13556#endif
13557 if (stp->dst_fptr)
13558 io_ascii8bit_binmode(stp->dst_fptr);
13559
13560 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13561 size_t len = stp->src_fptr->rbuf.len;
13562 VALUE str;
13563 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13564 len = (size_t)stp->copy_length;
13565 }
13566 str = rb_str_buf_new(len);
13567 rb_str_resize(str,len);
13568 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13569 if (stp->dst_fptr) { /* IO or filename */
13570 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13571 rb_sys_fail_on_write(stp->dst_fptr);
13572 }
13573 else /* others such as StringIO */
13574 rb_io_write(dst_io, str);
13575 rb_str_resize(str, 0);
13576 stp->total += len;
13577 if (stp->copy_length >= (rb_off_t)0)
13578 stp->copy_length -= len;
13579 }
13580
13581 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13582 rb_raise(rb_eIOError, "flush failed");
13583 }
13584
13585 if (stp->copy_length == 0)
13586 return Qnil;
13587
13588 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13589 return copy_stream_fallback(stp);
13590 }
13591
13592 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13593 return Qnil;
13594}
13595
13596static VALUE
13597copy_stream_finalize(VALUE arg)
13598{
13599 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13600
13601#ifdef HAVE_FCOPYFILE
13602 if (stp->copyfile_state) {
13603 copyfile_state_free(stp->copyfile_state);
13604 }
13605#endif
13606
13607 if (stp->close_src) {
13608 rb_io_close_m(stp->src);
13609 }
13610 if (stp->close_dst) {
13611 rb_io_close_m(stp->dst);
13612 }
13613 if (stp->syserr) {
13614 rb_syserr_fail(stp->error_no, stp->syserr);
13615 }
13616 if (stp->notimp) {
13617 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13618 }
13619 return Qnil;
13620}
13621
13622/*
13623 * call-seq:
13624 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13625 *
13626 * Copies from the given +src+ to the given +dst+,
13627 * returning the number of bytes copied.
13628 *
13629 * - The given +src+ must be one of the following:
13630 *
13631 * - The path to a readable file, from which source data is to be read.
13632 * - An \IO-like object, opened for reading and capable of responding
13633 * to method +:readpartial+ or method +:read+.
13634 *
13635 * - The given +dst+ must be one of the following:
13636 *
13637 * - The path to a writable file, to which data is to be written.
13638 * - An \IO-like object, opened for writing and capable of responding
13639 * to method +:write+.
13640 *
13641 * The examples here use file <tt>t.txt</tt> as source:
13642 *
13643 * File.read('t.txt')
13644 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13645 * File.read('t.txt').size # => 47
13646 *
13647 * If only arguments +src+ and +dst+ are given,
13648 * the entire source stream is copied:
13649 *
13650 * # Paths.
13651 * IO.copy_stream('t.txt', 't.tmp') # => 47
13652 *
13653 * # IOs (recall that a File is also an IO).
13654 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13655 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13656 * IO.copy_stream(src_io, dst_io) # => 47
13657 * src_io.close
13658 * dst_io.close
13659 *
13660 * With argument +src_length+ a non-negative integer,
13661 * no more than that many bytes are copied:
13662 *
13663 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13664 * File.read('t.tmp') # => "First line"
13665 *
13666 * With argument +src_offset+ also given,
13667 * the source stream is read beginning at that offset:
13668 *
13669 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13670 * IO.read('t.tmp') # => "Second line"
13671 *
13672 */
13673static VALUE
13674rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13675{
13676 VALUE src, dst, length, src_offset;
13677 struct copy_stream_struct st;
13678
13679 MEMZERO(&st, struct copy_stream_struct, 1);
13680
13681 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13682
13683 st.src = src;
13684 st.dst = dst;
13685
13686 st.src_fptr = NULL;
13687 st.dst_fptr = NULL;
13688
13689 if (NIL_P(length))
13690 st.copy_length = (rb_off_t)-1;
13691 else
13692 st.copy_length = NUM2OFFT(length);
13693
13694 if (NIL_P(src_offset))
13695 st.src_offset = (rb_off_t)-1;
13696 else
13697 st.src_offset = NUM2OFFT(src_offset);
13698
13699 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13700
13701 return OFFT2NUM(st.total);
13702}
13703
13704/*
13705 * call-seq:
13706 * external_encoding -> encoding or nil
13707 *
13708 * Returns the Encoding object that represents the encoding of the stream,
13709 * or +nil+ if the stream is in write mode and no encoding is specified.
13710 *
13711 * See {Encodings}[rdoc-ref:File@Encodings].
13712 *
13713 */
13714
13715static VALUE
13716rb_io_external_encoding(VALUE io)
13717{
13718 rb_io_t *fptr = rb_io_get_fptr(rb_io_taint_check(io));
13719
13720 if (fptr->encs.enc2) {
13721 return rb_enc_from_encoding(fptr->encs.enc2);
13722 }
13723 if (fptr->mode & FMODE_WRITABLE) {
13724 if (fptr->encs.enc)
13725 return rb_enc_from_encoding(fptr->encs.enc);
13726 return Qnil;
13727 }
13728 return rb_enc_from_encoding(io_read_encoding(fptr));
13729}
13730
13731/*
13732 * call-seq:
13733 * internal_encoding -> encoding or nil
13734 *
13735 * Returns the Encoding object that represents the encoding of the internal string,
13736 * if conversion is specified,
13737 * or +nil+ otherwise.
13738 *
13739 * See {Encodings}[rdoc-ref:File@Encodings].
13740 *
13741 */
13742
13743static VALUE
13744rb_io_internal_encoding(VALUE io)
13745{
13746 rb_io_t *fptr = rb_io_get_fptr(rb_io_taint_check(io));
13747
13748 if (!fptr->encs.enc2) return Qnil;
13749 return rb_enc_from_encoding(io_read_encoding(fptr));
13750}
13751
13752/*
13753 * call-seq:
13754 * set_encoding(ext_enc) -> self
13755 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13756 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13757 *
13758 * See {Encodings}[rdoc-ref:File@Encodings].
13759 *
13760 * Argument +ext_enc+, if given, must be an Encoding object
13761 * or a String with the encoding name;
13762 * it is assigned as the encoding for the stream.
13763 *
13764 * Argument +int_enc+, if given, must be an Encoding object
13765 * or a String with the encoding name;
13766 * it is assigned as the encoding for the internal string.
13767 *
13768 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13769 * containing two colon-separated encoding names;
13770 * corresponding Encoding objects are assigned as the external
13771 * and internal encodings for the stream.
13772 *
13773 * If the external encoding of a string is binary/ASCII-8BIT,
13774 * the internal encoding of the string is set to nil, since no
13775 * transcoding is needed.
13776 *
13777 * Optional keyword arguments +enc_opts+ specify
13778 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13779 *
13780 */
13781
13782static VALUE
13783rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13784{
13785 rb_io_t *fptr;
13786 VALUE v1, v2, opt;
13787
13788 if (!RB_TYPE_P(io, T_FILE)) {
13789 return forward(io, id_set_encoding, argc, argv);
13790 }
13791
13792 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13793 GetOpenFile(io, fptr);
13794 io_encoding_set(fptr, v1, v2, opt);
13795 return io;
13796}
13797
13798void
13799rb_stdio_set_default_encoding(void)
13800{
13801 VALUE val = Qnil;
13802
13803#ifdef _WIN32
13804 if (isatty(fileno(stdin))) {
13805 rb_encoding *external = rb_locale_encoding();
13806 rb_encoding *internal = rb_default_internal_encoding();
13807 if (!internal) internal = rb_default_external_encoding();
13808 io_encoding_set(RFILE(rb_stdin)->fptr,
13809 rb_enc_from_encoding(external),
13810 rb_enc_from_encoding(internal),
13811 Qnil);
13812 }
13813 else
13814#endif
13815 rb_io_set_encoding(1, &val, rb_stdin);
13816 rb_io_set_encoding(1, &val, rb_stdout);
13817 rb_io_set_encoding(1, &val, rb_stderr);
13818}
13819
13820static inline int
13821global_argf_p(VALUE arg)
13822{
13823 return arg == argf;
13824}
13825
13826typedef VALUE (*argf_encoding_func)(VALUE io);
13827
13828static VALUE
13829argf_encoding(VALUE argf, argf_encoding_func func)
13830{
13831 if (!RTEST(ARGF.current_file)) {
13832 return rb_enc_default_external();
13833 }
13834 return func(rb_io_check_io(ARGF.current_file));
13835}
13836
13837/*
13838 * call-seq:
13839 * ARGF.external_encoding -> encoding
13840 *
13841 * Returns the external encoding for files read from ARGF as an Encoding
13842 * object. The external encoding is the encoding of the text as stored in a
13843 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13844 * represent this text within Ruby.
13845 *
13846 * To set the external encoding use ARGF.set_encoding.
13847 *
13848 * For example:
13849 *
13850 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13851 *
13852 */
13853static VALUE
13854argf_external_encoding(VALUE argf)
13855{
13856 return argf_encoding(argf, rb_io_external_encoding);
13857}
13858
13859/*
13860 * call-seq:
13861 * ARGF.internal_encoding -> encoding
13862 *
13863 * Returns the internal encoding for strings read from ARGF as an
13864 * Encoding object.
13865 *
13866 * If ARGF.set_encoding has been called with two encoding names, the second
13867 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13868 * value is returned. Failing that, if a default external encoding was
13869 * specified on the command-line, that value is used. If the encoding is
13870 * unknown, +nil+ is returned.
13871 */
13872static VALUE
13873argf_internal_encoding(VALUE argf)
13874{
13875 return argf_encoding(argf, rb_io_internal_encoding);
13876}
13877
13878/*
13879 * call-seq:
13880 * ARGF.set_encoding(ext_enc) -> ARGF
13881 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13882 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13883 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13884 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13885 *
13886 * If single argument is specified, strings read from ARGF are tagged with
13887 * the encoding specified.
13888 *
13889 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13890 * the read string is converted from the first encoding (external encoding)
13891 * to the second encoding (internal encoding), then tagged with the second
13892 * encoding.
13893 *
13894 * If two arguments are specified, they must be encoding objects or encoding
13895 * names. Again, the first specifies the external encoding; the second
13896 * specifies the internal encoding.
13897 *
13898 * If the external encoding and the internal encoding are specified, the
13899 * optional Hash argument can be used to adjust the conversion process. The
13900 * structure of this hash is explained in the String#encode documentation.
13901 *
13902 * For example:
13903 *
13904 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13905 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13906 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13907 * # to UTF-8.
13908 */
13909static VALUE
13910argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13911{
13912 rb_io_t *fptr;
13913
13914 if (!next_argv()) {
13915 rb_raise(rb_eArgError, "no stream to set encoding");
13916 }
13917 rb_io_set_encoding(argc, argv, ARGF.current_file);
13918 GetOpenFile(ARGF.current_file, fptr);
13919 ARGF.encs = fptr->encs;
13920 RB_OBJ_WRITTEN(argf, Qundef, ARGF.encs.ecopts);
13921 return argf;
13922}
13923
13924/*
13925 * call-seq:
13926 * ARGF.tell -> Integer
13927 * ARGF.pos -> Integer
13928 *
13929 * Returns the current offset (in bytes) of the current file in ARGF.
13930 *
13931 * ARGF.pos #=> 0
13932 * ARGF.gets #=> "This is line one\n"
13933 * ARGF.pos #=> 17
13934 *
13935 */
13936static VALUE
13937argf_tell(VALUE argf)
13938{
13939 if (!next_argv()) {
13940 rb_raise(rb_eArgError, "no stream to tell");
13941 }
13942 ARGF_FORWARD(0, 0);
13943 return rb_io_tell(ARGF.current_file);
13944}
13945
13946/*
13947 * call-seq:
13948 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13949 *
13950 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13951 * the value of _whence_. See IO#seek for further details.
13952 */
13953static VALUE
13954argf_seek_m(int argc, VALUE *argv, VALUE argf)
13955{
13956 if (!next_argv()) {
13957 rb_raise(rb_eArgError, "no stream to seek");
13958 }
13959 ARGF_FORWARD(argc, argv);
13960 return rb_io_seek_m(argc, argv, ARGF.current_file);
13961}
13962
13963/*
13964 * call-seq:
13965 * ARGF.pos = position -> Integer
13966 *
13967 * Seeks to the position given by _position_ (in bytes) in ARGF.
13968 *
13969 * For example:
13970 *
13971 * ARGF.pos = 17
13972 * ARGF.gets #=> "This is line two\n"
13973 */
13974static VALUE
13975argf_set_pos(VALUE argf, VALUE offset)
13976{
13977 if (!next_argv()) {
13978 rb_raise(rb_eArgError, "no stream to set position");
13979 }
13980 ARGF_FORWARD(1, &offset);
13981 return rb_io_set_pos(ARGF.current_file, offset);
13982}
13983
13984/*
13985 * call-seq:
13986 * ARGF.rewind -> 0
13987 *
13988 * Positions the current file to the beginning of input, resetting
13989 * ARGF.lineno to zero.
13990 *
13991 * ARGF.readline #=> "This is line one\n"
13992 * ARGF.rewind #=> 0
13993 * ARGF.lineno #=> 0
13994 * ARGF.readline #=> "This is line one\n"
13995 */
13996static VALUE
13997argf_rewind(VALUE argf)
13998{
13999 VALUE ret;
14000 int old_lineno;
14001
14002 if (!next_argv()) {
14003 rb_raise(rb_eArgError, "no stream to rewind");
14004 }
14005 ARGF_FORWARD(0, 0);
14006 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
14007 ret = rb_io_rewind(ARGF.current_file);
14008 if (!global_argf_p(argf)) {
14009 ARGF.last_lineno = ARGF.lineno -= old_lineno;
14010 }
14011 return ret;
14012}
14013
14014/*
14015 * call-seq:
14016 * ARGF.fileno -> integer
14017 * ARGF.to_i -> integer
14018 *
14019 * Returns an integer representing the numeric file descriptor for
14020 * the current file. Raises an ArgumentError if there isn't a current file.
14021 *
14022 * ARGF.fileno #=> 3
14023 */
14024static VALUE
14025argf_fileno(VALUE argf)
14026{
14027 if (!next_argv()) {
14028 rb_raise(rb_eArgError, "no stream");
14029 }
14030 ARGF_FORWARD(0, 0);
14031 return rb_io_fileno(ARGF.current_file);
14032}
14033
14034/*
14035 * call-seq:
14036 * ARGF.to_io -> IO
14037 *
14038 * Returns an IO object representing the current file. This will be a
14039 * File object unless the current file is a stream such as STDIN.
14040 *
14041 * For example:
14042 *
14043 * ARGF.to_io #=> #<File:glark.txt>
14044 * ARGF.to_io #=> #<IO:<STDIN>>
14045 */
14046static VALUE
14047argf_to_io(VALUE argf)
14048{
14049 next_argv();
14050 ARGF_FORWARD(0, 0);
14051 return ARGF.current_file;
14052}
14053
14054/*
14055 * call-seq:
14056 * ARGF.eof? -> true or false
14057 * ARGF.eof -> true or false
14058 *
14059 * Returns true if the current file in ARGF is at end of file, i.e. it has
14060 * no data to read. The stream must be opened for reading or an IOError
14061 * will be raised.
14062 *
14063 * $ echo "eof" | ruby argf.rb
14064 *
14065 * ARGF.eof? #=> false
14066 * 3.times { ARGF.readchar }
14067 * ARGF.eof? #=> false
14068 * ARGF.readchar #=> "\n"
14069 * ARGF.eof? #=> true
14070 */
14071
14072static VALUE
14073argf_eof(VALUE argf)
14074{
14075 next_argv();
14076 if (RTEST(ARGF.current_file)) {
14077 if (ARGF.init_p == 0) return Qtrue;
14078 next_argv();
14079 ARGF_FORWARD(0, 0);
14080 if (rb_io_eof(ARGF.current_file)) {
14081 return Qtrue;
14082 }
14083 }
14084 return Qfalse;
14085}
14086
14087/*
14088 * call-seq:
14089 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
14090 *
14091 * Reads _length_ bytes from ARGF. The files named on the command line
14092 * are concatenated and treated as a single file by this method, so when
14093 * called without arguments the contents of this pseudo file are returned in
14094 * their entirety.
14095 *
14096 * _length_ must be a non-negative integer or +nil+.
14097 *
14098 * If _length_ is a positive integer, +read+ tries to read
14099 * _length_ bytes without any conversion (binary mode).
14100 * It returns +nil+ if an EOF is encountered before anything can be read.
14101 * Fewer than _length_ bytes are returned if an EOF is encountered during
14102 * the read.
14103 * In the case of an integer _length_, the resulting string is always
14104 * in ASCII-8BIT encoding.
14105 *
14106 * If _length_ is omitted or is +nil+, it reads until EOF
14107 * and the encoding conversion is applied, if applicable.
14108 * A string is returned even if EOF is encountered before any data is read.
14109 *
14110 * If _length_ is zero, it returns an empty string (<code>""</code>).
14111 *
14112 * If the optional _outbuf_ argument is present,
14113 * it must reference a String, which will receive the data.
14114 * The _outbuf_ will contain only the received data after the method call
14115 * even if it is not empty at the beginning.
14116 *
14117 * For example:
14118 *
14119 * $ echo "small" > small.txt
14120 * $ echo "large" > large.txt
14121 * $ ./glark.rb small.txt large.txt
14122 *
14123 * ARGF.read #=> "small\nlarge"
14124 * ARGF.read(200) #=> "small\nlarge"
14125 * ARGF.read(2) #=> "sm"
14126 * ARGF.read(0) #=> ""
14127 *
14128 * Note that this method behaves like the fread() function in C.
14129 * This means it retries to invoke read(2) system calls to read data
14130 * with the specified length.
14131 * If you need the behavior like a single read(2) system call,
14132 * consider ARGF#readpartial or ARGF#read_nonblock.
14133 */
14134
14135static VALUE
14136argf_read(int argc, VALUE *argv, VALUE argf)
14137{
14138 VALUE tmp, str, length;
14139 rb_len_t len = 0;
14140
14141 rb_scan_args(argc, argv, "02", &length, &str);
14142 if (!NIL_P(length)) {
14143 len = NUM2LEN(argv[0]);
14144 }
14145 if (!NIL_P(str)) {
14146 StringValue(str);
14147 rb_str_resize(str,0);
14148 argv[1] = Qnil;
14149 }
14150
14151 retry:
14152 if (!next_argv()) {
14153 return str;
14154 }
14155 if (ARGF_GENERIC_INPUT_P()) {
14156 tmp = argf_forward(argc, argv, argf);
14157 }
14158 else {
14159 tmp = io_read(argc, argv, ARGF.current_file);
14160 }
14161 if (NIL_P(str)) str = tmp;
14162 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
14163 if (NIL_P(tmp) || NIL_P(length)) {
14164 if (ARGF.next_p != -1) {
14165 argf_close(argf);
14166 ARGF.next_p = 1;
14167 goto retry;
14168 }
14169 }
14170 else if (argc >= 1) {
14171 rb_len_t slen = RSTRING_LEN(str);
14172 if (slen < len) {
14173 argv[0] = LEN2NUM(len - slen);
14174 goto retry;
14175 }
14176 }
14177 return str;
14178}
14179
14181 int argc;
14182 VALUE *argv;
14183 VALUE argf;
14184};
14185
14186static VALUE
14187argf_forward_call(VALUE arg)
14188{
14189 struct argf_call_arg *p = (struct argf_call_arg *)arg;
14190 argf_forward(p->argc, p->argv, p->argf);
14191 return Qnil;
14192}
14193
14194static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
14195 int nonblock);
14196
14197/*
14198 * call-seq:
14199 * ARGF.readpartial(maxlen) -> string
14200 * ARGF.readpartial(maxlen, outbuf) -> outbuf
14201 *
14202 * Reads at most _maxlen_ bytes from the ARGF stream.
14203 *
14204 * If the optional _outbuf_ argument is present,
14205 * it must reference a String, which will receive the data.
14206 * The _outbuf_ will contain only the received data after the method call
14207 * even if it is not empty at the beginning.
14208 *
14209 * It raises EOFError on end of ARGF stream.
14210 * Since ARGF stream is a concatenation of multiple files,
14211 * internally EOF is occur for each file.
14212 * ARGF.readpartial returns empty strings for EOFs except the last one and
14213 * raises EOFError for the last one.
14214 *
14215 */
14216
14217static VALUE
14218argf_readpartial(int argc, VALUE *argv, VALUE argf)
14219{
14220 return argf_getpartial(argc, argv, argf, Qnil, 0);
14221}
14222
14223/*
14224 * call-seq:
14225 * ARGF.read_nonblock(maxlen[, options]) -> string
14226 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14227 *
14228 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14229 */
14230
14231static VALUE
14232argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14233{
14234 VALUE opts;
14235
14236 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14237
14238 if (!NIL_P(opts))
14239 argc--;
14240
14241 return argf_getpartial(argc, argv, argf, opts, 1);
14242}
14243
14244static VALUE
14245argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14246{
14247 VALUE tmp, str, length;
14248 int no_exception;
14249
14250 rb_scan_args(argc, argv, "11", &length, &str);
14251 if (!NIL_P(str)) {
14252 StringValue(str);
14253 argv[1] = str;
14254 }
14255 no_exception = no_exception_p(opts);
14256
14257 if (!next_argv()) {
14258 if (!NIL_P(str)) {
14259 rb_str_resize(str, 0);
14260 }
14261 rb_eof_error();
14262 }
14263 if (ARGF_GENERIC_INPUT_P()) {
14264 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14265 struct argf_call_arg arg;
14266 arg.argc = argc;
14267 arg.argv = argv;
14268 arg.argf = argf;
14269 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14270 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14271 }
14272 else {
14273 tmp = io_getpartial(ARGF.current_file, length, str, no_exception, nonblock);
14274 }
14275 if (NIL_P(tmp)) {
14276 if (ARGF.next_p == -1) {
14277 return io_nonblock_eof(no_exception);
14278 }
14279 argf_close(argf);
14280 ARGF.next_p = 1;
14281 if (RARRAY_LEN(ARGF.argv) == 0) {
14282 return io_nonblock_eof(no_exception);
14283 }
14284 if (NIL_P(str))
14285 str = rb_str_new(NULL, 0);
14286 return str;
14287 }
14288 return tmp;
14289}
14290
14291/*
14292 * call-seq:
14293 * ARGF.getc -> String or nil
14294 *
14295 * Reads the next character from ARGF and returns it as a String. Returns
14296 * +nil+ at the end of the stream.
14297 *
14298 * ARGF treats the files named on the command line as a single file created
14299 * by concatenating their contents. After returning the last character of the
14300 * first file, it returns the first character of the second file, and so on.
14301 *
14302 * For example:
14303 *
14304 * $ echo "foo" > file
14305 * $ ruby argf.rb file
14306 *
14307 * ARGF.getc #=> "f"
14308 * ARGF.getc #=> "o"
14309 * ARGF.getc #=> "o"
14310 * ARGF.getc #=> "\n"
14311 * ARGF.getc #=> nil
14312 * ARGF.getc #=> nil
14313 */
14314static VALUE
14315argf_getc(VALUE argf)
14316{
14317 VALUE ch;
14318
14319 retry:
14320 if (!next_argv()) return Qnil;
14321 if (ARGF_GENERIC_INPUT_P()) {
14322 ch = forward_current(rb_intern("getc"), 0, 0);
14323 }
14324 else {
14325 ch = rb_io_getc(ARGF.current_file);
14326 }
14327 if (NIL_P(ch) && ARGF.next_p != -1) {
14328 argf_close(argf);
14329 ARGF.next_p = 1;
14330 goto retry;
14331 }
14332
14333 return ch;
14334}
14335
14336/*
14337 * call-seq:
14338 * ARGF.getbyte -> Integer or nil
14339 *
14340 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14341 * the end of the stream.
14342 *
14343 * For example:
14344 *
14345 * $ echo "foo" > file
14346 * $ ruby argf.rb file
14347 *
14348 * ARGF.getbyte #=> 102
14349 * ARGF.getbyte #=> 111
14350 * ARGF.getbyte #=> 111
14351 * ARGF.getbyte #=> 10
14352 * ARGF.getbyte #=> nil
14353 */
14354static VALUE
14355argf_getbyte(VALUE argf)
14356{
14357 VALUE ch;
14358
14359 retry:
14360 if (!next_argv()) return Qnil;
14361 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14362 ch = forward_current(rb_intern("getbyte"), 0, 0);
14363 }
14364 else {
14365 ch = rb_io_getbyte(ARGF.current_file);
14366 }
14367 if (NIL_P(ch) && ARGF.next_p != -1) {
14368 argf_close(argf);
14369 ARGF.next_p = 1;
14370 goto retry;
14371 }
14372
14373 return ch;
14374}
14375
14376/*
14377 * call-seq:
14378 * ARGF.readchar -> String or nil
14379 *
14380 * Reads the next character from ARGF and returns it as a String. Raises
14381 * an EOFError after the last character of the last file has been read.
14382 *
14383 * For example:
14384 *
14385 * $ echo "foo" > file
14386 * $ ruby argf.rb file
14387 *
14388 * ARGF.readchar #=> "f"
14389 * ARGF.readchar #=> "o"
14390 * ARGF.readchar #=> "o"
14391 * ARGF.readchar #=> "\n"
14392 * ARGF.readchar #=> end of file reached (EOFError)
14393 */
14394static VALUE
14395argf_readchar(VALUE argf)
14396{
14397 VALUE ch;
14398
14399 retry:
14400 if (!next_argv()) rb_eof_error();
14401 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14402 ch = forward_current(rb_intern("getc"), 0, 0);
14403 }
14404 else {
14405 ch = rb_io_getc(ARGF.current_file);
14406 }
14407 if (NIL_P(ch) && ARGF.next_p != -1) {
14408 argf_close(argf);
14409 ARGF.next_p = 1;
14410 goto retry;
14411 }
14412
14413 return ch;
14414}
14415
14416/*
14417 * call-seq:
14418 * ARGF.readbyte -> Integer
14419 *
14420 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14421 * an EOFError after the last byte of the last file has been read.
14422 *
14423 * For example:
14424 *
14425 * $ echo "foo" > file
14426 * $ ruby argf.rb file
14427 *
14428 * ARGF.readbyte #=> 102
14429 * ARGF.readbyte #=> 111
14430 * ARGF.readbyte #=> 111
14431 * ARGF.readbyte #=> 10
14432 * ARGF.readbyte #=> end of file reached (EOFError)
14433 */
14434static VALUE
14435argf_readbyte(VALUE argf)
14436{
14437 VALUE c;
14438
14439 NEXT_ARGF_FORWARD(0, 0);
14440 c = argf_getbyte(argf);
14441 if (NIL_P(c)) {
14442 rb_eof_error();
14443 }
14444 return c;
14445}
14446
14447#define FOREACH_ARGF() while (next_argv())
14448
14449static VALUE
14450argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14451{
14452 const VALUE current = ARGF.current_file;
14453 rb_yield_values2(argc, argv);
14454 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14456 }
14457 return Qnil;
14458}
14459
14460#define ARGF_block_call(mid, argc, argv, func, argf) \
14461 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14462 func, argf, rb_keyword_given_p())
14463
14464static void
14465argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14466{
14467 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14468 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14469}
14470
14471static VALUE
14472argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14473{
14474 if (!global_argf_p(argf)) {
14475 ARGF.last_lineno = ++ARGF.lineno;
14476 }
14477 return argf_block_call_i(i, argf, argc, argv, blockarg);
14478}
14479
14480static void
14481argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14482{
14483 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14484 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14485}
14486
14487/*
14488 * call-seq:
14489 * ARGF.each(sep=$/) {|line| block } -> ARGF
14490 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14491 * ARGF.each(...) -> an_enumerator
14492 *
14493 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14494 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14495 * ARGF.each_line(...) -> an_enumerator
14496 *
14497 * Returns an enumerator which iterates over each line (separated by _sep_,
14498 * which defaults to your platform's newline character) of each file in
14499 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14500 * block, otherwise an enumerator is returned.
14501 * The optional _limit_ argument is an Integer specifying the maximum
14502 * length of each line; longer lines will be split according to this limit.
14503 *
14504 * This method allows you to treat the files supplied on the command line as
14505 * a single file consisting of the concatenation of each named file. After
14506 * the last line of the first file has been returned, the first line of the
14507 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14508 * used to determine the filename of the current line and line number of the
14509 * whole input, respectively.
14510 *
14511 * For example, the following code prints out each line of each named file
14512 * prefixed with its line number, displaying the filename once per file:
14513 *
14514 * ARGF.each_line do |line|
14515 * puts ARGF.filename if ARGF.file.lineno == 1
14516 * puts "#{ARGF.file.lineno}: #{line}"
14517 * end
14518 *
14519 * While the following code prints only the first file's name at first, and
14520 * the contents with line number counted through all named files.
14521 *
14522 * ARGF.each_line do |line|
14523 * puts ARGF.filename if ARGF.lineno == 1
14524 * puts "#{ARGF.lineno}: #{line}"
14525 * end
14526 */
14527static VALUE
14528argf_each_line(int argc, VALUE *argv, VALUE argf)
14529{
14530 RETURN_ENUMERATOR(argf, argc, argv);
14531 FOREACH_ARGF() {
14532 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14533 }
14534 return argf;
14535}
14536
14537/*
14538 * call-seq:
14539 * ARGF.each_byte {|byte| block } -> ARGF
14540 * ARGF.each_byte -> an_enumerator
14541 *
14542 * Iterates over each byte of each file in +ARGV+.
14543 * A byte is returned as an Integer in the range 0..255.
14544 *
14545 * This method allows you to treat the files supplied on the command line as
14546 * a single file consisting of the concatenation of each named file. After
14547 * the last byte of the first file has been returned, the first byte of the
14548 * second file is returned. The ARGF.filename method can be used to
14549 * determine the filename of the current byte.
14550 *
14551 * If no block is given, an enumerator is returned instead.
14552 *
14553 * For example:
14554 *
14555 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14556 *
14557 */
14558static VALUE
14559argf_each_byte(VALUE argf)
14560{
14561 RETURN_ENUMERATOR(argf, 0, 0);
14562 FOREACH_ARGF() {
14563 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14564 }
14565 return argf;
14566}
14567
14568/*
14569 * call-seq:
14570 * ARGF.each_char {|char| block } -> ARGF
14571 * ARGF.each_char -> an_enumerator
14572 *
14573 * Iterates over each character of each file in ARGF.
14574 *
14575 * This method allows you to treat the files supplied on the command line as
14576 * a single file consisting of the concatenation of each named file. After
14577 * the last character of the first file has been returned, the first
14578 * character of the second file is returned. The ARGF.filename method can
14579 * be used to determine the name of the file in which the current character
14580 * appears.
14581 *
14582 * If no block is given, an enumerator is returned instead.
14583 */
14584static VALUE
14585argf_each_char(VALUE argf)
14586{
14587 RETURN_ENUMERATOR(argf, 0, 0);
14588 FOREACH_ARGF() {
14589 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14590 }
14591 return argf;
14592}
14593
14594/*
14595 * call-seq:
14596 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14597 * ARGF.each_codepoint -> an_enumerator
14598 *
14599 * Iterates over each codepoint of each file in ARGF.
14600 *
14601 * This method allows you to treat the files supplied on the command line as
14602 * a single file consisting of the concatenation of each named file. After
14603 * the last codepoint of the first file has been returned, the first
14604 * codepoint of the second file is returned. The ARGF.filename method can
14605 * be used to determine the name of the file in which the current codepoint
14606 * appears.
14607 *
14608 * If no block is given, an enumerator is returned instead.
14609 */
14610static VALUE
14611argf_each_codepoint(VALUE argf)
14612{
14613 RETURN_ENUMERATOR(argf, 0, 0);
14614 FOREACH_ARGF() {
14615 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14616 }
14617 return argf;
14618}
14619
14620/*
14621 * call-seq:
14622 * ARGF.filename -> String
14623 * ARGF.path -> String
14624 *
14625 * Returns the current filename. "-" is returned when the current file is
14626 * STDIN.
14627 *
14628 * For example:
14629 *
14630 * $ echo "foo" > foo
14631 * $ echo "bar" > bar
14632 * $ echo "glark" > glark
14633 *
14634 * $ ruby argf.rb foo bar glark
14635 *
14636 * ARGF.filename #=> "foo"
14637 * ARGF.read(5) #=> "foo\nb"
14638 * ARGF.filename #=> "bar"
14639 * ARGF.skip
14640 * ARGF.filename #=> "glark"
14641 */
14642static VALUE
14643argf_filename(VALUE argf)
14644{
14645 next_argv();
14646 return ARGF.filename;
14647}
14648
14649static VALUE
14650argf_filename_getter(ID id, VALUE *var)
14651{
14652 return argf_filename(*var);
14653}
14654
14655/*
14656 * call-seq:
14657 * ARGF.file -> IO or File object
14658 *
14659 * Returns the current file as an IO or File object.
14660 * <code>$stdin</code> is returned when the current file is STDIN.
14661 *
14662 * For example:
14663 *
14664 * $ echo "foo" > foo
14665 * $ echo "bar" > bar
14666 *
14667 * $ ruby argf.rb foo bar
14668 *
14669 * ARGF.file #=> #<File:foo>
14670 * ARGF.read(5) #=> "foo\nb"
14671 * ARGF.file #=> #<File:bar>
14672 */
14673static VALUE
14674argf_file(VALUE argf)
14675{
14676 next_argv();
14677 return ARGF.current_file;
14678}
14679
14680/*
14681 * call-seq:
14682 * ARGF.binmode -> ARGF
14683 *
14684 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14685 * be reset to non-binary mode. This option has the following effects:
14686 *
14687 * * Newline conversion is disabled.
14688 * * Encoding conversion is disabled.
14689 * * Content is treated as ASCII-8BIT.
14690 */
14691static VALUE
14692argf_binmode_m(VALUE argf)
14693{
14694 ARGF.binmode = 1;
14695 next_argv();
14696 ARGF_FORWARD(0, 0);
14697 rb_io_ascii8bit_binmode(ARGF.current_file);
14698 return argf;
14699}
14700
14701/*
14702 * call-seq:
14703 * ARGF.binmode? -> true or false
14704 *
14705 * Returns true if ARGF is being read in binary mode; false otherwise.
14706 * To enable binary mode use ARGF.binmode.
14707 *
14708 * For example:
14709 *
14710 * ARGF.binmode? #=> false
14711 * ARGF.binmode
14712 * ARGF.binmode? #=> true
14713 */
14714static VALUE
14715argf_binmode_p(VALUE argf)
14716{
14717 return RBOOL(ARGF.binmode);
14718}
14719
14720/*
14721 * call-seq:
14722 * ARGF.skip -> ARGF
14723 *
14724 * Sets the current file to the next file in ARGV. If there aren't any more
14725 * files it has no effect.
14726 *
14727 * For example:
14728 *
14729 * $ ruby argf.rb foo bar
14730 * ARGF.filename #=> "foo"
14731 * ARGF.skip
14732 * ARGF.filename #=> "bar"
14733 */
14734static VALUE
14735argf_skip(VALUE argf)
14736{
14737 if (ARGF.init_p && ARGF.next_p == 0) {
14738 argf_close(argf);
14739 ARGF.next_p = 1;
14740 }
14741 return argf;
14742}
14743
14744/*
14745 * call-seq:
14746 * ARGF.close -> ARGF
14747 *
14748 * Closes the current file and skips to the next file in ARGV. If there are
14749 * no more files to open, just closes the current file. STDIN will not be
14750 * closed.
14751 *
14752 * For example:
14753 *
14754 * $ ruby argf.rb foo bar
14755 *
14756 * ARGF.filename #=> "foo"
14757 * ARGF.close
14758 * ARGF.filename #=> "bar"
14759 * ARGF.close
14760 */
14761static VALUE
14762argf_close_m(VALUE argf)
14763{
14764 next_argv();
14765 argf_close(argf);
14766 if (ARGF.next_p != -1) {
14767 ARGF.next_p = 1;
14768 }
14769 ARGF.lineno = 0;
14770 return argf;
14771}
14772
14773/*
14774 * call-seq:
14775 * ARGF.closed? -> true or false
14776 *
14777 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14778 * ARGF.close to actually close the current file.
14779 */
14780static VALUE
14781argf_closed(VALUE argf)
14782{
14783 next_argv();
14784 ARGF_FORWARD(0, 0);
14785 return rb_io_closed_p(ARGF.current_file);
14786}
14787
14788/*
14789 * call-seq:
14790 * ARGF.to_s -> String
14791 *
14792 * Returns "ARGF".
14793 */
14794static VALUE
14795argf_to_s(VALUE argf)
14796{
14797 return rb_str_new2("ARGF");
14798}
14799
14800/*
14801 * call-seq:
14802 * ARGF.inplace_mode -> String
14803 *
14804 * Returns the file extension appended to the names of backup copies of
14805 * modified files under in-place edit mode. This value can be set using
14806 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14807 */
14808static VALUE
14809argf_inplace_mode_get(VALUE argf)
14810{
14811 if (!ARGF.inplace) return Qnil;
14812 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14813 return rb_str_dup(ARGF.inplace);
14814}
14815
14816static VALUE
14817opt_i_get(ID id, VALUE *var)
14818{
14819 return argf_inplace_mode_get(*var);
14820}
14821
14822/*
14823 * call-seq:
14824 * ARGF.inplace_mode = ext -> ARGF
14825 *
14826 * Sets the filename extension for in-place editing mode to the given String.
14827 * The backup copy of each file being edited has this value appended to its
14828 * filename.
14829 *
14830 * For example:
14831 *
14832 * $ ruby argf.rb file.txt
14833 *
14834 * ARGF.inplace_mode = '.bak'
14835 * ARGF.each_line do |line|
14836 * print line.sub("foo","bar")
14837 * end
14838 *
14839 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14840 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14841 * "bar".
14842 */
14843static VALUE
14844argf_inplace_mode_set(VALUE argf, VALUE val)
14845{
14846 if (!RTEST(val)) {
14847 ARGF.inplace = Qfalse;
14848 }
14849 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14850 ARGF.inplace = Qnil;
14851 }
14852 else {
14853 ARGF_SET(inplace, rb_str_new_frozen(val));
14854 }
14855 return argf;
14856}
14857
14858static void
14859opt_i_set(VALUE val, ID id, VALUE *var)
14860{
14861 argf_inplace_mode_set(*var, val);
14862}
14863
14864void
14865ruby_set_inplace_mode(const char *suffix)
14866{
14867 ARGF_SET(inplace, !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix)));
14868}
14869
14870/*
14871 * call-seq:
14872 * ARGF.argv -> ARGV
14873 *
14874 * Returns the +ARGV+ array, which contains the arguments passed to your
14875 * script, one per element.
14876 *
14877 * For example:
14878 *
14879 * $ ruby argf.rb -v glark.txt
14880 *
14881 * ARGF.argv #=> ["-v", "glark.txt"]
14882 *
14883 */
14884static VALUE
14885argf_argv(VALUE argf)
14886{
14887 return ARGF.argv;
14888}
14889
14890static VALUE
14891argf_argv_getter(ID id, VALUE *var)
14892{
14893 return argf_argv(*var);
14894}
14895
14896VALUE
14898{
14899 return ARGF.argv;
14900}
14901
14902/*
14903 * call-seq:
14904 * ARGF.to_write_io -> io
14905 *
14906 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14907 * enabled.
14908 */
14909static VALUE
14910argf_write_io(VALUE argf)
14911{
14912 if (!RTEST(ARGF.current_file)) {
14913 rb_raise(rb_eIOError, "not opened for writing");
14914 }
14915 return GetWriteIO(ARGF.current_file);
14916}
14917
14918/*
14919 * call-seq:
14920 * ARGF.write(*objects) -> integer
14921 *
14922 * Writes each of the given +objects+ if inplace mode.
14923 */
14924static VALUE
14925argf_write(int argc, VALUE *argv, VALUE argf)
14926{
14927 return rb_io_writev(argf_write_io(argf), argc, argv);
14928}
14929
14930void
14931rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14932{
14933 rb_readwrite_syserr_fail(waiting, errno, mesg);
14934}
14935
14936void
14937rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14938{
14939 VALUE arg, c = Qnil;
14940 arg = mesg ? rb_str_new2(mesg) : Qnil;
14941 switch (waiting) {
14942 case RB_IO_WAIT_WRITABLE:
14943 switch (n) {
14944 case EAGAIN:
14945 c = rb_eEAGAINWaitWritable;
14946 break;
14947#if EAGAIN != EWOULDBLOCK
14948 case EWOULDBLOCK:
14949 c = rb_eEWOULDBLOCKWaitWritable;
14950 break;
14951#endif
14952 case EINPROGRESS:
14953 c = rb_eEINPROGRESSWaitWritable;
14954 break;
14955 default:
14957 }
14958 break;
14959 case RB_IO_WAIT_READABLE:
14960 switch (n) {
14961 case EAGAIN:
14962 c = rb_eEAGAINWaitReadable;
14963 break;
14964#if EAGAIN != EWOULDBLOCK
14965 case EWOULDBLOCK:
14966 c = rb_eEWOULDBLOCKWaitReadable;
14967 break;
14968#endif
14969 case EINPROGRESS:
14970 c = rb_eEINPROGRESSWaitReadable;
14971 break;
14972 default:
14974 }
14975 break;
14976 default:
14977 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14978 }
14980}
14981
14982static VALUE
14983get_LAST_READ_LINE(ID _x, VALUE *_y)
14984{
14985 return rb_lastline_get();
14986}
14987
14988static void
14989set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14990{
14991 rb_lastline_set(val);
14992}
14993
14994/*
14995 * Document-class: IOError
14996 *
14997 * Raised when an IO operation fails.
14998 *
14999 * File.open("/etc/hosts") {|f| f << "example"}
15000 * #=> IOError: not opened for writing
15001 *
15002 * File.open("/etc/hosts") {|f| f.close; f.read }
15003 * #=> IOError: closed stream
15004 *
15005 * Note that some IO failures raise <code>SystemCallError</code>s
15006 * and these are not subclasses of IOError:
15007 *
15008 * File.open("does/not/exist")
15009 * #=> Errno::ENOENT: No such file or directory - does/not/exist
15010 */
15011
15012/*
15013 * Document-class: EOFError
15014 *
15015 * Raised by some IO operations when reaching the end of file. Many IO
15016 * methods exist in two forms,
15017 *
15018 * one that returns +nil+ when the end of file is reached, the other
15019 * raises EOFError.
15020 *
15021 * EOFError is a subclass of IOError.
15022 *
15023 * file = File.open("/etc/hosts")
15024 * file.read
15025 * file.gets #=> nil
15026 * file.readline #=> EOFError: end of file reached
15027 * file.close
15028 */
15029
15030/*
15031 * Document-class: ARGF
15032 *
15033 * == \ARGF and +ARGV+
15034 *
15035 * The \ARGF object works with the array at global variable +ARGV+
15036 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
15037 *
15038 * - **ARGV** may be thought of as the <b>argument vector</b> array.
15039 *
15040 * Initially, it contains the command-line arguments and options
15041 * that are passed to the Ruby program;
15042 * the program can modify that array as it likes.
15043 *
15044 * - **ARGF** may be thought of as the <b>argument files</b> object.
15045 *
15046 * It can access file streams and/or the <tt>$stdin</tt> stream,
15047 * based on what it finds in +ARGV+.
15048 * This provides a convenient way for the command line
15049 * to specify streams for a Ruby program to read.
15050 *
15051 * == Reading
15052 *
15053 * \ARGF may read from _source_ streams,
15054 * which at any particular time are determined by the content of +ARGV+.
15055 *
15056 * === Simplest Case
15057 *
15058 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
15059 * the source is <tt>$stdin</tt>:
15060 *
15061 * - \File +t.rb+:
15062 *
15063 * p ['ARGV', ARGV]
15064 * p ['ARGF.read', ARGF.read]
15065 *
15066 * - Commands and outputs
15067 * (see below for the content of files +foo.txt+ and +bar.txt+):
15068 *
15069 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
15070 * ["ARGV", []]
15071 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15072 *
15073 * $ cat foo.txt bar.txt | ruby t.rb
15074 * ["ARGV", []]
15075 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
15076 *
15077 * === About the Examples
15078 *
15079 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
15080 *
15081 * $ cat foo.txt
15082 * Foo 0
15083 * Foo 1
15084 * $ cat bar.txt
15085 * Bar 0
15086 * Bar 1
15087 * Bar 2
15088 * Bar 3
15089 *
15090 * === Sources in +ARGV+
15091 *
15092 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
15093 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
15094 * the sources are found in +ARGV+.
15095 *
15096 * \ARGF assumes that each element in array +ARGV+ is a potential source,
15097 * and is one of:
15098 *
15099 * - The string path to a file that may be opened as a stream.
15100 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
15101 *
15102 * Each element that is _not_ one of these
15103 * should be removed from +ARGV+ before \ARGF accesses that source.
15104 *
15105 * In the following example:
15106 *
15107 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
15108 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
15109 *
15110 * Example:
15111 *
15112 * - \File +t.rb+:
15113 *
15114 * # Print arguments (and options, if any) found on command line.
15115 * p ['ARGV', ARGV]
15116 *
15117 * - Command and output:
15118 *
15119 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
15120 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
15121 *
15122 * \ARGF's stream access considers the elements of +ARGV+, left to right:
15123 *
15124 * - \File +t.rb+:
15125 *
15126 * p "ARGV: #{ARGV}"
15127 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
15128 *
15129 * - Command and output:
15130 *
15131 * $ ruby t.rb foo.txt bar.txt
15132 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15133 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15134 *
15135 * Because the value at +ARGV+ is an ordinary array,
15136 * you can manipulate it to control which sources \ARGF considers:
15137 *
15138 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
15139 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
15140 *
15141 * Each element in +ARGV+ is removed when its corresponding source is accessed;
15142 * when all sources have been accessed, the array is empty:
15143 *
15144 * - \File +t.rb+:
15145 *
15146 * until ARGV.empty? && ARGF.eof?
15147 * p "ARGV: #{ARGV}"
15148 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
15149 * end
15150 *
15151 * - Command and output:
15152 *
15153 * $ ruby t.rb foo.txt bar.txt
15154 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15155 * "Line: Foo 0\n"
15156 * "ARGV: [\"bar.txt\"]"
15157 * "Line: Foo 1\n"
15158 * "ARGV: [\"bar.txt\"]"
15159 * "Line: Bar 0\n"
15160 * "ARGV: []"
15161 * "Line: Bar 1\n"
15162 * "ARGV: []"
15163 * "Line: Bar 2\n"
15164 * "ARGV: []"
15165 * "Line: Bar 3\n"
15166 *
15167 * ==== Filepaths in +ARGV+
15168 *
15169 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
15170 *
15171 * This program prints what it reads from files at the paths specified
15172 * on the command line:
15173 *
15174 * - \File +t.rb+:
15175 *
15176 * p ['ARGV', ARGV]
15177 * # Read and print all content from the specified sources.
15178 * p ['ARGF.read', ARGF.read]
15179 *
15180 * - Command and output:
15181 *
15182 * $ ruby t.rb foo.txt bar.txt
15183 * ["ARGV", [foo.txt, bar.txt]
15184 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
15185 *
15186 * ==== Specifying <tt>$stdin</tt> in +ARGV+
15187 *
15188 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
15189 *
15190 * - \File +t.rb+:
15191 *
15192 * p ['ARGV', ARGV]
15193 * p ['ARGF.read', ARGF.read]
15194 *
15195 * - Command and output:
15196 *
15197 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
15198 * ["ARGV", ["-"]]
15199 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15200 *
15201 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored.
15202 *
15203 * - Command and output:
15204 *
15205 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
15206 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15207 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15208 *
15209 * ==== Mixtures and Repetitions in +ARGV+
15210 *
15211 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
15212 * and character <tt>'-'</tt>, including repetitions.
15213 *
15214 * ==== Modifications to +ARGV+
15215 *
15216 * The running Ruby program may make any modifications to the +ARGV+ array;
15217 * the current value of +ARGV+ affects \ARGF reading.
15218 *
15219 * ==== Empty +ARGV+
15220 *
15221 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15222 * or raises an exception, depending on the specific method.
15223 *
15224 * === More Read Methods
15225 *
15226 * As seen above, method ARGF#read reads the content of all sources
15227 * into a single string.
15228 * Other \ARGF methods provide other ways to access that content;
15229 * these include:
15230 *
15231 * - Byte access: #each_byte, #getbyte, #readbyte.
15232 * - Character access: #each_char, #getc, #readchar.
15233 * - Codepoint access: #each_codepoint.
15234 * - Line access: #each_line, #gets, #readline, #readlines.
15235 * - Source access: #read, #read_nonblock, #readpartial.
15236 *
15237 * === About \Enumerable
15238 *
15239 * \ARGF includes module Enumerable.
15240 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15241 *
15242 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15243 * _not_ from +ARGV+;
15244 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15245 * not an array of the strings from +ARGV+:
15246 *
15247 * - \File +t.rb+:
15248 *
15249 * p ['ARGV', ARGV]
15250 * p ['ARGF.entries', ARGF.entries]
15251 *
15252 * - Command and output:
15253 *
15254 * $ ruby t.rb foo.txt bar.txt
15255 * ["ARGV", ["foo.txt", "bar.txt"]]
15256 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15257 *
15258 * == Writing
15259 *
15260 * If <i>inplace mode</i> is in effect,
15261 * \ARGF may write to target streams,
15262 * which at any particular time are determined by the content of ARGV.
15263 *
15264 * Methods about inplace mode:
15265 *
15266 * - #inplace_mode
15267 * - #inplace_mode=
15268 * - #to_write_io
15269 *
15270 * Methods for writing:
15271 *
15272 * - #print
15273 * - #printf
15274 * - #putc
15275 * - #puts
15276 * - #write
15277 *
15278 */
15279
15280/*
15281 * An instance of class \IO (commonly called a _stream_)
15282 * represents an input/output stream in the underlying operating system.
15283 * Class \IO is the basis for input and output in Ruby.
15284 *
15285 * Class File is the only class in the Ruby core that is a subclass of \IO.
15286 * Some classes in the Ruby standard library are also subclasses of \IO;
15287 * these include TCPSocket and UDPSocket.
15288 *
15289 * The global constant ARGF (also accessible as <tt>$<</tt>)
15290 * provides an IO-like stream that allows access to all file paths
15291 * found in ARGV (or found in STDIN if ARGV is empty).
15292 * ARGF is not itself a subclass of \IO.
15293 *
15294 * Class StringIO provides an IO-like stream that handles a String.
15295 * StringIO is not itself a subclass of \IO.
15296 *
15297 * Important objects based on \IO include:
15298 *
15299 * - $stdin.
15300 * - $stdout.
15301 * - $stderr.
15302 * - Instances of class File.
15303 *
15304 * An instance of \IO may be created using:
15305 *
15306 * - IO.new: returns a new \IO object for the given integer file descriptor.
15307 * - IO.open: passes a new \IO object to the given block.
15308 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15309 * of a newly-launched subprocess.
15310 * - Kernel#open: Returns a new \IO object connected to a given source:
15311 * stream, file, or subprocess.
15312 *
15313 * Like a File stream, an \IO stream has:
15314 *
15315 * - A read/write mode, which may be read-only, write-only, or read/write;
15316 * see {Read/Write Mode}[rdoc-ref:File@ReadWrite+Mode].
15317 * - A data mode, which may be text-only or binary;
15318 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15319 * - Internal and external encodings;
15320 * see {Encodings}[rdoc-ref:File@Encodings].
15321 *
15322 * And like other \IO streams, it has:
15323 *
15324 * - A position, which determines where in the stream the next
15325 * read or write is to occur;
15326 * see {Position}[rdoc-ref:IO@Position].
15327 * - A line number, which is a special, line-oriented, "position"
15328 * (different from the position mentioned above);
15329 * see {Line Number}[rdoc-ref:IO@Line+Number].
15330 *
15331 * == Extension <tt>io/console</tt>
15332 *
15333 * Extension <tt>io/console</tt> provides numerous methods
15334 * for interacting with the console;
15335 * requiring it adds numerous methods to class \IO.
15336 *
15337 * == Example Files
15338 *
15339 * Many examples here use these variables:
15340 *
15341 * :include: doc/examples/files.rdoc
15342 *
15343 * == Open Options
15344 *
15345 * A number of \IO methods accept optional keyword arguments
15346 * that determine how a new stream is to be opened:
15347 *
15348 * - +:mode+: Stream mode.
15349 * - +:flags+: Integer file open flags;
15350 * If +mode+ is also given, the two are bitwise-ORed.
15351 * - +:external_encoding+: External encoding for the stream.
15352 * - +:internal_encoding+: Internal encoding for the stream.
15353 * <tt>'-'</tt> is a synonym for the default internal encoding.
15354 * If the value is +nil+ no conversion occurs.
15355 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15356 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15357 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15358 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15359 * when the stream closes; otherwise it remains open.
15360 * - +:path+: If a string value is provided, it is used in #inspect and is available as
15361 * #path method.
15362 *
15363 * Also available are the options offered in String#encode,
15364 * which may control conversion between external and internal encoding.
15365 *
15366 * == Basic \IO
15367 *
15368 * You can perform basic stream \IO with these methods,
15369 * which typically operate on multi-byte strings:
15370 *
15371 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15372 * - IO#write: Writes zero or more strings to the stream;
15373 * each given object that is not already a string is converted via +to_s+.
15374 *
15375 * === Position
15376 *
15377 * An \IO stream has a nonnegative integer _position_,
15378 * which is the byte offset at which the next read or write is to occur.
15379 * A new stream has position zero (and line number zero);
15380 * method +rewind+ resets the position (and line number) to zero.
15381 *
15382 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15383 * Encoding::Converter instances used for that \IO.
15384 *
15385 * The relevant methods:
15386 *
15387 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15388 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15389 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15390 * relative to a given position +whence+
15391 * (indicating the beginning, end, or current position).
15392 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15393 *
15394 * === Open and Closed Streams
15395 *
15396 * A new \IO stream may be open for reading, open for writing, or both.
15397 *
15398 * A stream is automatically closed when claimed by the garbage collector.
15399 *
15400 * Attempted reading or writing on a closed stream raises an exception.
15401 *
15402 * The relevant methods:
15403 *
15404 * - IO#close: Closes the stream for both reading and writing.
15405 * - IO#close_read: Closes the stream for reading.
15406 * - IO#close_write: Closes the stream for writing.
15407 * - IO#closed?: Returns whether the stream is closed.
15408 *
15409 * === End-of-Stream
15410 *
15411 * You can query whether a stream is positioned at its end:
15412 *
15413 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15414 *
15415 * You can reposition to end-of-stream by using method IO#seek:
15416 *
15417 * f = File.new('t.txt')
15418 * f.eof? # => false
15419 * f.seek(0, :END)
15420 * f.eof? # => true
15421 * f.close
15422 *
15423 * Or by reading all stream content (which is slower than using IO#seek):
15424 *
15425 * f.rewind
15426 * f.eof? # => false
15427 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15428 * f.eof? # => true
15429 *
15430 * == Line \IO
15431 *
15432 * Class \IO supports line-oriented
15433 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15434 *
15435 * === Line Input
15436 *
15437 * Class \IO supports line-oriented input for
15438 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input].
15439 *
15440 * ==== Line Input Options
15441 *
15442 * Optional keyword argument +chomp+ (default: +false+)
15443 * specifies whether line separators are to be excluded from the result of a read.
15444 *
15445 * ==== \File Line Input
15446 *
15447 * You can read lines from a file using these methods:
15448 *
15449 * - IO.foreach: Reads each line and passes it to the given block.
15450 * - IO.readlines: Reads and returns all lines in an array.
15451 *
15452 * For each of these methods:
15453 *
15454 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15455 * - Line parsing depends on the effective <i>line separator</i>;
15456 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15457 * - The length of each returned line depends on the effective <i>line limit</i>;
15458 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15459 *
15460 * ==== Stream Line Input
15461 *
15462 * You can read lines from an \IO stream using these methods:
15463 *
15464 * - IO#each_line: Reads each remaining line, passing it to the given block.
15465 * - IO#gets: Returns the next line.
15466 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15467 * - IO#readlines: Returns all remaining lines in an array.
15468 *
15469 * For each of these methods:
15470 *
15471 * - Reading may begin mid-line,
15472 * depending on the stream's _position_;
15473 * see {Position}[rdoc-ref:IO@Position].
15474 * - Line parsing depends on the effective <i>line separator</i>;
15475 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15476 * - The length of each returned line depends on the effective <i>line limit</i>;
15477 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15478 *
15479 * ===== Line Separator
15480 *
15481 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15482 * the string that determines what is considered a line;
15483 * it is sometimes called the <i>input record separator</i>.
15484 *
15485 * The default line separator is taken from global variable <tt>$/</tt>,
15486 * whose initial value is <tt>"\n"</tt>.
15487 *
15488 * Generally, the line to be read next is all data
15489 * from the current {position}[rdoc-ref:IO@Position]
15490 * to the next line separator
15491 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15492 *
15493 * f = File.new('t.txt')
15494 * # Method gets with no sep argument returns the next line, according to $/.
15495 * f.gets # => "First line\n"
15496 * f.gets # => "Second line\n"
15497 * f.gets # => "\n"
15498 * f.gets # => "Fourth line\n"
15499 * f.gets # => "Fifth line\n"
15500 * f.close
15501 *
15502 * You can use a different line separator by passing argument +sep+:
15503 *
15504 * f = File.new('t.txt')
15505 * f.gets('l') # => "First l"
15506 * f.gets('li') # => "ine\nSecond li"
15507 * f.gets('lin') # => "ne\n\nFourth lin"
15508 * f.gets # => "e\n"
15509 * f.close
15510 *
15511 * Or by setting global variable <tt>$/</tt>:
15512 *
15513 * f = File.new('t.txt')
15514 * $/ = 'l'
15515 * f.gets # => "First l"
15516 * f.gets # => "ine\nSecond l"
15517 * f.gets # => "ine\n\nFourth l"
15518 * f.close
15519 *
15520 * ===== Special Line Separator Values
15521 *
15522 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15523 * accepts two special values for parameter +sep+:
15524 *
15525 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15526 *
15527 * f = File.new('t.txt')
15528 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15529 * f.close
15530 *
15531 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15532 * (paragraphs being separated by two consecutive line separators):
15533 *
15534 * f = File.new('t.txt')
15535 * f.gets('') # => "First line\nSecond line\n\n"
15536 * f.gets('') # => "Fourth line\nFifth line\n"
15537 * f.close
15538 *
15539 * ===== Line Limit
15540 *
15541 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15542 * uses an integer <i>line limit</i>,
15543 * which restricts the number of bytes that may be returned.
15544 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15545 * than the limit).
15546 *
15547 * The default limit value is <tt>-1</tt>;
15548 * any negative limit value means that there is no limit.
15549 *
15550 * If there is no limit, the line is determined only by +sep+.
15551 *
15552 * # Text with 1-byte characters.
15553 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15554 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15555 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15556 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15557 * # No more than one line.
15558 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15559 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15560 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15561 *
15562 * # Text with 3-byte characters, which will not be split.
15563 * File.read('t.ja') # => "こんにちは"
15564 * File.open('t.ja') {|f| f.gets(1).size } # => 1
15565 * File.open('t.ja') {|f| f.gets(2).size } # => 1
15566 * File.open('t.ja') {|f| f.gets(3).size } # => 1
15567 * File.open('t.ja') {|f| f.gets(4).size } # => 2
15568 * File.open('t.ja') {|f| f.gets(5).size } # => 2
15569 *
15570 * ===== Line Separator and Line Limit
15571 *
15572 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15573 *
15574 * - Returns the next line as determined by line separator +sep+.
15575 * - But returns no more bytes than are allowed by the limit +limit+.
15576 *
15577 * Example:
15578 *
15579 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15580 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15581 *
15582 * ===== Line Number
15583 *
15584 * A readable \IO stream has a non-negative integer <i>line number</i>:
15585 *
15586 * - IO#lineno: Returns the line number.
15587 * - IO#lineno=: Resets and returns the line number.
15588 *
15589 * Unless modified by a call to method IO#lineno=,
15590 * the line number is the number of lines read
15591 * by certain line-oriented methods,
15592 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15593 *
15594 * - IO.foreach: Increments the line number on each call to the block.
15595 * - IO#each_line: Increments the line number on each call to the block.
15596 * - IO#gets: Increments the line number.
15597 * - IO#readline: Increments the line number.
15598 * - IO#readlines: Increments the line number for each line read.
15599 *
15600 * A new stream is initially has line number zero (and position zero);
15601 * method +rewind+ resets the line number (and position) to zero:
15602 *
15603 * f = File.new('t.txt')
15604 * f.lineno # => 0
15605 * f.gets # => "First line\n"
15606 * f.lineno # => 1
15607 * f.rewind
15608 * f.lineno # => 0
15609 * f.close
15610 *
15611 * Reading lines from a stream usually changes its line number:
15612 *
15613 * f = File.new('t.txt', 'r')
15614 * f.lineno # => 0
15615 * f.readline # => "This is line one.\n"
15616 * f.lineno # => 1
15617 * f.readline # => "This is the second line.\n"
15618 * f.lineno # => 2
15619 * f.readline # => "Here's the third line.\n"
15620 * f.lineno # => 3
15621 * f.eof? # => true
15622 * f.close
15623 *
15624 * Iterating over lines in a stream usually changes its line number:
15625 *
15626 * File.open('t.txt') do |f|
15627 * f.each_line do |line|
15628 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15629 * end
15630 * end
15631 *
15632 * Output:
15633 *
15634 * "position=11 eof?=false lineno=1"
15635 * "position=23 eof?=false lineno=2"
15636 * "position=24 eof?=false lineno=3"
15637 * "position=36 eof?=false lineno=4"
15638 * "position=47 eof?=true lineno=5"
15639 *
15640 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15641 * the line number does not affect where the next read or write will occur:
15642 *
15643 * f = File.new('t.txt')
15644 * f.lineno = 1000
15645 * f.lineno # => 1000
15646 * f.gets # => "First line\n"
15647 * f.lineno # => 1001
15648 * f.close
15649 *
15650 * Associated with the line number is the global variable <tt>$.</tt>:
15651 *
15652 * - When a stream is opened, <tt>$.</tt> is not set;
15653 * its value is left over from previous activity in the process:
15654 *
15655 * $. = 41
15656 * f = File.new('t.txt')
15657 * $. = 41
15658 * # => 41
15659 * f.close
15660 *
15661 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15662 *
15663 * f0 = File.new('t.txt')
15664 * f1 = File.new('t.dat')
15665 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15666 * $. # => 5
15667 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15668 * $. # => 1
15669 * f0.close
15670 * f1.close
15671 *
15672 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15673 *
15674 * f = File.new('t.txt')
15675 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15676 * $. # => 5
15677 * f.rewind
15678 * f.seek(0, :SET)
15679 * $. # => 5
15680 * f.close
15681 *
15682 * === Line Output
15683 *
15684 * You can write to an \IO stream line-by-line using this method:
15685 *
15686 * - IO#puts: Writes objects to the stream.
15687 *
15688 * == Character \IO
15689 *
15690 * You can process an \IO stream character-by-character using these methods:
15691 *
15692 * - IO#getc: Reads and returns the next character from the stream.
15693 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15694 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15695 * - IO#putc: Writes a character to the stream.
15696 * - IO#each_char: Reads each remaining character in the stream,
15697 * passing the character to the given block.
15698 *
15699 * == Byte \IO
15700 *
15701 * You can process an \IO stream byte-by-byte using these methods:
15702 *
15703 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15704 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15705 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15706 * - IO#each_byte: Reads each remaining byte in the stream,
15707 * passing the byte to the given block.
15708 *
15709 * == Codepoint \IO
15710 *
15711 * You can process an \IO stream codepoint-by-codepoint:
15712 *
15713 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15714 *
15715 * == What's Here
15716 *
15717 * First, what's elsewhere. Class \IO:
15718 *
15719 * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
15720 * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
15721 * which provides dozens of additional methods.
15722 *
15723 * Here, class \IO provides methods that are useful for:
15724 *
15725 * - {Creating}[rdoc-ref:IO@Creating]
15726 * - {Reading}[rdoc-ref:IO@Reading]
15727 * - {Writing}[rdoc-ref:IO@Writing]
15728 * - {Positioning}[rdoc-ref:IO@Positioning]
15729 * - {Iterating}[rdoc-ref:IO@Iterating]
15730 * - {Settings}[rdoc-ref:IO@Settings]
15731 * - {Querying}[rdoc-ref:IO@Querying]
15732 * - {Buffering}[rdoc-ref:IO@Buffering]
15733 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15734 * - {Other}[rdoc-ref:IO@Other]
15735 *
15736 * === Creating
15737 *
15738 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15739 * integer file descriptor.
15740 * - ::open: Creates a new \IO object.
15741 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15742 * - ::popen: Creates an \IO object to interact with a subprocess.
15743 * - ::select: Selects which given \IO instances are ready for reading,
15744 * writing, or have pending exceptions.
15745 *
15746 * === Reading
15747 *
15748 * - ::binread: Returns a binary string with all or a subset of bytes
15749 * from the given file.
15750 * - ::read: Returns a string with all or a subset of bytes from the given file.
15751 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15752 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15753 * - #getc: Returns the next character read from +self+ as a string.
15754 * - #gets: Returns the line read from +self+.
15755 * - #pread: Returns all or the next _n_ bytes read from +self+,
15756 * not updating the receiver's offset.
15757 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15758 * for a given _n_.
15759 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15760 * in non-block mode.
15761 * - #readbyte: Returns the next byte read from +self+;
15762 * same as #getbyte, but raises an exception on end-of-stream.
15763 * - #readchar: Returns the next character read from +self+;
15764 * same as #getc, but raises an exception on end-of-stream.
15765 * - #readline: Returns the next line read from +self+;
15766 * same as #getline, but raises an exception of end-of-stream.
15767 * - #readlines: Returns an array of all lines read read from +self+.
15768 * - #readpartial: Returns up to the given number of bytes from +self+.
15769 *
15770 * === Writing
15771 *
15772 * - ::binwrite: Writes the given string to the file at the given filepath,
15773 * in binary mode.
15774 * - ::write: Writes the given string to +self+.
15775 * - #<<: Appends the given string to +self+.
15776 * - #print: Prints last read line or given objects to +self+.
15777 * - #printf: Writes to +self+ based on the given format string and objects.
15778 * - #putc: Writes a character to +self+.
15779 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15780 * - #pwrite: Writes the given string at the given offset,
15781 * not updating the receiver's offset.
15782 * - #write: Writes one or more given strings to +self+.
15783 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15784 *
15785 * === Positioning
15786 *
15787 * - #lineno: Returns the current line number in +self+.
15788 * - #lineno=: Sets the line number is +self+.
15789 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15790 * - #pos=: Sets the byte offset in +self+.
15791 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15792 * - #rewind: Positions +self+ to the beginning of input.
15793 * - #seek: Sets the offset for +self+ relative to given position.
15794 *
15795 * === Iterating
15796 *
15797 * - ::foreach: Yields each line of given file to the block.
15798 * - #each (aliased as #each_line): Calls the given block
15799 * with each successive line in +self+.
15800 * - #each_byte: Calls the given block with each successive byte in +self+
15801 * as an integer.
15802 * - #each_char: Calls the given block with each successive character in +self+
15803 * as a string.
15804 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15805 * as an integer.
15806 *
15807 * === Settings
15808 *
15809 * - #autoclose=: Sets whether +self+ auto-closes.
15810 * - #binmode: Sets +self+ to binary mode.
15811 * - #close: Closes +self+.
15812 * - #close_on_exec=: Sets the close-on-exec flag.
15813 * - #close_read: Closes +self+ for reading.
15814 * - #close_write: Closes +self+ for writing.
15815 * - #set_encoding: Sets the encoding for +self+.
15816 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15817 * Unicode byte-order-mark.
15818 * - #sync=: Sets the sync-mode to the given value.
15819 *
15820 * === Querying
15821 *
15822 * - #autoclose?: Returns whether +self+ auto-closes.
15823 * - #binmode?: Returns whether +self+ is in binary mode.
15824 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15825 * - #closed?: Returns whether +self+ is closed.
15826 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15827 * - #external_encoding: Returns the external encoding object for +self+.
15828 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15829 * - #internal_encoding: Returns the internal encoding object for +self+.
15830 * - #pid: Returns the process ID of a child process associated with +self+,
15831 * if +self+ was created by ::popen.
15832 * - #stat: Returns the File::Stat object containing status information for +self+.
15833 * - #sync: Returns whether +self+ is in sync-mode.
15834 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15835 *
15836 * === Buffering
15837 *
15838 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15839 * - #flush: Flushes any buffered data within +self+ to the underlying
15840 * operating system.
15841 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15842 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15843 * - #ungetc: Prepends buffer for +self+ with given string.
15844 *
15845 * === Low-Level Access
15846 *
15847 * - ::sysopen: Opens the file given by its path,
15848 * returning the integer file descriptor.
15849 * - #advise: Announces the intention to access data from +self+ in a specific way.
15850 * - #fcntl: Passes a low-level command to the file specified
15851 * by the given file descriptor.
15852 * - #ioctl: Passes a low-level command to the device specified
15853 * by the given file descriptor.
15854 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15855 * - #sysseek: Sets the offset for +self+.
15856 * - #syswrite: Writes the given string to +self+ using a low-level write.
15857 *
15858 * === Other
15859 *
15860 * - ::copy_stream: Copies data from a source to a destination,
15861 * each of which is a filepath or an \IO-like object.
15862 * - ::try_convert: Returns a new \IO object resulting from converting
15863 * the given object.
15864 * - #inspect: Returns the string representation of +self+.
15865 *
15866 */
15867
15868void
15869Init_IO(void)
15870{
15871 VALUE rb_cARGF;
15872#ifdef __CYGWIN__
15873#include <sys/cygwin.h>
15874 static struct __cygwin_perfile pf[] =
15875 {
15876 {"", O_RDONLY | O_BINARY},
15877 {"", O_WRONLY | O_BINARY},
15878 {"", O_RDWR | O_BINARY},
15879 {"", O_APPEND | O_BINARY},
15880 {NULL, 0}
15881 };
15882 cygwin_internal(CW_PERFILE, pf);
15883#endif
15884
15885 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
15886 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
15887
15888 id_write = rb_intern_const("write");
15889 id_read = rb_intern_const("read");
15890 id_flush = rb_intern_const("flush");
15891 id_readpartial = rb_intern_const("readpartial");
15892 id_set_encoding = rb_intern_const("set_encoding");
15893 id_fileno = rb_intern_const("fileno");
15894
15895 rb_define_global_function("syscall", rb_f_syscall, -1);
15896
15897 rb_define_global_function("open", rb_f_open, -1);
15898 rb_define_global_function("printf", rb_f_printf, -1);
15899 rb_define_global_function("print", rb_f_print, -1);
15900 rb_define_global_function("putc", rb_f_putc, 1);
15901 rb_define_global_function("puts", rb_f_puts, -1);
15902 rb_define_global_function("gets", rb_f_gets, -1);
15903 rb_define_global_function("readline", rb_f_readline, -1);
15904 rb_define_global_function("select", rb_f_select, -1);
15905
15906 rb_define_global_function("readlines", rb_f_readlines, -1);
15907
15908 rb_define_global_function("`", rb_f_backquote, 1);
15909
15910 rb_define_global_function("p", rb_f_p, -1);
15911 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15912
15913 rb_cIO = rb_define_class("IO", rb_cObject);
15915
15916 /* Can be raised by IO operations when IO#timeout= is set. */
15917 rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
15918
15919 /* Readable event mask for IO#wait. */
15920 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15921 /* Writable event mask for IO#wait. */
15922 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15923 /* Priority event mask for IO#wait. */
15924 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15925
15926 /* exception to wait for reading. see IO.select. */
15927 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
15928 /* exception to wait for writing. see IO.select. */
15929 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
15930 /* exception to wait for reading by EAGAIN. see IO.select. */
15931 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15932 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15933 /* exception to wait for writing by EAGAIN. see IO.select. */
15934 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15935 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15936#if EAGAIN == EWOULDBLOCK
15937 /* same as IO::EAGAINWaitReadable */
15938 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15939 /* same as IO::EAGAINWaitWritable */
15940 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15941#else
15942 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15943 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15944 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15945 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15946 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15947 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15948#endif
15949 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15950 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15951 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15952 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15953 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15954 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15955
15956#if 0
15957 /* This is necessary only for forcing rdoc handle File::open */
15958 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15959#endif
15960
15961 rb_define_alloc_func(rb_cIO, io_alloc);
15962 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15963 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15964 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15965 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15966 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15967 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15968 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15969 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15970 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15971 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15972 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15973 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15974 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15975 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15976 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15977
15978 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15979
15981 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
15982
15983 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15984 rb_vm_register_global_object(rb_default_rs);
15985 rb_rs = rb_default_rs;
15987 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15988 rb_gvar_ractor_local("$/"); // not local but ractor safe
15989 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15990 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15991 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
15992
15993 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15994 rb_gvar_ractor_local("$_");
15995 rb_gvar_box_dynamic("$_");
15996
15997 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15998 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15999
16000 rb_define_method(rb_cIO, "print", rb_io_print, -1);
16001 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
16002 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
16003 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
16004
16005 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
16006 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
16007 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
16008 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
16009 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
16010
16011 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
16012 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
16013
16014 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
16015 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
16016
16017 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
16018 rb_define_alias(rb_cIO, "to_i", "fileno");
16019 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
16020
16021 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
16022 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
16023
16024 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
16025 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
16026 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
16027 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
16028
16029 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
16030 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
16031
16032 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
16033
16034 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
16035 rb_define_method(rb_cIO, "read", io_read, -1);
16036 rb_define_method(rb_cIO, "write", io_write_m, -1);
16037 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
16038 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
16039 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
16040 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
16041 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
16042 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
16043 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
16045 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
16046 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
16047 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
16048 /* Set I/O position from the beginning */
16049 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
16050 /* Set I/O position from the current position */
16051 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
16052 /* Set I/O position from the end */
16053 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
16054#ifdef SEEK_DATA
16055 /* Set I/O position to the next location containing data */
16056 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
16057#endif
16058#ifdef SEEK_HOLE
16059 /* Set I/O position to the next hole */
16060 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
16061#endif
16062 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
16063 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
16064 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
16065 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
16066 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
16067
16068 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
16069 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
16070
16071 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
16072 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
16073 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
16074 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
16075
16076 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
16077 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
16078 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
16079 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
16080 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
16081 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
16082
16083 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
16084 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
16085 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
16086
16087 rb_define_method(rb_cIO, "path", rb_io_path, 0);
16088 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
16089
16090 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
16091
16092 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
16093 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
16094 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
16095 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
16096
16097 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
16098 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
16099
16100 rb_define_method(rb_cIO, "wait", io_wait, -1);
16101
16102 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
16103 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
16104 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
16105
16106 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
16107 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
16108 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
16109 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
16110
16111 rb_gvar_ractor_local("$stdin");
16112 rb_gvar_ractor_local("$stdout");
16113 rb_gvar_ractor_local("$>");
16114 rb_gvar_ractor_local("$stderr");
16115
16116 rb_gvar_box_dynamic("$stdin");
16117 rb_gvar_box_dynamic("$stdout");
16118 rb_gvar_box_dynamic("$>");
16119 rb_gvar_box_dynamic("$stderr");
16120
16122 rb_stdin = rb_io_prep_stdin();
16124 rb_stdout = rb_io_prep_stdout();
16126 rb_stderr = rb_io_prep_stderr();
16127
16128 orig_stdout = rb_stdout;
16129 orig_stderr = rb_stderr;
16130
16131 /* Holds the original stdin */
16133 /* Holds the original stdout */
16135 /* Holds the original stderr */
16137
16138#if 0
16139 /* Hack to get rdoc to regard ARGF as a class: */
16140 rb_cARGF = rb_define_class("ARGF", rb_cObject);
16141#endif
16142
16143 rb_cARGF = rb_class_new(rb_cObject);
16144 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
16145 rb_define_alloc_func(rb_cARGF, argf_alloc);
16146
16148
16149 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
16150 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
16151 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
16152 rb_define_alias(rb_cARGF, "inspect", "to_s");
16153 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
16154
16155 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
16156 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
16157 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
16158 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
16159 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
16160 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
16161 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
16162 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
16163 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
16164
16165 rb_define_method(rb_cARGF, "read", argf_read, -1);
16166 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
16167 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
16168 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
16169 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
16170 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
16171 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
16172 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
16173 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
16174 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
16175 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
16176 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
16177 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
16178 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
16179 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
16180 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
16181 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
16182 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
16183 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
16184 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
16185
16186 rb_define_method(rb_cARGF, "write", argf_write, -1);
16187 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
16188 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
16189 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
16190 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
16191
16192 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
16193 rb_define_method(rb_cARGF, "path", argf_filename, 0);
16194 rb_define_method(rb_cARGF, "file", argf_file, 0);
16195 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
16196 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
16197 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
16198
16199 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
16200 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
16201
16202 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
16203 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
16204
16205 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
16206 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
16207 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
16208
16209 argf = rb_class_new_instance(0, 0, rb_cARGF);
16210
16212 /*
16213 * ARGF is a stream designed for use in scripts that process files given
16214 * as command-line arguments or passed in via STDIN.
16215 *
16216 * See ARGF (the class) for more details.
16217 */
16219
16220 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
16221 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
16222 ARGF_SET(filename, rb_str_new2("-"));
16223
16224 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
16225 rb_gvar_ractor_local("$-i");
16226
16227 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16228
16229#if defined (_WIN32) || defined(__CYGWIN__)
16230 atexit(pipe_atexit);
16231#endif
16232
16233 Init_File();
16234
16235 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16236
16237 sym_mode = ID2SYM(rb_intern_const("mode"));
16238 sym_perm = ID2SYM(rb_intern_const("perm"));
16239 sym_flags = ID2SYM(rb_intern_const("flags"));
16240 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16241 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16242 sym_encoding = ID2SYM(rb_id_encoding());
16243 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16244 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16245 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16246 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16247 sym_normal = ID2SYM(rb_intern_const("normal"));
16248 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16249 sym_random = ID2SYM(rb_intern_const("random"));
16250 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16251 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16252 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16253 sym_SET = ID2SYM(rb_intern_const("SET"));
16254 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16255 sym_END = ID2SYM(rb_intern_const("END"));
16256#ifdef SEEK_DATA
16257 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16258#endif
16259#ifdef SEEK_HOLE
16260 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16261#endif
16262 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16263 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16264}
16265
16266static void init_builtin_io(void);
16267#define Init_builtin_io init_builtin_io
16268#include "io.rbinc"
16269#undef Init_builtin_io
16270
16271void
16272Init_builtin_io(void)
16273{
16274 init_builtin_io();
16275
16276 /* Init_IO is called earlier than `loaded_features` is initialized */
16277 rb_provide("io/wait.rb");
16278 rb_provide("io/wait.so");
16279}
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:113
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1770
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:853
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:3095
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:3398
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:3385
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1035
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:3174
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1700
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
#define REALLOC_N
Old name of RB_REALLOC_N.
Definition memory.h:403
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:400
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define LEN2NUM
Old name of RB_LEN2NUM.
Definition len_t.h:29
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1708
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:131
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:111
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:520
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:109
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition ctype.h:103
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:518
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition transcode.h:538
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:519
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define NUM2LEN
Old name of RB_NUM2LEN.
Definition len_t.h:30
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1702
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:474
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:506
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1467
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:678
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:4068
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
Definition io.c:14937
VALUE rb_eIOError
IOError exception.
Definition io.c:179
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1454
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:4158
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:4074
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:476
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1457
VALUE rb_eEOFError
EOFError exception.
Definition io.c:178
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14931
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2413
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1455
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:464
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1477
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:59
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3347
VALUE rb_cObject
Object class.
Definition object.c:60
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:658
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2268
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2309
VALUE rb_cIO
IO class.
Definition io.c:177
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:2297
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:28
VALUE rb_stdin
STDIN constant.
Definition io.c:193
VALUE rb_stderr
STDERR constant.
Definition io.c:193
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:234
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:556
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:669
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:181
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:182
VALUE rb_obj_freeze(VALUE obj)
Same as RB_OBJ_FREEZE(), but returns the given object.
Definition object.c:1309
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:3328
VALUE rb_cFile
File class.
Definition file.c:175
VALUE rb_stdout
STDOUT constant.
Definition io.c:193
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3341
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:504
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:492
Scheduler APIs.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
Definition scheduler.c:581
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
Definition scheduler.c:632
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
Definition scheduler.c:866
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:856
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
Definition scheduler.h:74
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size)
Non-blocking pread from the passed IO using a native buffer.
Definition scheduler.c:1127
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:896
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size)
Non-blocking read from the passed IO using a native buffer.
Definition scheduler.c:1079
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread value inst...
Definition scheduler.c:589
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size)
Non-blocking pwrite to the passed IO using a native buffer.
Definition scheduler.c:1152
VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread)
Identical to rb_fiber_scheduler_current_for_thread(), except it expects a threadptr instead of a thre...
Definition scheduler.c:594
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
Definition scheduler.c:872
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
Definition scheduler.c:1177
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size)
Non-blocking write to the passed IO using a native buffer.
Definition scheduler.c:1103
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
Definition encoding.h:571
static int rb_enc_mbmaxlen(rb_encoding *enc)
Queries the maximum number of bytes that the passed encoding needs to represent a character.
Definition encoding.h:447
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1379
rb_len_t rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c:844
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3953
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
Definition transcode.c:2679
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
Definition transcode.c:2126
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
Definition transcode.c:1487
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
Definition transcode.h:69
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
Definition transcode.h:41
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1783
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1827
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
Definition transcode.c:1962
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
Definition transcode.c:2730
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
Definition transcode.c:2025
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
Definition transcode.c:2993
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4359
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4365
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1744
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1794
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1123
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
Definition vm_eval.c:1090
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
Definition vm_eval.c:1081
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_ary_entry(VALUE ary, rb_len_t off)
Queries an element of an array.
VALUE rb_ary_new_capa(rb_len_t capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:242
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8817
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4504
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:477
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:8950
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2428
void rb_write_error2(const char *str, rb_len_t len)
Identical to rb_write_error(), except it additionally takes the message's length.
Definition io.c:9359
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9379
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:5376
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5281
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:375
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:9560
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:273
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:336
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:198
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2770
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:323
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6619
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6573
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5440
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7620
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10648
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:483
VALUE rb_output_fs
The field separator character for outputs, or the $,.
Definition io.c:196
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:7504
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:368
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7511
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5976
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:199
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
Definition load.c:710
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:2175
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:2169
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
Definition proc.c:3812
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1161
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:676
void rb_str_modify_expand(VALUE str, rb_len_t capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2820
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:3917
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1523
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1706
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1557
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:1023
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1555
void rb_str_set_len(VALUE str, rb_len_t len)
Overwrites the length of the string.
Definition string.c:3504
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:2038
VALUE rb_str_cat(VALUE dst, const char *src, rb_len_t srclen)
Destructively appends the passed contents to the string.
Definition string.c:3685
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_no_gvl_safe_acquire(VALUE orig)
Creates a frozen copy of orig that guarantees the RSTRING_PTR is safe to use in operations that relea...
Definition string.c:1584
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4386
void rb_str_no_gvl_safe_release(VALUE orig, VALUE tmp)
Releases a string created from rb_str_no_gvl_safe_acquire.
Definition string.c:1627
VALUE rb_str_substr(VALUE str, rb_len_t beg, rb_len_t len)
This is the implementation of two-argumented String#slice.
Definition string.c:3367
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:3859
VALUE rb_str_buf_new(rb_len_t capa)
Allocates a "string buffer".
Definition string.c:1769
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:3051
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3486
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1539
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c:1902
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1662
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
Definition io.c:1668
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
Definition thread.c:1645
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:3480
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1662
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1668
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2984
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:457
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:2139
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:516
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3696
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well... Let us hesitate from describing what a "basic definition" is.
Definition vm_method.c:3574
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
Definition vm_eval.c:691
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:285
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
Definition variable.c:4052
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
Definition variable.c:888
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:162
enum rb_io_mode rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
Definition io.c:6705
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:818
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:864
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:788
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1102
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:6838
#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:1048
#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:1057
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:1654
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:7321
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:6987
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2969
#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:9606
#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:1721
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:1674
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:180
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:3048
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:7112
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:795
#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:5887
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:824
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:6084
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:893
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:2085
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:1029
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
Definition io.h:229
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:830
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3535
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1610
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:9472
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:841
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1081
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:1736
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:803
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1575
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7612
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1515
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:1455
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:1524
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:1512
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:1500
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:2319
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition sprintf.c:232
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
Definition vm_eval.c:1423
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1378
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition off_t.h:55
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:50
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:280
#define RARRAY_AREF(a, i)
Definition rarray.h:402
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:51
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:409
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:450
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:81
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:604
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14897
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9258
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:90
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
Definition scan_args.h:59
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition scan_args.h:78
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
Definition thread.c:4853
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
@ RUBY_Qfalse
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
C99 shim for <stdbool.h>
Ruby's File and IO.
Definition rfile.h:35
Definition io.c:228
Definition win32.h:196
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:242
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
Decomposed encoding flags (e.g.
Definition io.h:134
int ecflags
Flags.
Definition io.h:144
VALUE ecopts
Flags as Ruby hash.
Definition io.h:152
rb_encoding * enc2
External encoding.
Definition io.h:138
rb_encoding * enc
Internal encoding.
Definition io.h:136
IO buffers.
Definition io.h:109
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:112
int off
Offset inside of ptr.
Definition io.h:115
int len
Length of the buffer.
Definition io.h:118
int capa
Designed capacity of the buffer.
Definition io.h:121
Ruby's IO, metadata and buffers.
Definition io.h:295
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:330
enum rb_io_mode mode
mode flags: FMODE_XXXs
Definition io.h:310
void(* finalize)(struct rb_io *, int)
finalize proc
Definition io.h:326
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:352
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:363
struct rb_io_encoding encs
Decomposed encoding flags.
Definition io.h:348
VALUE self
The IO's Ruby level counterpart.
Definition io.h:298
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:400
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:406
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:302
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
Definition io.h:390
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:345
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:376
int fd
file descriptor.
Definition io.h:306
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:337
int lineno
number of lines read
Definition io.h:318
struct ccan_list_head blocking_operations
Threads that are performing a blocking operation without the GVL using this IO.
Definition io.h:134
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:372
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:359
rb_pid_t pid
child's pid (for pipes)
Definition io.h:314
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
Definition io.h:383
VALUE pathv
pathname for file
Definition io.h:322
long rb_len_t
A signed integer type for lengths and indices of objects such as String and Array.
Definition value.h:131
#define RB_LEN_MAX
Maximum possible value that a rb_len_t can take.
Definition value.h:148
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
Definition value_type.h:307
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:425
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376
#define RBIMPL_WARNING_IGNORED(flag)
Suppresses a warning.
#define RBIMPL_WARNING_PUSH()
Pushes compiler warning state.
#define RBIMPL_WARNING_POP()
Pops compiler warning state.