Ruby 4.1.0dev (2026-10-06 revision 186ebd63daaf628ba31d29793ae0bebf23697d39)
io.c (186ebd63daaf628ba31d29793ae0bebf23697d39)
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
104# ifndef COPYFILE_STATE_COPIED
105/*
106 * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
107 * COPYFILE_STATE_COPIED. Since the only use of the former here
108 * requires the latter, we disable the former when the latter is undefined.
109 */
110# undef HAVE_FCOPYFILE
111# endif
112
113#endif
114
115#if defined __APPLE__
116# include <AvailabilityMacros.h>
117#endif
118
120#include "ccan/list/list.h"
121#include "dln.h"
122#include "encindex.h"
123#include "id.h"
124#include "internal.h"
125#include "internal/class.h"
126#include "internal/encoding.h"
127#include "internal/error.h"
128#include "internal/inits.h"
129#include "internal/io.h"
130#include "internal/numeric.h"
131#include "internal/object.h"
132#include "internal/process.h"
133#include "internal/thread.h"
134#include "internal/transcode.h"
135#include "internal/variable.h"
136#include "ruby/io.h"
137#include "ruby/io/buffer.h"
138#include "ruby/missing.h"
139#include "ruby/thread.h"
140#include "ruby/util.h"
141#include "ruby_atomic.h"
142#include "ruby/ractor.h"
143
144#if !USE_POLL
145# include "vm_core.h"
146#endif
147
148#include "builtin.h"
149
150#ifndef O_ACCMODE
151#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
152#endif
153
154#ifndef PIPE_BUF
155# ifdef _POSIX_PIPE_BUF
156# define PIPE_BUF _POSIX_PIPE_BUF
157# else
158# define PIPE_BUF 512 /* is this ok? */
159# endif
160#endif
161
162#ifndef EWOULDBLOCK
163# define EWOULDBLOCK EAGAIN
164#endif
165
166#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
167/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
168off_t __syscall(quad_t number, ...);
169#endif
170
171#define IO_RBUF_CAPA_MIN 8192
172#define IO_CBUF_CAPA_MIN (128*1024)
173#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174#define IO_WBUF_CAPA_MIN 8192
175
176#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
177
178/* define system APIs */
179#ifdef _WIN32
180#undef open
181#define open rb_w32_uopen
182#undef rename
183#define rename(f, t) rb_w32_urename((f), (t))
184#include "win32/file.h"
185#endif
186
193
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196#if EAGAIN != EWOULDBLOCK
197static VALUE rb_eEWOULDBLOCKWaitReadable;
198static VALUE rb_eEWOULDBLOCKWaitWritable;
199#endif
200static VALUE rb_eEINPROGRESSWaitWritable;
201static VALUE rb_eEINPROGRESSWaitReadable;
202
204static VALUE orig_stdout, orig_stderr;
205
207VALUE rb_rs;
210
211static VALUE argf;
212
213static ID id_write, id_read, id_flush, id_readpartial, id_set_encoding, id_fileno;
214static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
215static VALUE sym_textmode, sym_binmode, sym_autoclose;
216static VALUE sym_SET, sym_CUR, sym_END;
217static VALUE sym_wait_readable, sym_wait_writable;
218#ifdef SEEK_DATA
219static VALUE sym_DATA;
220#endif
221#ifdef SEEK_HOLE
222static VALUE sym_HOLE;
223#endif
224
225static VALUE prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path);
226
227VALUE
228rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
229{
230 return rb_thread_io_blocking_call(io, function, argument, events);
231}
232
233VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
234{
235 return rb_io_blocking_region_wait(io, function, argument, 0);
236}
237
238struct argf {
239 VALUE filename, current_file;
240 long last_lineno; /* $. */
241 long lineno;
242 VALUE argv;
243 VALUE inplace;
244 struct rb_io_encoding encs;
245 int8_t init_p, next_p, binmode;
246};
247
248
249#if defined(__APPLE__) && \
250 (!defined(MAC_OS_VERSION_27_0) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_27_0))
251
252# if __has_attribute(availability) && __has_warning("-Wunguarded-availability-new")
253
255RBIMPL_WARNING_IGNORED(-Wunguarded-availability-new)
256
257# ifdef HAVE_DUP3
258static inline int (*rb_dup3(void))(int, int, int) {return &dup3;}
259# define dup3 rb_dup3()
260# endif
261
262# ifdef HAVE_PIPE2
263static inline int (*rb_pipe2(void))(int [2], int) {return &pipe2;}
264# define pipe2 rb_pipe2()
265# endif
266
268
269# else /* __API_AVAILABLE macro does nothing on gcc */
270
271# ifdef HAVE_DUP3
272__attribute__((weak)) int dup3(int, int, int);
273# endif
274# ifdef HAVE_PIPE2
275__attribute__((weak)) int pipe2(int [2], int);
276# endif
277
278# endif
279#endif /* __APPLE__ && < MAC_OS_X_VERSION_27_0 */
280
281static rb_atomic_t max_file_descriptor = NOFILE;
282void
284{
285 rb_atomic_t afd = (rb_atomic_t)fd;
286 rb_atomic_t max_fd = max_file_descriptor;
287 int err;
288
289 if (fd < 0 || afd <= max_fd)
290 return;
291
292#if defined(HAVE_FCNTL) && defined(F_GETFL)
293 err = fcntl(fd, F_GETFL) == -1;
294#else
295 {
296 struct stat buf;
297 err = fstat(fd, &buf) != 0;
298 }
299#endif
300 if (err && errno == EBADF) {
301 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
302 }
303
304 while (max_fd < afd) {
305 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
306 }
307}
308
309void
310rb_maygvl_fd_fix_cloexec(int fd)
311{
312 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
313#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
314 int flags, flags2, ret;
315 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
316 if (flags == -1) {
317 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
318 }
319 if (fd <= 2)
320 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
321 else
322 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
323 if (flags != flags2) {
324 ret = fcntl(fd, F_SETFD, flags2);
325 if (ret != 0) {
326 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
327 }
328 }
329#endif
330}
331
332void
334{
335 rb_maygvl_fd_fix_cloexec(fd);
337}
338
339static inline bool
340io_again_p(int e)
341{
342 return (e == EWOULDBLOCK) || (e == EAGAIN);
343}
344
345int
346rb_cloexec_open(const char *pathname, int flags, mode_t mode)
347{
348 int ret;
349
350 static const int retry_interval = 0;
351 static const int retry_max_count = 10000;
352
353 int retry_count = 0;
354
355#ifdef O_CLOEXEC
356 flags |= O_CLOEXEC;
357#elif defined O_NOINHERIT
358 flags |= O_NOINHERIT;
359#endif
360
361 while ((ret = open(pathname, flags, mode)) == -1) {
362 int e = errno;
363 if (!io_again_p(e)) break;
364 if (retry_count++ >= retry_max_count) break;
365
366 sleep(retry_interval);
367 }
368
369 if (ret < 0) return ret;
370#ifdef O_CLOEXEC
371 if (ret > 2) return ret;
372#endif
373 rb_maygvl_fd_fix_cloexec(ret);
374 return ret;
375}
376
377int
379{
380 /* Don't allocate standard file descriptors: 0, 1, 2 */
381 return rb_cloexec_fcntl_dupfd(oldfd, 3);
382}
383
384int
385rb_cloexec_dup2(int oldfd, int newfd)
386{
387 int ret;
388
389 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
390 * rb_cloexec_dup2 succeeds as dup2. */
391 if (oldfd == newfd) {
392 ret = newfd;
393 }
394 else {
395#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
396# if defined(__APPLE__)
397# define try_dup3 (dup3 != NULL)
398# define abandon_dup3() true
399# else
400 static bool try_dup3 = true;
401# define abandon_dup3() (errno != ENOSYS || !!(try_dup3 = false))
402# endif
403 if (newfd <= 2) {
404 /* pass stdin, stdout and stderr to children */
405 }
406 else if (try_dup3) {
407 ret = dup3(oldfd, newfd, O_CLOEXEC);
408 /* dup3 is available since:
409 * - Linux 2.6.27, glibc 2.9
410 * - macOS 27.0
411 */
412 if (ret != -1)
413 return ret;
414 if (abandon_dup3()) return ret;
415 }
416#endif
417 ret = dup2(oldfd, newfd);
418 if (ret < 0) return ret;
419 }
420 rb_maygvl_fd_fix_cloexec(ret);
421 return ret;
422}
423
424static int
425rb_fd_set_nonblock(int fd)
426{
427#ifdef _WIN32
428 return rb_w32_set_nonblock(fd);
429#elif defined(F_GETFL)
430 int oflags = fcntl(fd, F_GETFL);
431
432 if (oflags == -1)
433 return -1;
434 if (oflags & O_NONBLOCK)
435 return 0;
436 oflags |= O_NONBLOCK;
437 return fcntl(fd, F_SETFL, oflags);
438#endif
439 return 0;
440}
441
442static inline int
443cloexec_pipe(int descriptors[2], int flags, bool force_cloexec)
444{
445 int result = -1;
446#ifdef HAVE_PIPE2
447# if defined(__APPLE__)
448# define try_pipe2 (pipe2 != NULL)
449# define abandon_pipe2() true
450# else
451 static bool try_pipe2 = true;
452# define abandon_pipe2() (errno != ENOSYS || !!(try_pipe2 = false))
453# endif
454 if (try_pipe2) {
455 result = pipe2(descriptors, O_CLOEXEC | flags);
456 if (result == 0) return result;
457 if (abandon_pipe2()) return result;
458 }
459#endif
460 if (result < 0 && (result = pipe(descriptors)) < 0)
461 return result;
462
463#ifdef __CYGWIN__
464 if (result == 0 && descriptors[1] == -1) {
465 close(descriptors[0]);
466 descriptors[0] = -1;
467 errno = ENFILE;
468 return -1;
469 }
470#endif
471
472 if (!force_cloexec) return result;
473
474 /* no pipe2 or fallenback to dup */
475 rb_maygvl_fd_fix_cloexec(descriptors[0]);
476 rb_maygvl_fd_fix_cloexec(descriptors[1]);
477
478#ifndef _WIN32
479 rb_fd_set_nonblock(descriptors[0]);
480 rb_fd_set_nonblock(descriptors[1]);
481#endif
482
483 return result;
484}
485
486int
487rb_cloexec_pipe(int descriptors[2])
488{
489 return cloexec_pipe(descriptors, O_NONBLOCK, true);
490}
491
492int
493rb_cloexec_fcntl_dupfd(int fd, int minfd)
494{
495 int ret;
496
497#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC)
498 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
499 if (ret > 2) return ret;
500#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
501 ret = fcntl(fd, F_DUPFD, minfd);
502#else
503 ret = dup(fd);
504 if (ret >= 0 && ret < minfd) {
505 const int prev_fd = ret;
506 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
507 close(prev_fd);
508 }
509 return ret;
510#endif
511 if (ret < 0) return ret;
512 rb_maygvl_fd_fix_cloexec(ret);
513 return ret;
514}
515
516#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
517#define ARGF argf_of(argf)
518#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
519
520#define GetWriteIO(io) rb_io_get_write_io(io)
521
522#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
523#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
524#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
525#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
526
527#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
528#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
529#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
530
531#if defined(_WIN32)
532#define WAIT_FD_IN_WIN32(fptr) \
533 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
534#else
535#define WAIT_FD_IN_WIN32(fptr)
536#endif
537
538#define READ_CHECK(fptr) do {\
539 if (!READ_DATA_PENDING(fptr)) {\
540 WAIT_FD_IN_WIN32(fptr);\
541 rb_io_check_closed(fptr);\
542 }\
543} while(0)
544
545#ifndef S_ISSOCK
546# ifdef _S_ISSOCK
547# define S_ISSOCK(m) _S_ISSOCK(m)
548# else
549# ifdef _S_IFSOCK
550# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
551# else
552# ifdef S_IFSOCK
553# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
554# endif
555# endif
556# endif
557#endif
558
559static int io_fflush(rb_io_t *);
560static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
561static void clear_readconv(rb_io_t *fptr);
562static void clear_codeconv(rb_io_t *fptr);
563
564#define FMODE_SIGNAL_ON_EPIPE (1<<17)
565
566#define fptr_signal_on_epipe(fptr) \
567 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
568
569#define fptr_set_signal_on_epipe(fptr, flag) \
570 ((flag) ? \
571 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
572 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
573
574extern ID ruby_static_id_signo;
575
576NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
577static void
578rb_sys_fail_on_write(rb_io_t *fptr)
579{
580 int e = errno;
581 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
582#if defined EPIPE
583 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
584 const VALUE sig =
585# if defined SIGPIPE
586 INT2FIX(SIGPIPE) - INT2FIX(0) +
587# endif
588 INT2FIX(0);
589 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
590 }
591#endif
592 rb_exc_raise(errinfo);
593}
594
595#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
596#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
597#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
598# define RUBY_CRLF_ENVIRONMENT 1
599#else
600# define RUBY_CRLF_ENVIRONMENT 0
601#endif
602
603#if RUBY_CRLF_ENVIRONMENT
604/* Windows */
605# define DEFAULT_TEXTMODE FMODE_TEXTMODE
606# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
607/*
608 * CRLF newline is set as default newline decorator.
609 * If only CRLF newline conversion is needed, we use binary IO process
610 * with OS's text mode for IO performance improvement.
611 * If encoding conversion is needed or a user sets text mode, we use encoding
612 * conversion IO process and universal newline decorator by default.
613 */
614#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
615#define WRITECONV_MASK ( \
616 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
617 ECONV_STATEFUL_DECORATOR_MASK|\
618 0)
619#define NEED_WRITECONV(fptr) ( \
620 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
621 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
622 0)
623#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
624
625#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
626 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
627 if (((fptr)->mode & FMODE_READABLE) &&\
628 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
629 setmode((fptr)->fd, O_BINARY);\
630 }\
631 else {\
632 setmode((fptr)->fd, O_TEXT);\
633 }\
634 }\
635} while(0)
636
637#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
638 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
639 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
640 }\
641} while(0)
642
643/*
644 * IO unread with taking care of removed '\r' in text mode.
645 */
646static void
647io_unread(rb_io_t *fptr, bool discard_rbuf)
648{
649 rb_off_t r, pos;
650 ssize_t read_size;
651 long i;
652 long newlines = 0;
653 long extra_max;
654 char *p;
655 char *buf;
656
657 rb_io_check_closed(fptr);
658 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
659 return;
660 }
661
662 errno = 0;
663 if (!rb_w32_fd_is_text(fptr->fd)) {
664 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
665 if (r < 0 && errno) {
666 if (errno == ESPIPE)
667 fptr->mode |= FMODE_DUPLEX;
668 if (!discard_rbuf) return;
669 }
670
671 goto end;
672 }
673
674 pos = lseek(fptr->fd, 0, SEEK_CUR);
675 if (pos < 0 && errno) {
676 if (errno == ESPIPE)
677 fptr->mode |= FMODE_DUPLEX;
678 if (!discard_rbuf) goto end;
679 }
680
681 /* add extra offset for removed '\r' in rbuf */
682 extra_max = (long)(pos - fptr->rbuf.len);
683 p = fptr->rbuf.ptr + fptr->rbuf.off;
684
685 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
686 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
687 newlines++;
688 }
689
690 for (i = 0; i < fptr->rbuf.len; i++) {
691 if (*p == '\n') newlines++;
692 if (extra_max == newlines) break;
693 p++;
694 }
695
696 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
697 while (newlines >= 0) {
698 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
699 if (newlines == 0) break;
700 if (r < 0) {
701 newlines--;
702 continue;
703 }
704 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
705 if (read_size < 0) {
706 int e = errno;
707 free(buf);
708 rb_syserr_fail_path(e, fptr->pathv);
709 }
710 if (read_size == fptr->rbuf.len) {
711 lseek(fptr->fd, r, SEEK_SET);
712 break;
713 }
714 else {
715 newlines--;
716 }
717 }
718 free(buf);
719 end:
720 fptr->rbuf.off = 0;
721 fptr->rbuf.len = 0;
722 clear_codeconv(fptr);
723 return;
724}
725
726/*
727 * We use io_seek to back cursor position when changing mode from text to binary,
728 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
729 * conversion for working properly with mode change.
730 *
731 * Return previous translation mode.
732 */
733static inline int
734set_binary_mode_with_seek_cur(rb_io_t *fptr)
735{
736 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
737
738 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
739 return setmode(fptr->fd, O_BINARY);
740 }
741 flush_before_seek(fptr, false);
742 return setmode(fptr->fd, O_BINARY);
743}
744#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
745
746#else
747/* Unix */
748# define DEFAULT_TEXTMODE 0
749#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
750#define NEED_WRITECONV(fptr) ( \
751 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
752 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
753 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
754 0)
755#define SET_BINARY_MODE(fptr) (void)(fptr)
756#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
757#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
758#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
759#endif
760
761#if !defined HAVE_SHUTDOWN && !defined shutdown
762#define shutdown(a,b) 0
763#endif
764
765#if defined(_WIN32)
766#define is_socket(fd, path) rb_w32_is_socket(fd)
767#elif !defined(S_ISSOCK)
768#define is_socket(fd, path) 0
769#else
770static int
771is_socket(int fd, VALUE path)
772{
773 struct stat sbuf;
774 if (fstat(fd, &sbuf) < 0)
775 rb_sys_fail_path(path);
776 return S_ISSOCK(sbuf.st_mode);
777}
778#endif
779
780static const char closed_stream[] = "closed stream";
781
782static void
783io_fd_check_closed(int fd)
784{
785 if (fd < 0) {
786 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
787 rb_raise(rb_eIOError, closed_stream);
788 }
789}
790
791void
792rb_eof_error(void)
793{
794 rb_raise(rb_eEOFError, "end of file reached");
795}
796
797VALUE
799{
800 rb_check_frozen(io);
801 return io;
802}
803
804void
806{
807 if (!fptr) {
808 rb_raise(rb_eIOError, "uninitialized stream");
809 }
810}
811
812void
814{
816 io_fd_check_closed(fptr->fd);
817}
818
819static rb_io_t *
820rb_io_get_fptr(VALUE io)
821{
822 rb_io_t *fptr = RFILE(io)->fptr;
824 return fptr;
825}
826
827VALUE
829{
830 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
831}
832
833VALUE
835{
836 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
837}
838
839VALUE
841{
842 VALUE write_io;
843 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
844 if (write_io) {
845 return write_io;
846 }
847 return io;
848}
849
850VALUE
852{
853 VALUE write_io;
854 rb_io_t *fptr = rb_io_get_fptr(io);
855 if (!RTEST(w)) {
856 w = 0;
857 }
858 else {
859 GetWriteIO(w);
860 }
861 write_io = fptr->tied_io_for_writing;
862 fptr->tied_io_for_writing = w;
863 return write_io ? write_io : Qnil;
864}
865
866/*
867 * call-seq:
868 * timeout -> duration or nil
869 *
870 * Get the internal timeout duration or nil if it was not set.
871 *
872 */
873VALUE
875{
876 rb_io_t *fptr = rb_io_get_fptr(self);
877
878 return fptr->timeout;
879}
880
881/*
882 * call-seq:
883 * timeout = duration -> duration
884 * timeout = nil -> nil
885 *
886 * Sets the internal timeout to the specified duration or nil. The timeout
887 * applies to all blocking operations where possible.
888 *
889 * When the operation performs longer than the timeout set, IO::TimeoutError
890 * is raised.
891 *
892 * This affects the following methods (but is not limited to): #gets, #puts,
893 * #read, #write, #wait_readable and #wait_writable. This also affects
894 * blocking socket operations like Socket#accept and Socket#connect.
895 *
896 * Some operations like File#open and IO#close are not affected by the
897 * timeout. A timeout during a write operation may leave the IO in an
898 * inconsistent state, e.g. data was partially written. Generally speaking, a
899 * timeout is a last ditch effort to prevent an application from hanging on
900 * slow I/O operations, such as those that occur during a slowloris attack.
901 */
902VALUE
904{
905 // Validate it:
906 if (RTEST(timeout)) {
907 rb_time_interval(timeout);
908 }
909
910 rb_io_t *fptr = rb_io_get_fptr(self);
911
912 RB_OBJ_WRITE(self, &fptr->timeout, timeout);
913
914 return self;
915}
916
917/*
918 * call-seq:
919 * IO.try_convert(object) -> new_io or nil
920 *
921 * Attempts to convert +object+ into an \IO object via method +to_io+;
922 * returns the new \IO object if successful, or +nil+ otherwise:
923 *
924 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
925 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
926 * IO.try_convert('STDOUT') # => nil
927 *
928 */
929static VALUE
930rb_io_s_try_convert(VALUE dummy, VALUE io)
931{
932 return rb_io_check_io(io);
933}
934
935#if !RUBY_CRLF_ENVIRONMENT
936static void
937io_unread(rb_io_t *fptr, bool discard_rbuf)
938{
939 rb_off_t r;
940 rb_io_check_closed(fptr);
941 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
942 return;
943 /* xxx: target position may be negative if buffer is filled by ungetc */
944 errno = 0;
945 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
946 if (r < 0 && errno) {
947 if (errno == ESPIPE)
948 fptr->mode |= FMODE_DUPLEX;
949 if (!discard_rbuf) return;
950 }
951 fptr->rbuf.off = 0;
952 fptr->rbuf.len = 0;
953 clear_codeconv(fptr);
954 return;
955}
956#endif
957
958static rb_encoding *io_input_encoding(rb_io_t *fptr);
959
960static void
961io_ungetbyte(VALUE str, rb_io_t *fptr)
962{
963 long len = RSTRING_LEN(str);
964
965 if (fptr->rbuf.ptr == NULL) {
966 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
967 fptr->rbuf.off = 0;
968 fptr->rbuf.len = 0;
969#if SIZEOF_LONG > SIZEOF_INT
970 if (len > INT_MAX)
971 rb_raise(rb_eIOError, "ungetbyte failed");
972#endif
973 if (len > min_capa)
974 fptr->rbuf.capa = (int)len;
975 else
976 fptr->rbuf.capa = min_capa;
977 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
978 }
979 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
980 rb_raise(rb_eIOError, "ungetbyte failed");
981 }
982 if (fptr->rbuf.off < len) {
983 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
984 fptr->rbuf.ptr+fptr->rbuf.off,
985 char, fptr->rbuf.len);
986 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
987 }
988 fptr->rbuf.off-=(int)len;
989 fptr->rbuf.len+=(int)len;
990 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
991}
992
993static void
994io_restore_read_buffer(VALUE str, rb_io_t *fptr)
995{
996 long len = RSTRING_LEN(str);
997
998 if (len > INT_MAX - fptr->rbuf.len) {
999 rb_raise(rb_eIOError, "read buffer too large");
1000 }
1001 if (fptr->rbuf.ptr == NULL || fptr->rbuf.capa >= len + fptr->rbuf.len) {
1002 io_ungetbyte(str, fptr);
1003 }
1004 else {
1005 int pending = fptr->rbuf.len;
1006 int capa = (int)len + pending;
1007 char *ptr = ALLOC_N(char, capa);
1008
1009 MEMMOVE(ptr, RSTRING_PTR(str), char, len);
1010 MEMMOVE(ptr + len, fptr->rbuf.ptr + fptr->rbuf.off, char, pending);
1011 ruby_xfree(fptr->rbuf.ptr);
1012 fptr->rbuf.ptr = ptr;
1013 fptr->rbuf.off = 0;
1014 fptr->rbuf.len = capa;
1015 fptr->rbuf.capa = capa;
1016 }
1017}
1018
1019static rb_io_t *
1020flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
1021{
1022 if (io_fflush(fptr) < 0)
1023 rb_sys_fail_on_write(fptr);
1024 io_unread(fptr, discard_rbuf);
1025 errno = 0;
1026 return fptr;
1027}
1028
1029#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
1030#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1031
1032#ifndef SEEK_CUR
1033# define SEEK_SET 0
1034# define SEEK_CUR 1
1035# define SEEK_END 2
1036#endif
1037
1038void
1040{
1041 rb_io_check_closed(fptr);
1042 if (!(fptr->mode & FMODE_READABLE)) {
1043 rb_raise(rb_eIOError, "not opened for reading");
1044 }
1045 if (fptr->wbuf.len) {
1046 if (io_fflush(fptr) < 0)
1047 rb_sys_fail_on_write(fptr);
1048 }
1049 if (fptr->tied_io_for_writing) {
1050 rb_io_t *wfptr;
1051 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1052 if (io_fflush(wfptr) < 0)
1053 rb_sys_fail_on_write(wfptr);
1054 }
1055}
1056
1057void
1059{
1061 if (READ_CHAR_PENDING(fptr)) {
1062 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1063 }
1064}
1065
1066void
1071
1072static rb_encoding*
1073io_read_encoding(rb_io_t *fptr)
1074{
1075 if (fptr->encs.enc) {
1076 return fptr->encs.enc;
1077 }
1078 return rb_default_external_encoding();
1079}
1080
1081static rb_encoding*
1082io_input_encoding(rb_io_t *fptr)
1083{
1084 if (fptr->encs.enc2) {
1085 return fptr->encs.enc2;
1086 }
1087 return io_read_encoding(fptr);
1088}
1089
1090void
1092{
1093 rb_io_check_closed(fptr);
1094 if (!(fptr->mode & FMODE_WRITABLE)) {
1095 rb_raise(rb_eIOError, "not opened for writing");
1096 }
1097 if (fptr->rbuf.len) {
1098 io_unread(fptr, true);
1099 }
1100}
1101
1102int
1103rb_io_read_pending(rb_io_t *fptr)
1104{
1105 /* This function is used for bytes and chars. Confusing. */
1106 if (READ_CHAR_PENDING(fptr))
1107 return 1; /* should raise? */
1108 return READ_DATA_PENDING(fptr);
1109}
1110
1111void
1113{
1114 if (!READ_DATA_PENDING(fptr)) {
1115 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1116 }
1117 return;
1118}
1119
1120int
1121rb_gc_for_fd(int err)
1122{
1123 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1124 rb_gc();
1125 return 1;
1126 }
1127 return 0;
1128}
1129
1130/* try `expr` upto twice while it returns false and `errno`
1131 * is to GC. Each `errno`s are available as `first_errno` and
1132 * `retried_errno` respectively */
1133#define TRY_WITH_GC(expr) \
1134 for (int first_errno, retried_errno = 0, retried = 0; \
1135 (!retried && \
1136 !(expr) && \
1137 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1138 (retried_errno = errno, 1)); \
1139 (void)retried_errno, retried = 1)
1140
1141static int
1142ruby_dup(int orig)
1143{
1144 int fd = -1;
1145
1146 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1147 rb_syserr_fail(first_errno, 0);
1148 }
1149 rb_update_max_fd(fd);
1150 return fd;
1151}
1152
1153static VALUE
1154io_alloc(VALUE klass)
1155{
1156 UNPROTECTED_NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile));
1157
1158 io->fptr = 0;
1159
1160 return (VALUE)io;
1161}
1162
1163#ifndef S_ISREG
1164# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1165#endif
1166
1168 VALUE th;
1169 rb_io_t *fptr;
1170 int nonblock;
1171 int fd;
1172
1173 void *buf;
1174 size_t capa;
1175 struct timeval *timeout;
1176};
1177
1179 VALUE th;
1180 rb_io_t *fptr;
1181 int nonblock;
1182 int fd;
1183
1184 const void *buf;
1185 size_t capa;
1186 struct timeval *timeout;
1187};
1188
1189#ifdef HAVE_WRITEV
1190struct io_internal_writev_struct {
1191 VALUE th;
1192 rb_io_t *fptr;
1193 int nonblock;
1194 int fd;
1195
1196 int iovcnt;
1197 const struct iovec *iov;
1198 struct timeval *timeout;
1199};
1200#endif
1201
1202static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1203
1209static inline int
1210io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1211{
1212 if (!timeout && rb_thread_mn_schedulable(thread)) {
1213 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1214 return -1;
1215 }
1216
1217 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1218
1219 if (ready > 0) {
1220 return ready;
1221 }
1222 else if (ready == 0) {
1223 errno = ETIMEDOUT;
1224 return -1;
1225 }
1226
1227 // If there was an error BEFORE we started waiting, return it:
1228 if (error) {
1229 errno = error;
1230 return -1;
1231 }
1232 else {
1233 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1234 return ready;
1235 }
1236}
1237
1238static VALUE
1239internal_read_func(void *ptr)
1240{
1241 struct io_internal_read_struct *iis = ptr;
1242 ssize_t result;
1243
1244 if (iis->timeout && !iis->nonblock) {
1245 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1246 return -1;
1247 }
1248 }
1249
1250 retry:
1251 result = read(iis->fd, iis->buf, iis->capa);
1252
1253 if (result < 0 && !iis->nonblock) {
1254 if (io_again_p(errno)) {
1255 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1256 return -1;
1257 }
1258 else {
1259 goto retry;
1260 }
1261 }
1262 }
1263
1264 return result;
1265}
1266
1267#if defined __APPLE__
1268# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1269#else
1270# define do_write_retry(code) result = code
1271#endif
1272
1273static VALUE
1274internal_write_func(void *ptr)
1275{
1276 struct io_internal_write_struct *iis = ptr;
1277 ssize_t result;
1278
1279 if (iis->timeout && !iis->nonblock) {
1280 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1281 return -1;
1282 }
1283 }
1284
1285 retry:
1286 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1287
1288 if (result < 0 && !iis->nonblock) {
1289 int e = errno;
1290 if (io_again_p(e)) {
1291 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1292 return -1;
1293 }
1294 else {
1295 goto retry;
1296 }
1297 }
1298 }
1299
1300 return result;
1301}
1302
1303#ifdef HAVE_WRITEV
1304static VALUE
1305internal_writev_func(void *ptr)
1306{
1307 struct io_internal_writev_struct *iis = ptr;
1308 ssize_t result;
1309
1310 if (iis->timeout && !iis->nonblock) {
1311 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1312 return -1;
1313 }
1314 }
1315
1316 retry:
1317 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1318
1319 if (result < 0 && !iis->nonblock) {
1320 if (io_again_p(errno)) {
1321 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1322 return -1;
1323 }
1324 else {
1325 goto retry;
1326 }
1327 }
1328 }
1329
1330 return result;
1331}
1332#endif
1333
1334static ssize_t
1335rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1336{
1337 rb_thread_t *th = GET_THREAD();
1339 if (scheduler != Qnil) {
1340 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count);
1341
1342 if (!UNDEF_P(result)) {
1344 }
1345 }
1346
1347 struct io_internal_read_struct iis = {
1348 .th = th->self,
1349 .fptr = fptr,
1350 .nonblock = 0,
1351 .fd = fptr->fd,
1352
1353 .buf = buf,
1354 .capa = count,
1355 .timeout = NULL,
1356 };
1357
1358 struct timeval timeout_storage;
1359
1360 if (fptr->timeout != Qnil) {
1361 timeout_storage = rb_time_interval(fptr->timeout);
1362 iis.timeout = &timeout_storage;
1363 }
1364
1365 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1366}
1367
1368static ssize_t
1369rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1370{
1371 rb_thread_t *th = GET_THREAD();
1373 if (scheduler != Qnil) {
1374 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count);
1375
1376 if (!UNDEF_P(result)) {
1378 }
1379 }
1380
1381 struct io_internal_write_struct iis = {
1382 .th = th->self,
1383 .fptr = fptr,
1384 .nonblock = 0,
1385 .fd = fptr->fd,
1386
1387 .buf = buf,
1388 .capa = count,
1389 .timeout = NULL
1390 };
1391
1392 struct timeval timeout_storage;
1393
1394 if (fptr->timeout != Qnil) {
1395 timeout_storage = rb_time_interval(fptr->timeout);
1396 iis.timeout = &timeout_storage;
1397 }
1398
1399 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1400}
1401
1402#ifdef HAVE_WRITEV
1403static ssize_t
1404rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1405{
1406 if (!iovcnt) return 0;
1407
1408 rb_thread_t *th = GET_THREAD();
1409
1411 if (scheduler != Qnil) {
1412 // This path assumes at least one `iov`:
1413 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len);
1414
1415 if (!UNDEF_P(result)) {
1417 }
1418 }
1419
1420 struct io_internal_writev_struct iis = {
1421 .th = th->self,
1422 .fptr = fptr,
1423 .nonblock = 0,
1424 .fd = fptr->fd,
1425
1426 .iov = iov,
1427 .iovcnt = iovcnt,
1428 .timeout = NULL
1429 };
1430
1431 struct timeval timeout_storage;
1432
1433 if (fptr->timeout != Qnil) {
1434 timeout_storage = rb_time_interval(fptr->timeout);
1435 iis.timeout = &timeout_storage;
1436 }
1437
1438 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1439}
1440#endif
1441
1442static VALUE
1443io_flush_buffer_sync(void *arg)
1444{
1445 rb_io_t *fptr = arg;
1446 long l = fptr->wbuf.len;
1447 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1448
1449 if (fptr->wbuf.len <= r) {
1450 fptr->wbuf.off = 0;
1451 fptr->wbuf.len = 0;
1452 return 0;
1453 }
1454
1455 if (0 <= r) {
1456 fptr->wbuf.off += (int)r;
1457 fptr->wbuf.len -= (int)r;
1458 errno = EAGAIN;
1459 }
1460
1461 return (VALUE)-1;
1462}
1463
1464static inline VALUE
1465io_flush_buffer_fiber_scheduler(VALUE scheduler, rb_io_t *fptr)
1466{
1467 VALUE ret = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, fptr->wbuf.ptr+fptr->wbuf.off, fptr->wbuf.len);
1468 if (!UNDEF_P(ret)) {
1469 ssize_t result = rb_fiber_scheduler_io_result_apply(ret);
1470 if (result > 0) {
1471 fptr->wbuf.off += result;
1472 fptr->wbuf.len -= result;
1473 }
1474 return result >= 0 ? (VALUE)0 : (VALUE)-1;
1475 }
1476 return ret;
1477}
1478
1479static VALUE
1480io_flush_buffer_async(VALUE arg)
1481{
1482 rb_io_t *fptr = (rb_io_t *)arg;
1483
1484 VALUE scheduler = rb_fiber_scheduler_current();
1485 if (scheduler != Qnil) {
1486 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1487 if (!UNDEF_P(result)) {
1488 return result;
1489 }
1490 }
1491
1492 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1493}
1494
1495static inline int
1496io_flush_buffer(rb_io_t *fptr)
1497{
1498 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1499 return (int)io_flush_buffer_async((VALUE)fptr);
1500 }
1501 else {
1502 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1503 }
1504}
1505
1506static int
1507io_fflush(rb_io_t *fptr)
1508{
1509 rb_io_check_closed(fptr);
1510
1511 if (fptr->wbuf.len == 0)
1512 return 0;
1513
1514 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1515 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1516 return -1;
1517
1518 rb_io_check_closed(fptr);
1519 }
1520
1521 return 0;
1522}
1523
1524VALUE
1525rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1526{
1527 rb_thread_t *th = GET_THREAD();
1529
1530 if (scheduler != Qnil) {
1531 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1532 }
1533
1534 rb_io_t * fptr = NULL;
1535 RB_IO_POINTER(io, fptr);
1536
1537 struct timeval tv_storage;
1538 struct timeval *tv = NULL;
1539
1540 if (NIL_OR_UNDEF_P(timeout)) {
1541 timeout = fptr->timeout;
1542 }
1543
1544 if (timeout != Qnil) {
1545 tv_storage = rb_time_interval(timeout);
1546 tv = &tv_storage;
1547 }
1548
1549 int ready = rb_thread_io_wait(th, fptr, RB_NUM2INT(events), tv);
1550
1551 if (ready < 0) {
1552 rb_sys_fail(0);
1553 }
1554
1555 // Not sure if this is necessary:
1556 rb_io_check_closed(fptr);
1557
1558 if (ready) {
1559 return RB_INT2NUM(ready);
1560 }
1561 else {
1562 return Qfalse;
1563 }
1564}
1565
1566static VALUE
1567io_from_fd(int fd)
1568{
1569 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1570}
1571
1572static int
1573io_wait_for_single_fd(int fd, int events, struct timeval *timeout, rb_thread_t *th, VALUE scheduler)
1574{
1575 if (scheduler != Qnil) {
1576 return RTEST(
1577 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1578 );
1579 }
1580
1581 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1582}
1583
1584int
1586{
1587 io_fd_check_closed(f);
1588
1589 rb_thread_t *th = GET_THREAD();
1591
1592 switch (errno) {
1593 case EINTR:
1594#if defined(ERESTART)
1595 case ERESTART:
1596#endif
1598 return TRUE;
1599
1600 case EAGAIN:
1601#if EWOULDBLOCK != EAGAIN
1602 case EWOULDBLOCK:
1603#endif
1604 if (scheduler != Qnil) {
1605 return RTEST(
1606 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1607 );
1608 }
1609 else {
1610 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL, th, scheduler);
1611 }
1612 return TRUE;
1613
1614 default:
1615 return FALSE;
1616 }
1617}
1618
1619int
1621{
1622 io_fd_check_closed(f);
1623
1624 rb_thread_t *th = GET_THREAD();
1626
1627 switch (errno) {
1628 case EINTR:
1629#if defined(ERESTART)
1630 case ERESTART:
1631#endif
1632 /*
1633 * In old Linux, several special files under /proc and /sys don't handle
1634 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1635 * Otherwise, we face nasty hang up. Sigh.
1636 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1637 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1638 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1639 * Then rb_thread_check_ints() is enough.
1640 */
1642 return TRUE;
1643
1644 case EAGAIN:
1645#if EWOULDBLOCK != EAGAIN
1646 case EWOULDBLOCK:
1647#endif
1648 if (scheduler != Qnil) {
1649 return RTEST(
1650 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1651 );
1652 }
1653 else {
1654 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL, th, scheduler);
1655 }
1656 return TRUE;
1657
1658 default:
1659 return FALSE;
1660 }
1661}
1662
1663int
1664rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1665{
1666 rb_thread_t *th = GET_THREAD();
1668 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1669}
1670
1671int
1673{
1674 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1675}
1676
1677int
1679{
1680 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1681}
1682
1683VALUE
1684rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1685{
1686 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1687 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1688 // instead relies on `read(-1) -> -1` which causes this code path. We then
1689 // check here whether the IO was in fact closed. Probably it's better to
1690 // check that `fptr->fd != -1` before using it in syscall.
1691 rb_io_check_closed(RFILE(io)->fptr);
1692
1693 switch (error) {
1694 // In old Linux, several special files under /proc and /sys don't handle
1695 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1696 // Otherwise, we face nasty hang up. Sigh.
1697 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1698 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1699 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1700 // Then rb_thread_check_ints() is enough.
1701 case EINTR:
1702#if defined(ERESTART)
1703 case ERESTART:
1704#endif
1705 // We might have pending interrupts since the previous syscall was interrupted:
1707
1708 // The operation was interrupted, so retry it immediately:
1709 return events;
1710
1711 case EAGAIN:
1712#if EWOULDBLOCK != EAGAIN
1713 case EWOULDBLOCK:
1714#endif
1715 {
1716 // The operation would block, so wait for the specified events:
1717 VALUE result = rb_io_wait(io, events, timeout);
1718 // The scheduler may change errno while waiting. Preserve the original
1719 // error in case no events are ready and the caller reports the failure.
1720 errno = error;
1721 return result;
1722 }
1723
1724 default:
1725 // Non-specific error, no event is ready:
1726 return Qnil;
1727 }
1728}
1729
1730int
1732{
1733 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1734
1735 if (RTEST(result)) {
1736 return RB_NUM2INT(result);
1737 }
1738 else if (result == RUBY_Qfalse) {
1739 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1740 }
1741
1742 return 0;
1743}
1744
1745int
1747{
1748 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1749
1750 if (RTEST(result)) {
1751 return RB_NUM2INT(result);
1752 }
1753 else if (result == RUBY_Qfalse) {
1754 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1755 }
1756
1757 return 0;
1758}
1759
1760static void
1761make_writeconv(rb_io_t *fptr)
1762{
1763 if (!fptr->writeconv_initialized) {
1764 const char *senc, *denc;
1765 rb_encoding *enc;
1766 int ecflags;
1767 VALUE ecopts;
1768
1769 fptr->writeconv_initialized = 1;
1770
1771 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1772 ecopts = fptr->encs.ecopts;
1773
1774 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1775 /* no encoding conversion */
1776 fptr->writeconv_pre_ecflags = 0;
1777 fptr->writeconv_pre_ecopts = Qnil;
1778 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1779 if (!fptr->writeconv)
1780 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1782 }
1783 else {
1784 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1785 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1786 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1787 /* single conversion */
1788 fptr->writeconv_pre_ecflags = ecflags;
1789 fptr->writeconv_pre_ecopts = ecopts;
1790 fptr->writeconv = NULL;
1792 }
1793 else {
1794 /* double conversion */
1795 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1796 fptr->writeconv_pre_ecopts = ecopts;
1797 if (senc) {
1798 denc = rb_enc_name(enc);
1799 fptr->writeconv_asciicompat = rb_str_new2(senc);
1800 }
1801 else {
1802 senc = denc = "";
1803 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1804 }
1806 ecopts = fptr->encs.ecopts;
1807 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1808 if (!fptr->writeconv)
1809 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1810 }
1811 }
1812 }
1813}
1814
1815/* writing functions */
1817 rb_io_t *fptr;
1818 const char *ptr;
1819 long length;
1820};
1821
1823 VALUE io;
1824 VALUE str;
1825 int nosync;
1826};
1827
1828#ifdef HAVE_WRITEV
1829static ssize_t
1830io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1831{
1832 if (fptr->wbuf.len) {
1833 struct iovec iov[2];
1834
1835 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1836 iov[0].iov_len = fptr->wbuf.len;
1837 iov[1].iov_base = (void*)ptr;
1838 iov[1].iov_len = length;
1839
1840 ssize_t result = rb_writev_internal(fptr, iov, 2);
1841
1842 if (result < 0)
1843 return result;
1844
1845 if (result >= fptr->wbuf.len) {
1846 // We wrote more than the internal buffer:
1847 result -= fptr->wbuf.len;
1848 fptr->wbuf.off = 0;
1849 fptr->wbuf.len = 0;
1850 }
1851 else {
1852 // We only wrote less data than the internal buffer:
1853 fptr->wbuf.off += (int)result;
1854 fptr->wbuf.len -= (int)result;
1855
1856 result = 0;
1857 }
1858
1859 return result;
1860 }
1861 else {
1862 return rb_io_write_memory(fptr, ptr, length);
1863 }
1864}
1865#else
1866static ssize_t
1867io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1868{
1869 long remaining = length;
1870
1871 if (fptr->wbuf.len) {
1872 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1873 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1874 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1875 fptr->wbuf.off = 0;
1876 }
1877
1878 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1879 fptr->wbuf.len += (int)length;
1880
1881 // We copied the entire incoming data to the internal buffer:
1882 remaining = 0;
1883 }
1884
1885 // Flush the internal buffer:
1886 if (io_fflush(fptr) < 0) {
1887 return -1;
1888 }
1889
1890 // If all the data was buffered, we are done:
1891 if (remaining == 0) {
1892 return length;
1893 }
1894 }
1895
1896 // Otherwise, we should write the data directly:
1897 return rb_io_write_memory(fptr, ptr, length);
1898}
1899#endif
1900
1901static VALUE
1902io_binwrite_string(VALUE arg)
1903{
1904 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1905
1906 const char *ptr = p->ptr;
1907 size_t remaining = p->length;
1908
1909 while (remaining) {
1910 // Write as much as possible:
1911 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1912
1913 if (result == 0) {
1914 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1915 // should try again immediately.
1916 }
1917 else if (result > 0) {
1918 if ((size_t)result == remaining) break;
1919 ptr += result;
1920 remaining -= result;
1921 }
1922 // Wait for it to become writable:
1923 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1924 rb_io_check_closed(p->fptr);
1925 }
1926 else {
1927 // The error was unrelated to waiting for it to become writable, so we fail:
1928 return -1;
1929 }
1930 }
1931
1932 return p->length;
1933}
1934
1935inline static void
1936io_allocate_write_buffer(rb_io_t *fptr, int sync)
1937{
1938 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1939 fptr->wbuf.off = 0;
1940 fptr->wbuf.len = 0;
1941 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1942 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1943 }
1944
1945 if (NIL_P(fptr->write_lock)) {
1946 fptr->write_lock = rb_mutex_new();
1947 rb_mutex_allow_trap(fptr->write_lock, 1);
1948 }
1949}
1950
1951static inline int
1952io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1953{
1954 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1955 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1956 return 1;
1957
1958 // If the amount of data we want to write exceeds the internal buffer:
1959 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1960 return 1;
1961
1962 // Otherwise, we can append to the internal buffer:
1963 return 0;
1964}
1965
1966static long
1967io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1968{
1969 if (len <= 0) return len;
1970
1971 // Don't write anything if current thread has a pending interrupt:
1973
1974 io_allocate_write_buffer(fptr, !nosync);
1975
1976 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1977 struct binwrite_arg arg;
1978
1979 arg.fptr = fptr;
1980 arg.ptr = ptr;
1981 arg.length = len;
1982
1983 if (!NIL_P(fptr->write_lock)) {
1984 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1985 }
1986 else {
1987 return io_binwrite_string((VALUE)&arg);
1988 }
1989 }
1990 else {
1991 if (fptr->wbuf.off) {
1992 if (fptr->wbuf.len)
1993 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1994 fptr->wbuf.off = 0;
1995 }
1996
1997 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1998 fptr->wbuf.len += (int)len;
1999
2000 return len;
2001 }
2002}
2003
2004# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
2005 (fmode & FMODE_TEXTMODE) ? (c) : (a))
2006
2007#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
2008 MODE_BTMODE(d, e, f) : \
2009 MODE_BTMODE(a, b, c))
2010
2011static VALUE
2012do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
2013{
2014 if (NEED_WRITECONV(fptr)) {
2015 VALUE common_encoding = Qnil;
2016 SET_BINARY_MODE(fptr);
2017
2018 make_writeconv(fptr);
2019
2020 if (fptr->writeconv) {
2021#define fmode (fptr->mode)
2022 if (!NIL_P(fptr->writeconv_asciicompat))
2023 common_encoding = fptr->writeconv_asciicompat;
2024 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
2025 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2026 rb_enc_name(rb_enc_get(str)));
2027 }
2028#undef fmode
2029 }
2030 else {
2031 if (fptr->encs.enc2)
2032 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
2033 else if (fptr->encs.enc != rb_ascii8bit_encoding())
2034 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
2035 }
2036
2037 if (!NIL_P(common_encoding)) {
2038 str = rb_str_encode(str, common_encoding,
2040 *converted = 1;
2041 }
2042
2043 if (fptr->writeconv) {
2045 *converted = 1;
2046 }
2047 }
2048#if RUBY_CRLF_ENVIRONMENT
2049#define fmode (fptr->mode)
2050 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2051 if ((fptr->mode & FMODE_READABLE) &&
2053 setmode(fptr->fd, O_BINARY);
2054 }
2055 else {
2056 setmode(fptr->fd, O_TEXT);
2057 }
2058 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2059 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2060 rb_enc_name(rb_enc_get(str)));
2061 }
2062 }
2063#undef fmode
2064#endif
2065 return str;
2066}
2067
2068static long
2069io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
2070{
2071 int converted = 0;
2072 VALUE tmp;
2073 long n, len;
2074 const char *ptr;
2075
2076#ifdef _WIN32
2077 if (fptr->mode & FMODE_TTY) {
2078 if (rb_w32_write_console(str, fptr->fd) > 0) return RSTRING_LEN(str);
2079 }
2080#endif
2081
2082 str = do_writeconv(str, fptr, &converted);
2083 if (converted)
2084 OBJ_FREEZE(str);
2085
2086 tmp = rb_str_no_gvl_safe_acquire(str);
2087 RSTRING_GETMEM(tmp, ptr, len);
2088 n = io_binwrite(ptr, len, fptr, nosync);
2090
2091 return n;
2092}
2093
2094ssize_t
2095rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2096{
2097 rb_io_t *fptr;
2098
2099 GetOpenFile(io, fptr);
2101 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2102}
2103
2104static VALUE
2105io_write(VALUE io, VALUE str, int nosync)
2106{
2107 rb_io_t *fptr;
2108 long n;
2109 VALUE tmp;
2110
2111 io = GetWriteIO(io);
2112 str = rb_obj_as_string(str);
2113 tmp = rb_io_check_io(io);
2114
2115 if (NIL_P(tmp)) {
2116 /* port is not IO, call write method for it. */
2117 return rb_funcall(io, id_write, 1, str);
2118 }
2119
2120 io = tmp;
2121 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2122
2123 GetOpenFile(io, fptr);
2125
2126 n = io_fwrite(str, fptr, nosync);
2127 if (n < 0L) rb_sys_fail_on_write(fptr);
2128
2129 return LONG2FIX(n);
2130}
2131
2132#ifdef HAVE_WRITEV
2133struct binwritev_arg {
2134 rb_io_t *fptr;
2135 struct iovec *iov;
2136 int iovcnt;
2137 size_t total;
2138};
2139
2140static VALUE
2141io_binwritev_internal(VALUE arg)
2142{
2143 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2144
2145 size_t remaining = p->total;
2146 size_t offset = 0;
2147
2148 rb_io_t *fptr = p->fptr;
2149 struct iovec *iov = p->iov;
2150 int iovcnt = p->iovcnt;
2151
2152 while (remaining) {
2153 long result = rb_writev_internal(fptr, iov, iovcnt);
2154
2155 if (result >= 0) {
2156 offset += result;
2157 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2158 if (offset < (size_t)fptr->wbuf.len) {
2159 fptr->wbuf.off += result;
2160 fptr->wbuf.len -= result;
2161 }
2162 else {
2163 offset -= (size_t)fptr->wbuf.len;
2164 fptr->wbuf.off = 0;
2165 fptr->wbuf.len = 0;
2166 }
2167 }
2168
2169 if (offset == p->total) {
2170 return p->total;
2171 }
2172
2173 while (result >= (ssize_t)iov->iov_len) {
2174 /* iovcnt > 0 */
2175 result -= iov->iov_len;
2176 iov->iov_len = 0;
2177 iov++;
2178
2179 if (!--iovcnt) {
2180 // I don't believe this code path can ever occur.
2181 return offset;
2182 }
2183 }
2184
2185 iov->iov_base = (char *)iov->iov_base + result;
2186 iov->iov_len -= result;
2187 }
2188 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2189 rb_io_check_closed(fptr);
2190 }
2191 else {
2192 return -1;
2193 }
2194 }
2195
2196 return offset;
2197}
2198
2199static long
2200io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2201{
2202 // Don't write anything if current thread has a pending interrupt:
2204
2205 if (iovcnt == 0) return 0;
2206
2207 size_t total = 0;
2208 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2209
2210 io_allocate_write_buffer(fptr, 1);
2211
2212 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2213 // The end of the buffered data:
2214 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2215
2216 if (offset + total <= (size_t)fptr->wbuf.capa) {
2217 for (int i = 1; i < iovcnt; i++) {
2218 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2219 offset += iov[i].iov_len;
2220 }
2221
2222 fptr->wbuf.len += total;
2223
2224 /* io_binwritev is only reached in sync/TTY mode (it is called only
2225 * from io_fwritev, which io_writev uses only when FMODE_SYNC or
2226 * FMODE_TTY is set), so the coalesced data must be flushed
2227 * immediately rather than left in the buffer until the next flush
2228 * or close. Otherwise a multi-argument write with many arguments
2229 * would not be observably atomic under sync. */
2230 if (io_fflush(fptr) < 0) return -1;
2231
2232 return total;
2233 }
2234 else {
2235 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2236 iov[0].iov_len = fptr->wbuf.len;
2237 }
2238 }
2239 else {
2240 // The first iov is reserved for the internal buffer, and it's empty.
2241 iov++;
2242
2243 if (!--iovcnt) {
2244 // If there are no other io vectors we are done.
2245 return 0;
2246 }
2247 }
2248
2249 struct binwritev_arg arg;
2250 arg.fptr = fptr;
2251 arg.iov = iov;
2252 arg.iovcnt = iovcnt;
2253 arg.total = total;
2254
2255 if (!NIL_P(fptr->write_lock)) {
2256 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2257 }
2258 else {
2259 return io_binwritev_internal((VALUE)&arg);
2260 }
2261}
2262
2263static long
2264io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2265{
2266 int i, converted, iovcnt = argc + 1;
2267 long n;
2268 VALUE v1, v2, str, tmp, *tmp_array;
2269 struct iovec *iov;
2270
2271 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2272 tmp_array = ALLOCV_N(VALUE, v2, argc);
2273
2274 for (i = 0; i < argc; i++) {
2275 str = rb_obj_as_string(argv[i]);
2276 converted = 0;
2277 str = do_writeconv(str, fptr, &converted);
2278
2279 if (converted)
2280 OBJ_FREEZE(str);
2281
2282 tmp = rb_str_tmp_frozen_acquire(str);
2283 tmp_array[i] = tmp;
2284
2285 /* iov[0] is reserved for buffer of fptr */
2286 iov[i+1].iov_base = RSTRING_PTR(tmp);
2287 iov[i+1].iov_len = RSTRING_LEN(tmp);
2288 }
2289
2290 n = io_binwritev(iov, iovcnt, fptr);
2291 if (v1) ALLOCV_END(v1);
2292
2293 for (i = 0; i < argc; i++) {
2294 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2295 }
2296
2297 if (v2) ALLOCV_END(v2);
2298
2299 return n;
2300}
2301
2302static int
2303iovcnt_ok(int iovcnt)
2304{
2305#ifdef IOV_MAX
2306 return iovcnt < IOV_MAX;
2307#else /* GNU/Hurd has writev, but no IOV_MAX */
2308 return 1;
2309#endif
2310}
2311#endif /* HAVE_WRITEV */
2312
2313static VALUE
2314io_writev(int argc, const VALUE *argv, VALUE io)
2315{
2316 rb_io_t *fptr;
2317 long n;
2318 VALUE tmp, total = INT2FIX(0);
2319 int i, cnt = 1;
2320
2321 io = GetWriteIO(io);
2322 tmp = rb_io_check_io(io);
2323
2324 if (NIL_P(tmp)) {
2325 /* port is not IO, call write method for it. */
2326 return rb_funcallv(io, id_write, argc, argv);
2327 }
2328
2329 io = tmp;
2330
2331 GetOpenFile(io, fptr);
2333
2334 for (i = 0; i < argc; i += cnt) {
2335#ifdef HAVE_WRITEV
2336 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2337 n = io_fwritev(cnt, &argv[i], fptr);
2338 }
2339 else
2340#endif
2341 {
2342 cnt = 1;
2343 /* sync at last item */
2344 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2345 }
2346
2347 if (n < 0L)
2348 rb_sys_fail_on_write(fptr);
2349
2350 total = rb_fix_plus(LONG2FIX(n), total);
2351 }
2352
2353 return total;
2354}
2355
2356/*
2357 * call-seq:
2358 * write(*objects) -> integer
2359 *
2360 * Writes each of the given +objects+ to +self+,
2361 * which must be opened for writing
2362 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2363 * returns the total number bytes written;
2364 * each of +objects+ that is not a string is converted via method +to_s+:
2365 *
2366 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2367 * $stdout.write('foo', :bar, 2, "\n") # => 8
2368 *
2369 * Output:
2370 *
2371 * Hello, World!
2372 * foobar2
2373 *
2374 * Related: IO#read.
2375 */
2376
2377static VALUE
2378io_write_m(int argc, VALUE *argv, VALUE io)
2379{
2380 if (argc != 1) {
2381 return io_writev(argc, argv, io);
2382 }
2383 else {
2384 VALUE str = argv[0];
2385 return io_write(io, str, 0);
2386 }
2387}
2388
2389VALUE
2390rb_io_write(VALUE io, VALUE str)
2391{
2392 return rb_funcallv(io, id_write, 1, &str);
2393}
2394
2395static VALUE
2396rb_io_writev(VALUE io, int argc, const VALUE *argv)
2397{
2398 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2399 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2400 VALUE klass = CLASS_OF(io);
2401 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2403 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2404 " which accepts just one argument",
2405 klass, sep
2406 );
2407 }
2408
2409 do rb_io_write(io, *argv++); while (--argc);
2410
2411 return Qnil;
2412 }
2413
2414 return rb_funcallv(io, id_write, argc, argv);
2415}
2416
2417/*
2418 * call-seq:
2419 * self << object -> self
2420 *
2421 * Writes the given +object+ to +self+,
2422 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2423 * returns +self+;
2424 * if +object+ is not a string, it is converted via method +to_s+:
2425 *
2426 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2427 * $stdout << 'foo' << :bar << 2 << "\n"
2428 *
2429 * Output:
2430 *
2431 * Hello, World!
2432 * foobar2
2433 *
2434 */
2435
2436
2437VALUE
2439{
2440 rb_io_write(io, str);
2441 return io;
2442}
2443
2444#ifdef HAVE_FSYNC
2445static VALUE
2446nogvl_fsync(void *ptr)
2447{
2448 rb_io_t *fptr = ptr;
2449
2450#ifdef _WIN32
2451 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2452 return 0;
2453#endif
2454 return (VALUE)fsync(fptr->fd);
2455}
2456#endif
2457
2458VALUE
2459rb_io_flush_raw(VALUE io, int sync)
2460{
2461 rb_io_t *fptr;
2462
2463 if (!RB_TYPE_P(io, T_FILE)) {
2464 return rb_funcall(io, id_flush, 0);
2465 }
2466
2467 io = GetWriteIO(io);
2468 GetOpenFile(io, fptr);
2469
2470 if (fptr->mode & FMODE_WRITABLE) {
2471 if (io_fflush(fptr) < 0)
2472 rb_sys_fail_on_write(fptr);
2473 }
2474 if (fptr->mode & FMODE_READABLE) {
2475 io_unread(fptr, true);
2476 }
2477
2478 return io;
2479}
2480
2481/*
2482 * call-seq:
2483 * flush -> self
2484 *
2485 * Flushes data buffered in +self+ to the operating system
2486 * (but does not necessarily flush data buffered in the operating system):
2487 *
2488 * $stdout.print 'no newline' # Not necessarily flushed.
2489 * $stdout.flush # Flushed.
2490 *
2491 */
2492
2493VALUE
2494rb_io_flush(VALUE io)
2495{
2496 return rb_io_flush_raw(io, 1);
2497}
2498
2499/*
2500 * call-seq:
2501 * tell -> integer
2502 *
2503 * Returns the current position (in bytes) in +self+
2504 * (see {Position}[rdoc-ref:IO@Position]):
2505 *
2506 * f = File.open('t.txt')
2507 * f.tell # => 0
2508 * f.gets # => "First line\n"
2509 * f.tell # => 12
2510 * f.close
2511 *
2512 * Related: IO#pos=, IO#seek.
2513 */
2514
2515static VALUE
2516rb_io_tell(VALUE io)
2517{
2518 rb_io_t *fptr;
2519 rb_off_t pos;
2520
2521 GetOpenFile(io, fptr);
2522 pos = io_tell(fptr);
2523 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2524 pos -= fptr->rbuf.len;
2525 return OFFT2NUM(pos);
2526}
2527
2528static VALUE
2529rb_io_seek(VALUE io, VALUE offset, int whence)
2530{
2531 rb_io_t *fptr;
2532 rb_off_t pos;
2533
2534 pos = NUM2OFFT(offset);
2535 GetOpenFile(io, fptr);
2536 pos = io_seek(fptr, pos, whence);
2537 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2538 if (fptr->readconv) clear_readconv(fptr);
2539
2540 return INT2FIX(0);
2541}
2542
2543static int
2544interpret_seek_whence(VALUE vwhence)
2545{
2546 if (vwhence == sym_SET)
2547 return SEEK_SET;
2548 if (vwhence == sym_CUR)
2549 return SEEK_CUR;
2550 if (vwhence == sym_END)
2551 return SEEK_END;
2552#ifdef SEEK_DATA
2553 if (vwhence == sym_DATA)
2554 return SEEK_DATA;
2555#endif
2556#ifdef SEEK_HOLE
2557 if (vwhence == sym_HOLE)
2558 return SEEK_HOLE;
2559#endif
2560 return NUM2INT(vwhence);
2561}
2562
2563/*
2564 * call-seq:
2565 * seek(offset, whence = IO::SEEK_SET) -> 0
2566 *
2567 * Seeks to the position given by integer +offset+
2568 * (see {Position}[rdoc-ref:IO@Position])
2569 * and constant +whence+, which is one of:
2570 *
2571 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2572 * Repositions the stream to its current position plus the given +offset+:
2573 *
2574 * f = File.open('t.txt')
2575 * f.tell # => 0
2576 * f.seek(20, :CUR) # => 0
2577 * f.tell # => 20
2578 * f.seek(-10, :CUR) # => 0
2579 * f.tell # => 10
2580 * f.close
2581 *
2582 * - +:END+ or <tt>IO::SEEK_END</tt>:
2583 * Repositions the stream to its end plus the given +offset+:
2584 *
2585 * f = File.open('t.txt')
2586 * f.tell # => 0
2587 * f.seek(0, :END) # => 0 # Repositions to stream end.
2588 * f.tell # => 52
2589 * f.seek(-20, :END) # => 0
2590 * f.tell # => 32
2591 * f.seek(-40, :END) # => 0
2592 * f.tell # => 12
2593 * f.close
2594 *
2595 * - +:SET+ or <tt>IO::SEEK_SET</tt>:
2596 * Repositions the stream to the given +offset+:
2597 *
2598 * f = File.open('t.txt')
2599 * f.tell # => 0
2600 * f.seek(20, :SET) # => 0
2601 * f.tell # => 20
2602 * f.seek(40, :SET) # => 0
2603 * f.tell # => 40
2604 * f.close
2605 *
2606 * Related: IO#pos=, IO#tell.
2607 *
2608 */
2609
2610static VALUE
2611rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2612{
2613 VALUE offset, ptrname;
2614 int whence = SEEK_SET;
2615
2616 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2617 whence = interpret_seek_whence(ptrname);
2618 }
2619
2620 return rb_io_seek(io, offset, whence);
2621}
2622
2623/*
2624 * call-seq:
2625 * pos = new_position -> new_position
2626 *
2627 * Seeks to the given +new_position+ (in bytes);
2628 * see {Position}[rdoc-ref:IO@Position]:
2629 *
2630 * f = File.open('t.txt')
2631 * f.tell # => 0
2632 * f.pos = 20 # => 20
2633 * f.tell # => 20
2634 * f.close
2635 *
2636 * Related: IO#seek, IO#tell.
2637 *
2638 */
2639
2640static VALUE
2641rb_io_set_pos(VALUE io, VALUE offset)
2642{
2643 rb_io_t *fptr;
2644 rb_off_t pos;
2645
2646 pos = NUM2OFFT(offset);
2647 GetOpenFile(io, fptr);
2648 pos = io_seek(fptr, pos, SEEK_SET);
2649 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2650 if (fptr->readconv) clear_readconv(fptr);
2651
2652 return OFFT2NUM(pos);
2653}
2654
2655/*
2656 * call-seq:
2657 * rewind -> 0
2658 *
2659 * Repositions the stream to its beginning,
2660 * setting both the position and the line number to zero;
2661 * see {Position}[rdoc-ref:IO@Position]
2662 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2663 *
2664 * f = File.open('t.txt')
2665 * f.tell # => 0
2666 * f.lineno # => 0
2667 * f.gets # => "First line\n"
2668 * f.tell # => 12
2669 * f.lineno # => 1
2670 * f.rewind # => 0
2671 * f.tell # => 0
2672 * f.lineno # => 0
2673 * f.close
2674 *
2675 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2676 *
2677 */
2678
2679static VALUE
2680rb_io_rewind(VALUE io)
2681{
2682 rb_io_t *fptr;
2683
2684 GetOpenFile(io, fptr);
2685 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2686 if (io == ARGF.current_file) {
2687 ARGF.lineno -= fptr->lineno;
2688 }
2689 fptr->lineno = 0;
2690 if (fptr->readconv) {
2691 clear_readconv(fptr);
2692 }
2693
2694 return INT2FIX(0);
2695}
2696
2697static int
2698fptr_wait_readable(rb_io_t *fptr)
2699{
2700 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2701
2702 if (result)
2703 rb_io_check_closed(fptr);
2704
2705 return result;
2706}
2707
2708static int
2709io_fillbuf(rb_io_t *fptr)
2710{
2711 ssize_t r;
2712
2713 if (fptr->rbuf.ptr == NULL) {
2714 fptr->rbuf.off = 0;
2715 fptr->rbuf.len = 0;
2716 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2717 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2718 }
2719 if (fptr->rbuf.len == 0) {
2720 retry:
2721 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2722
2723 if (r < 0) {
2724 if (fptr_wait_readable(fptr))
2725 goto retry;
2726
2727 int e = errno;
2728 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2729 if (!NIL_P(fptr->pathv)) {
2730 rb_str_append(path, fptr->pathv);
2731 }
2732
2733 rb_syserr_fail_path(e, path);
2734 }
2735 if (r > 0) rb_io_check_closed(fptr);
2736 fptr->rbuf.off = 0;
2737 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2738 if (r == 0)
2739 return -1; /* EOF */
2740 }
2741 return 0;
2742}
2743
2744/*
2745 * call-seq:
2746 * eof -> true or false
2747 *
2748 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2749 * see {Position}[rdoc-ref:IO@Position]:
2750 *
2751 * f = File.open('t.txt')
2752 * f.eof # => false
2753 * f.seek(0, :END) # => 0
2754 * f.eof # => true
2755 * f.close
2756 *
2757 * Raises an exception unless the stream is opened for reading;
2758 * see {Mode}[rdoc-ref:File@Access+Modes].
2759 *
2760 * If +self+ is a stream such as pipe or socket, this method
2761 * blocks until the other end sends some data or closes it:
2762 *
2763 * r, w = IO.pipe
2764 * Thread.new { sleep 1; w.close }
2765 * r.eof? # => true # After 1-second wait.
2766 *
2767 * r, w = IO.pipe
2768 * Thread.new { sleep 1; w.puts "a" }
2769 * r.eof? # => false # After 1-second wait.
2770 *
2771 * r, w = IO.pipe
2772 * r.eof? # blocks forever
2773 *
2774 * Note that this method reads data to the input byte buffer. So
2775 * IO#sysread may not behave as you intend with IO#eof?, unless you
2776 * call IO#rewind first (which is not available for some streams).
2777 */
2778
2779VALUE
2781{
2782 rb_io_t *fptr;
2783
2784 GetOpenFile(io, fptr);
2786
2787 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2788 if (READ_DATA_PENDING(fptr)) return Qfalse;
2789 READ_CHECK(fptr);
2790#if RUBY_CRLF_ENVIRONMENT
2791 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2792 return RBOOL(eof(fptr->fd));
2793 }
2794#endif
2795 return RBOOL(io_fillbuf(fptr) < 0);
2796}
2797
2798/*
2799 * call-seq:
2800 * sync -> true or false
2801 *
2802 * Returns the current sync mode of the stream.
2803 * When sync mode is true, all output is immediately flushed to the underlying
2804 * operating system and is not buffered by Ruby internally. See also #fsync.
2805 *
2806 * f = File.open('t.tmp', 'w')
2807 * f.sync # => false
2808 * f.sync = true
2809 * f.sync # => true
2810 * f.close
2811 *
2812 */
2813
2814static VALUE
2815rb_io_sync(VALUE io)
2816{
2817 rb_io_t *fptr;
2818
2819 io = GetWriteIO(io);
2820 GetOpenFile(io, fptr);
2821 return RBOOL(fptr->mode & FMODE_SYNC);
2822}
2823
2824#ifdef HAVE_FSYNC
2825
2826/*
2827 * call-seq:
2828 * sync = boolean -> boolean
2829 *
2830 * Sets the _sync_ _mode_ for the stream to the given value;
2831 * returns the given value.
2832 *
2833 * Values for the sync mode:
2834 *
2835 * - +true+: All output is immediately flushed to the
2836 * underlying operating system and is not buffered internally.
2837 * - +false+: Output may be buffered internally.
2838 *
2839 * Example;
2840 *
2841 * f = File.open('t.tmp', 'w')
2842 * f.sync # => false
2843 * f.sync = true
2844 * f.sync # => true
2845 * f.close
2846 *
2847 * Related: IO#fsync.
2848 *
2849 */
2850
2851static VALUE
2852rb_io_set_sync(VALUE io, VALUE sync)
2853{
2854 rb_io_t *fptr;
2855
2856 io = GetWriteIO(io);
2857 GetOpenFile(io, fptr);
2858 if (RTEST(sync)) {
2859 fptr->mode |= FMODE_SYNC;
2860 }
2861 else {
2862 fptr->mode &= ~FMODE_SYNC;
2863 }
2864 return sync;
2865}
2866
2867/*
2868 * call-seq:
2869 * fsync -> 0
2870 *
2871 * Immediately writes to disk all data buffered in the stream,
2872 * via the operating system's <tt>fsync(2)</tt>.
2873
2874 * Note this difference:
2875 *
2876 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2877 * but does not guarantee that the operating system actually writes the data to disk.
2878 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2879 * and that data is written to disk.
2880 *
2881 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2882 *
2883 */
2884
2885static VALUE
2886rb_io_fsync(VALUE io)
2887{
2888 rb_io_t *fptr;
2889
2890 io = GetWriteIO(io);
2891 GetOpenFile(io, fptr);
2892
2893 if (io_fflush(fptr) < 0)
2894 rb_sys_fail_on_write(fptr);
2895
2896 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2897 rb_sys_fail_path(fptr->pathv);
2898
2899 return INT2FIX(0);
2900}
2901#else
2902# define rb_io_fsync rb_f_notimplement
2903# define rb_io_sync rb_f_notimplement
2904static VALUE
2905rb_io_set_sync(VALUE io, VALUE sync)
2906{
2907 rb_notimplement();
2909}
2910#endif
2911
2912#ifdef HAVE_FDATASYNC
2913static VALUE
2914nogvl_fdatasync(void *ptr)
2915{
2916 rb_io_t *fptr = ptr;
2917
2918 return (VALUE)fdatasync(fptr->fd);
2919}
2920
2921/*
2922 * call-seq:
2923 * fdatasync -> 0
2924 *
2925 * Immediately writes to disk all data buffered in the stream,
2926 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2927 * otherwise via <tt>fsync(2)</tt>, if supported;
2928 * otherwise raises an exception.
2929 *
2930 */
2931
2932static VALUE
2933rb_io_fdatasync(VALUE io)
2934{
2935 rb_io_t *fptr;
2936
2937 io = GetWriteIO(io);
2938 GetOpenFile(io, fptr);
2939
2940 if (io_fflush(fptr) < 0)
2941 rb_sys_fail_on_write(fptr);
2942
2943 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2944 return INT2FIX(0);
2945
2946 /* fall back */
2947 return rb_io_fsync(io);
2948}
2949#else
2950#define rb_io_fdatasync rb_io_fsync
2951#endif
2952
2953/*
2954 * call-seq:
2955 * fileno -> integer
2956 *
2957 * Returns the integer file descriptor for the stream:
2958 *
2959 * $stdin.fileno # => 0
2960 * $stdout.fileno # => 1
2961 * $stderr.fileno # => 2
2962 * File.open('t.txt').fileno # => 10
2963 * f.close
2964 *
2965 */
2966
2967static VALUE
2968rb_io_fileno(VALUE io)
2969{
2970 rb_io_t *fptr = RFILE(io)->fptr;
2971 int fd;
2972
2973 rb_io_check_closed(fptr);
2974 fd = fptr->fd;
2975 return INT2FIX(fd);
2976}
2977
2978int
2980{
2981 if (RB_TYPE_P(io, T_FILE)) {
2982 rb_io_t *fptr = RFILE(io)->fptr;
2983 rb_io_check_closed(fptr);
2984 return fptr->fd;
2985 }
2986 else {
2987 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2988 if (!UNDEF_P(fileno)) {
2989 return RB_NUM2INT(fileno);
2990 }
2991 }
2992
2993 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2994
2996}
2997
2998int
2999rb_io_mode(VALUE io)
3000{
3001 rb_io_t *fptr;
3002 GetOpenFile(io, fptr);
3003 return fptr->mode;
3004}
3005
3006/*
3007 * call-seq:
3008 * pid -> integer or nil
3009 *
3010 * Returns the process ID of a child process associated with the stream,
3011 * which will have been set by IO#popen, or +nil+ if the stream was not
3012 * created by IO#popen:
3013 *
3014 * pipe = IO.popen("-")
3015 * if pipe
3016 * $stderr.puts "In parent, child pid is #{pipe.pid}"
3017 * else
3018 * $stderr.puts "In child, pid is #{$$}"
3019 * end
3020 *
3021 * Output:
3022 *
3023 * In child, pid is 26209
3024 * In parent, child pid is 26209
3025 *
3026 */
3027
3028static VALUE
3029rb_io_pid(VALUE io)
3030{
3031 rb_io_t *fptr;
3032
3033 GetOpenFile(io, fptr);
3034 if (!fptr->pid)
3035 return Qnil;
3036 return PIDT2NUM(fptr->pid);
3037}
3038
3039/*
3040 * :markup: markdown
3041 *
3042 * call-seq:
3043 * path -> string or nil
3044 *
3045 * Returns the string path associated with `self`,
3046 * or `nil` if there is no associated path:
3047 *
3048 * ```ruby
3049 * path = 'doc/maintainers.md'
3050 * fd = File.open(path).fileno # => 6
3051 * IO.new(fd, path: path).path # => "doc/maintainers.md"
3052 * IO.new(fd).path # => nil
3053 * ```
3054 *
3055 */
3056
3057VALUE
3059{
3060 rb_io_t *fptr = RFILE(io)->fptr;
3061
3062 if (!fptr)
3063 return Qnil;
3064
3065 return rb_obj_dup(fptr->pathv);
3066}
3067
3068/*
3069 * call-seq:
3070 * inspect -> string
3071 *
3072 * Returns a string representation of +self+:
3073 *
3074 * f = File.open('t.txt')
3075 * f.inspect # => "#<File:t.txt>"
3076 * f.close
3077 *
3078 */
3079
3080static VALUE
3081rb_io_inspect(VALUE obj)
3082{
3083 rb_io_t *fptr;
3084 VALUE result;
3085 static const char closed[] = " (closed)";
3086
3087 fptr = RFILE(obj)->fptr;
3088 if (!fptr) return rb_any_to_s(obj);
3089 result = rb_str_new_cstr("#<");
3090 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3091 rb_str_cat2(result, ":");
3092 if (NIL_P(fptr->pathv)) {
3093 if (fptr->fd < 0) {
3094 rb_str_cat(result, closed+1, strlen(closed)-1);
3095 }
3096 else {
3097 rb_str_catf(result, "fd %d", fptr->fd);
3098 }
3099 }
3100 else {
3101 rb_str_append(result, fptr->pathv);
3102 if (fptr->fd < 0) {
3103 rb_str_cat(result, closed, strlen(closed));
3104 }
3105 }
3106 return rb_str_cat2(result, ">");
3107}
3108
3109/*
3110 * call-seq:
3111 * to_io -> self
3112 *
3113 * Returns +self+.
3114 *
3115 */
3116
3117static VALUE
3118rb_io_to_io(VALUE io)
3119{
3120 return io;
3121}
3122
3123/* reading functions */
3124static long
3125read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3126{
3127 int n;
3128
3129 n = READ_DATA_PENDING_COUNT(fptr);
3130 if (n <= 0) return 0;
3131 if (n > len) n = (int)len;
3132 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3133 fptr->rbuf.off += n;
3134 fptr->rbuf.len -= n;
3135 return n;
3136}
3137
3138static long
3139io_bufread(char *ptr, long len, rb_io_t *fptr, long *read_len)
3140{
3141 long offset = 0;
3142 long n = len;
3143 long c;
3144
3145 *read_len = 0;
3146 if (READ_DATA_PENDING(fptr) == 0) {
3147 while (n > 0) {
3148 again:
3149 rb_io_check_closed(fptr);
3150 c = rb_io_read_memory(fptr, ptr+offset, n);
3151 if (c == 0) break;
3152 if (c < 0) {
3153 if (fptr_wait_readable(fptr))
3154 goto again;
3155 return -1;
3156 }
3157 offset += c;
3158 *read_len = offset;
3159 if ((n -= c) <= 0) break;
3160 }
3161 return len - n;
3162 }
3163
3164 while (n > 0) {
3165 c = read_buffered_data(ptr+offset, n, fptr);
3166 if (c > 0) {
3167 offset += c;
3168 *read_len = offset;
3169 if ((n -= c) <= 0) break;
3170 }
3171 rb_io_check_closed(fptr);
3172 if (io_fillbuf(fptr) < 0) {
3173 break;
3174 }
3175 }
3176 return len - n;
3177}
3178
3179static int io_setstrbuf(VALUE *str, long len);
3180
3182 char *str_ptr;
3183 long offset;
3184 long len;
3185 long read_len;
3186 rb_io_t *fptr;
3187};
3188
3189static VALUE
3190bufread_body(VALUE arg)
3191{
3192 struct bufread_arg *p = (struct bufread_arg *)arg;
3193 p->len = io_bufread(p->str_ptr + p->offset, p->len, p->fptr, &p->read_len);
3194 return Qundef;
3195}
3196
3197static VALUE
3198bufread_timeout(VALUE arg, VALUE error)
3199{
3200 struct bufread_arg *p = (struct bufread_arg *)arg;
3201
3202 if (p->offset + p->read_len > 0) {
3203 VALUE str = rb_str_new(p->str_ptr, p->offset + p->read_len);
3204 io_restore_read_buffer(str, p->fptr);
3205 }
3206 rb_exc_raise(error);
3208}
3209
3210static VALUE
3211bufread_call(VALUE arg)
3212{
3213 struct bufread_arg *p = (struct bufread_arg *)arg;
3214
3215 if (NIL_P(p->fptr->timeout)) {
3216 return bufread_body(arg);
3217 }
3218 return rb_rescue2(bufread_body, arg, bufread_timeout, arg,
3219 rb_eIOTimeoutError, (VALUE)0);
3220}
3221
3222static long
3223io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3224{
3225 long len;
3226 struct bufread_arg arg;
3227
3228 io_setstrbuf(&str, offset + size);
3229 arg.str_ptr = RSTRING_PTR(str);
3230 arg.offset = offset;
3231 arg.len = size;
3232 arg.read_len = 0;
3233 arg.fptr = fptr;
3234 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3235 len = arg.len;
3236 if (len < 0) rb_sys_fail_path(fptr->pathv);
3237 return len;
3238}
3239
3240static long
3241remain_size(rb_io_t *fptr)
3242{
3243 struct stat st;
3244 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3245 rb_off_t pos;
3246
3247 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3248#if defined(__HAIKU__)
3249 && (st.st_dev > 3)
3250#endif
3251 )
3252 {
3253 if (io_fflush(fptr) < 0)
3254 rb_sys_fail_on_write(fptr);
3255 pos = lseek(fptr->fd, 0, SEEK_CUR);
3256 if (st.st_size >= pos && pos >= 0) {
3257 siz += st.st_size - pos;
3258 if (siz > LONG_MAX) {
3259 rb_raise(rb_eIOError, "file too big for single read");
3260 }
3261 }
3262 }
3263 else {
3264 siz += BUFSIZ;
3265 }
3266 return (long)siz;
3267}
3268
3269static VALUE
3270io_enc_str(VALUE str, rb_io_t *fptr)
3271{
3272 rb_enc_associate(str, io_read_encoding(fptr));
3273 return str;
3274}
3275
3276static void
3277make_readconv(rb_io_t *fptr, int size)
3278{
3279 if (!fptr->readconv) {
3280 int ecflags;
3281 VALUE ecopts;
3282 const char *sname, *dname;
3283 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3284 ecopts = fptr->encs.ecopts;
3285 if (fptr->encs.enc2) {
3286 sname = rb_enc_name(fptr->encs.enc2);
3287 dname = rb_enc_name(io_read_encoding(fptr));
3288 }
3289 else {
3290 sname = dname = "";
3291 }
3292 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3293 if (!fptr->readconv)
3294 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3295 fptr->cbuf.off = 0;
3296 fptr->cbuf.len = 0;
3297 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3298 fptr->cbuf.capa = size;
3299 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3300 }
3301}
3302
3303#define MORE_CHAR_SUSPENDED Qtrue
3304#define MORE_CHAR_FINISHED Qnil
3305static VALUE
3306fill_cbuf(rb_io_t *fptr, int ec_flags)
3307{
3308 const unsigned char *ss, *sp, *se;
3309 unsigned char *ds, *dp, *de;
3311 int putbackable;
3312 int cbuf_len0;
3313 VALUE exc;
3314
3315 ec_flags |= ECONV_PARTIAL_INPUT;
3316
3317 if (fptr->cbuf.len == fptr->cbuf.capa)
3318 return MORE_CHAR_SUSPENDED; /* cbuf full */
3319 if (fptr->cbuf.len == 0)
3320 fptr->cbuf.off = 0;
3321 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3322 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3323 fptr->cbuf.off = 0;
3324 }
3325
3326 cbuf_len0 = fptr->cbuf.len;
3327
3328 while (1) {
3329 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3330 se = sp + fptr->rbuf.len;
3331 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3332 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3333 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3334 fptr->rbuf.off += (int)(sp - ss);
3335 fptr->rbuf.len -= (int)(sp - ss);
3336 fptr->cbuf.len += (int)(dp - ds);
3337
3338 putbackable = rb_econv_putbackable(fptr->readconv);
3339 if (putbackable) {
3340 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3341 fptr->rbuf.off -= putbackable;
3342 fptr->rbuf.len += putbackable;
3343 }
3344
3345 exc = rb_econv_make_exception(fptr->readconv);
3346 if (!NIL_P(exc))
3347 return exc;
3348
3349 if (cbuf_len0 != fptr->cbuf.len)
3350 return MORE_CHAR_SUSPENDED;
3351
3352 if (res == econv_finished) {
3353 return MORE_CHAR_FINISHED;
3354 }
3355
3356 if (res == econv_source_buffer_empty) {
3357 if (fptr->rbuf.len == 0) {
3358 READ_CHECK(fptr);
3359 if (io_fillbuf(fptr) < 0) {
3360 if (!fptr->readconv) {
3361 return MORE_CHAR_FINISHED;
3362 }
3363 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3364 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3365 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3366 fptr->cbuf.len += (int)(dp - ds);
3368 break;
3369 }
3370 }
3371 }
3372 }
3373 if (cbuf_len0 != fptr->cbuf.len)
3374 return MORE_CHAR_SUSPENDED;
3375
3376 return MORE_CHAR_FINISHED;
3377}
3378
3379static VALUE
3380more_char(rb_io_t *fptr)
3381{
3382 VALUE v;
3383 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3384 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3385 rb_exc_raise(v);
3386 return v;
3387}
3388
3389static VALUE
3390io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3391{
3392 VALUE str = Qnil;
3393 if (strp) {
3394 str = *strp;
3395 if (NIL_P(str)) {
3396 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3397 }
3398 else {
3399 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3400 }
3401 rb_enc_associate(str, fptr->encs.enc);
3402 }
3403 fptr->cbuf.off += len;
3404 fptr->cbuf.len -= len;
3405 /* xxx: set coderange */
3406 if (fptr->cbuf.len == 0)
3407 fptr->cbuf.off = 0;
3408 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3409 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3410 fptr->cbuf.off = 0;
3411 }
3412 return str;
3413}
3414
3415static int
3416io_setstrbuf(VALUE *str, long len)
3417{
3418 if (NIL_P(*str)) {
3419 *str = rb_str_new(0, len);
3420 return TRUE;
3421 }
3422 else {
3423 VALUE s = StringValue(*str);
3424 rb_str_modify(s);
3425
3426 long clen = RSTRING_LEN(s);
3427 if (clen >= len) {
3428 return FALSE;
3429 }
3430 len -= clen;
3431 }
3432 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3434 }
3435 return FALSE;
3436}
3437
3438#define MAX_REALLOC_GAP 4096
3439static void
3440io_shrink_read_string(VALUE str, long n)
3441{
3442 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3443 rb_str_resize(str, n);
3444 }
3445}
3446
3447static void
3448io_set_read_length(VALUE str, long n, int shrinkable)
3449{
3450 if (RSTRING_LEN(str) != n) {
3451 rb_str_modify(str);
3452 rb_str_set_len(str, n);
3453 if (shrinkable) io_shrink_read_string(str, n);
3454 }
3455}
3456
3457static VALUE
3458read_all(rb_io_t *fptr, long siz, VALUE str)
3459{
3460 long bytes;
3461 long n;
3462 long pos;
3463 rb_encoding *enc;
3464 int cr;
3465 int shrinkable;
3466
3467 if (NEED_READCONV(fptr)) {
3468 int first = !NIL_P(str);
3469 SET_BINARY_MODE(fptr);
3470 shrinkable = io_setstrbuf(&str,0);
3471 make_readconv(fptr, 0);
3472 while (1) {
3473 VALUE v;
3474 if (fptr->cbuf.len) {
3475 if (first) rb_str_set_len(str, first = 0);
3476 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3477 }
3478 v = fill_cbuf(fptr, 0);
3479 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3480 if (fptr->cbuf.len) {
3481 if (first) rb_str_set_len(str, first = 0);
3482 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3483 }
3484 rb_exc_raise(v);
3485 }
3486 if (v == MORE_CHAR_FINISHED) {
3487 clear_readconv(fptr);
3488 if (first) rb_str_set_len(str, first = 0);
3489 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3490 return io_enc_str(str, fptr);
3491 }
3492 }
3493 }
3494
3495 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3496 bytes = 0;
3497 pos = 0;
3498
3499 enc = io_read_encoding(fptr);
3500 cr = 0;
3501
3502 if (siz == 0) {
3503 siz = BUFSIZ;
3504 }
3505 else {
3506 // If `siz` is set, we got it from `stat(2)`.
3507 // We attempt to read one extra byte because:
3508 // - If the file was appended to since then, we'll continue reading.
3509 // - If the file is still the same length, we won't issue a second `io_fread`.
3510 siz++;
3511 }
3512 shrinkable = io_setstrbuf(&str, siz);
3513 for (;;) {
3514 READ_CHECK(fptr);
3515 n = io_fread(str, bytes, siz - bytes, fptr);
3516 if (n == 0 && bytes == 0) {
3517 rb_str_set_len(str, 0);
3518 break;
3519 }
3520 bytes += n;
3521 rb_str_set_len(str, bytes);
3522 if (cr != ENC_CODERANGE_BROKEN)
3523 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3524 if (bytes < siz) break;
3525 siz += BUFSIZ;
3526
3527 size_t capa = rb_str_capacity(str);
3528 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3529 if (capa < BUFSIZ) {
3530 capa = BUFSIZ;
3531 }
3532 else if (capa > IO_MAX_BUFFER_GROWTH) {
3533 capa = IO_MAX_BUFFER_GROWTH;
3534 }
3536 }
3537 }
3538 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3539 str = io_enc_str(str, fptr);
3540 ENC_CODERANGE_SET(str, cr);
3541 return str;
3542}
3543
3544void
3546{
3547 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3548 rb_sys_fail_path(fptr->pathv);
3549 }
3550}
3551
3552static VALUE
3553io_read_memory_call(VALUE arg)
3554{
3555 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3556
3557 VALUE scheduler = rb_fiber_scheduler_current();
3558 if (scheduler != Qnil) {
3559 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa);
3560
3561 if (!UNDEF_P(result)) {
3562 // This is actually returned as a pseudo-VALUE and later cast to a long:
3564 }
3565 }
3566
3567 if (iis->nonblock) {
3568 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3569 }
3570 else {
3571 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3572 }
3573}
3574
3575static long
3576io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3577{
3578 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3579}
3580
3581#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3582
3583static VALUE
3584io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3585{
3586 rb_io_t *fptr;
3587 VALUE length, str;
3588 long n, len;
3589 struct io_internal_read_struct iis;
3590 int shrinkable;
3591
3592 rb_scan_args(argc, argv, "11", &length, &str);
3593
3594 if ((len = NUM2LONG(length)) < 0) {
3595 rb_raise(rb_eArgError, "negative length %ld given", len);
3596 }
3597
3598 shrinkable = io_setstrbuf(&str, len);
3599
3600 GetOpenFile(io, fptr);
3602
3603 if (len == 0) {
3604 io_set_read_length(str, 0, shrinkable);
3605 return str;
3606 }
3607
3608 if (!nonblock)
3609 READ_CHECK(fptr);
3610 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3611 if (n <= 0) {
3612 again:
3613 if (nonblock) {
3614 rb_io_set_nonblock(fptr);
3615 }
3616 io_setstrbuf(&str, len);
3617 iis.th = rb_thread_current();
3618 iis.fptr = fptr;
3619 iis.nonblock = nonblock;
3620 iis.fd = fptr->fd;
3621 iis.buf = RSTRING_PTR(str);
3622 iis.capa = len;
3623 iis.timeout = NULL;
3624 n = io_read_memory_locktmp(str, &iis);
3625 if (n < 0) {
3626 int e = errno;
3627 if (!nonblock && fptr_wait_readable(fptr))
3628 goto again;
3629 if (nonblock && (io_again_p(e))) {
3630 if (no_exception)
3631 return sym_wait_readable;
3632 else
3633 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3634 e, "read would block");
3635 }
3636 rb_syserr_fail_path(e, fptr->pathv);
3637 }
3638 }
3639 io_set_read_length(str, n, shrinkable);
3640
3641 if (n == 0)
3642 return Qnil;
3643 else
3644 return str;
3645}
3646
3647/*
3648 * call-seq:
3649 * readpartial(maxlen) -> string
3650 * readpartial(maxlen, out_string) -> out_string
3651 *
3652 * Reads up to +maxlen+ bytes from the stream;
3653 * returns a string (either a new string or the given +out_string+).
3654 * Its encoding is:
3655 *
3656 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3657 * - ASCII-8BIT, otherwise.
3658 *
3659 * - Contains +maxlen+ bytes from the stream, if available.
3660 * - Otherwise contains all available bytes, if any available.
3661 * - Is an empty string if +maxlen+ is zero.
3662 *
3663 * With the single non-negative integer argument +maxlen+ given,
3664 * returns a new string:
3665 *
3666 * f = File.new('t.txt')
3667 * f.readpartial(20) # => "First line\nSecond l"
3668 * f.readpartial(20) # => "ine\n\nFourth line\n"
3669 * f.readpartial(20) # => "Fifth line\n"
3670 * f.readpartial(20) # Raises EOFError.
3671 * f.close
3672 *
3673 * With both argument +maxlen+ and string argument +out_string+ given,
3674 * returns modified +out_string+:
3675 *
3676 * f = File.new('t.txt')
3677 * s = 'foo'
3678 * f.readpartial(20, s) # => "First line\nSecond l"
3679 * s = 'bar'
3680 * f.readpartial(0, s) # => ""
3681 * f.close
3682 *
3683 * This method is useful for a stream such as a pipe, a socket, or a tty.
3684 * It blocks only when no data is immediately available.
3685 * This means that it blocks only when _all_ of the following are true:
3686 *
3687 * - The byte buffer in the stream is empty.
3688 * - The content of the stream is empty.
3689 * - The stream is not at EOF.
3690 *
3691 * When blocked, the method waits for either more data or EOF on the stream:
3692 *
3693 * - If more data is read, the method returns the data.
3694 * - If EOF is reached, the method raises EOFError.
3695 *
3696 * When not blocked, the method responds immediately:
3697 *
3698 * - Returns data from the buffer if there is any.
3699 * - Otherwise returns data from the stream if there is any.
3700 * - Otherwise raises EOFError if the stream has reached EOF.
3701 *
3702 * Note that this method is similar to sysread. The differences are:
3703 *
3704 * - If the byte buffer is not empty, read from the byte buffer
3705 * instead of "sysread for buffered IO (IOError)".
3706 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3707 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3708 * readpartial retries the system call.
3709 *
3710 * The latter means that readpartial is non-blocking-flag insensitive.
3711 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3712 * if the fd is blocking mode.
3713 *
3714 * Examples:
3715 *
3716 * # # Returned Buffer Content Pipe Content
3717 * r, w = IO.pipe #
3718 * w << 'abc' # "" "abc".
3719 * r.readpartial(4096) # => "abc" "" ""
3720 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3721 *
3722 * # # Returned Buffer Content Pipe Content
3723 * r, w = IO.pipe #
3724 * w << 'abc' # "" "abc"
3725 * w.close # "" "abc" EOF
3726 * r.readpartial(4096) # => "abc" "" EOF
3727 * r.readpartial(4096) # raises EOFError
3728 *
3729 * # # Returned Buffer Content Pipe Content
3730 * r, w = IO.pipe #
3731 * w << "abc\ndef\n" # "" "abc\ndef\n"
3732 * r.gets # => "abc\n" "def\n" ""
3733 * w << "ghi\n" # "def\n" "ghi\n"
3734 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3735 * r.readpartial(4096) # => "ghi\n" "" ""
3736 *
3737 */
3738
3739static VALUE
3740io_readpartial(int argc, VALUE *argv, VALUE io)
3741{
3742 VALUE ret;
3743
3744 ret = io_getpartial(argc, argv, io, Qnil, 0);
3745 if (NIL_P(ret))
3746 rb_eof_error();
3747 return ret;
3748}
3749
3750static VALUE
3751io_nonblock_eof(int no_exception)
3752{
3753 if (!no_exception) {
3754 rb_eof_error();
3755 }
3756 return Qnil;
3757}
3758
3759/* :nodoc: */
3760static VALUE
3761io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3762{
3763 rb_io_t *fptr;
3764 long n, len;
3765 struct io_internal_read_struct iis;
3766 int shrinkable;
3767
3768 if ((len = NUM2LONG(length)) < 0) {
3769 rb_raise(rb_eArgError, "negative length %ld given", len);
3770 }
3771
3772 shrinkable = io_setstrbuf(&str, len);
3773 rb_bool_expected(ex, "exception", TRUE);
3774
3775 GetOpenFile(io, fptr);
3777
3778 if (len == 0) {
3779 io_set_read_length(str, 0, shrinkable);
3780 return str;
3781 }
3782
3783 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3784 if (n <= 0) {
3785 rb_fd_set_nonblock(fptr->fd);
3786 shrinkable |= io_setstrbuf(&str, len);
3787 iis.fptr = fptr;
3788 iis.nonblock = 1;
3789 iis.fd = fptr->fd;
3790 iis.buf = RSTRING_PTR(str);
3791 iis.capa = len;
3792 iis.timeout = NULL;
3793 n = io_read_memory_locktmp(str, &iis);
3794 if (n < 0) {
3795 int e = errno;
3796 if (io_again_p(e)) {
3797 if (!ex) return sym_wait_readable;
3798 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3799 e, "read would block");
3800 }
3801 rb_syserr_fail_path(e, fptr->pathv);
3802 }
3803 }
3804 io_set_read_length(str, n, shrinkable);
3805
3806 if (n == 0) {
3807 if (!ex) return Qnil;
3808 rb_eof_error();
3809 }
3810
3811 return str;
3812}
3813
3814/* :nodoc: */
3815static VALUE
3816io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3817{
3818 rb_io_t *fptr;
3819 long n;
3820
3821 if (!RB_TYPE_P(str, T_STRING))
3822 str = rb_obj_as_string(str);
3823 rb_bool_expected(ex, "exception", TRUE);
3824
3825 io = GetWriteIO(io);
3826 GetOpenFile(io, fptr);
3828
3829 if (io_fflush(fptr) < 0)
3830 rb_sys_fail_on_write(fptr);
3831
3832 rb_fd_set_nonblock(fptr->fd);
3833 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3834 RB_GC_GUARD(str);
3835
3836 if (n < 0) {
3837 int e = errno;
3838 if (io_again_p(e)) {
3839 if (!ex) {
3840 return sym_wait_writable;
3841 }
3842 else {
3843 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3844 }
3845 }
3846 rb_syserr_fail_path(e, fptr->pathv);
3847 }
3848
3849 return LONG2FIX(n);
3850}
3851
3852/*
3853 * call-seq:
3854 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3855 *
3856 * Reads bytes from the stream; the stream must be opened for reading
3857 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3858 *
3859 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3860 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3861 *
3862 * Returns a string (either a new string or the given +out_string+)
3863 * containing the bytes read.
3864 * The encoding of the string depends on both +maxLen+ and +out_string+:
3865 *
3866 * - +maxlen+ is +nil+: uses internal encoding of +self+
3867 * (regardless of whether +out_string+ was given).
3868 * - +maxlen+ not +nil+:
3869 *
3870 * - +out_string+ given: encoding of +out_string+ not modified.
3871 * - +out_string+ not given: ASCII-8BIT is used.
3872 *
3873 * <b>Without Argument +out_string+</b>
3874 *
3875 * When argument +out_string+ is omitted,
3876 * the returned value is a new string:
3877 *
3878 * f = File.new('t.txt')
3879 * f.read
3880 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3881 * f.rewind
3882 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3883 * f.read(30) # => "rth line\r\nFifth line\r\n"
3884 * f.read(30) # => nil
3885 * f.close
3886 *
3887 * If +maxlen+ is zero, returns an empty string.
3888 *
3889 * <b> With Argument +out_string+</b>
3890 *
3891 * When argument +out_string+ is given,
3892 * the returned value is +out_string+, whose content is replaced:
3893 *
3894 * f = File.new('t.txt')
3895 * s = 'foo' # => "foo"
3896 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3897 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3898 * f.rewind
3899 * s = 'bar'
3900 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3901 * s # => "First line\r\nSecond line\r\n\r\nFou"
3902 * s = 'baz'
3903 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3904 * s # => "rth line\r\nFifth line\r\n"
3905 * s = 'bat'
3906 * f.read(30, s) # => nil
3907 * s # => ""
3908 * f.close
3909 *
3910 * Note that this method behaves like the fread() function in C.
3911 * This means it retries to invoke read(2) system calls to read data
3912 * with the specified maxlen (or until EOF).
3913 *
3914 * This behavior is preserved even if the stream is in non-blocking mode.
3915 * (This method is non-blocking-flag insensitive as other methods.)
3916 *
3917 * If you need the behavior like a single read(2) system call,
3918 * consider #readpartial, #read_nonblock, and #sysread.
3919 *
3920 * Related: IO#write.
3921 */
3922
3923static VALUE
3924io_read(int argc, VALUE *argv, VALUE io)
3925{
3926 rb_io_t *fptr;
3927 long n, len;
3928 VALUE length, str;
3929 int shrinkable;
3930#if RUBY_CRLF_ENVIRONMENT
3931 int previous_mode;
3932#endif
3933
3934 rb_scan_args(argc, argv, "02", &length, &str);
3935
3936 if (NIL_P(length)) {
3937 GetOpenFile(io, fptr);
3939 return read_all(fptr, remain_size(fptr), str);
3940 }
3941 len = NUM2LONG(length);
3942 if (len < 0) {
3943 rb_raise(rb_eArgError, "negative length %ld given", len);
3944 }
3945
3946 shrinkable = io_setstrbuf(&str,len);
3947
3948 GetOpenFile(io, fptr);
3950 if (len == 0) {
3951 io_set_read_length(str, 0, shrinkable);
3952 return str;
3953 }
3954
3955 READ_CHECK(fptr);
3956#if RUBY_CRLF_ENVIRONMENT
3957 previous_mode = set_binary_mode_with_seek_cur(fptr);
3958#endif
3959 n = io_fread(str, 0, len, fptr);
3960 io_set_read_length(str, n, shrinkable);
3961#if RUBY_CRLF_ENVIRONMENT
3962 if (previous_mode == O_TEXT) {
3963 setmode(fptr->fd, O_TEXT);
3964 }
3965#endif
3966 if (n == 0) return Qnil;
3967
3968 return str;
3969}
3970
3971static void
3972rscheck(const char *rsptr, long rslen, VALUE rs)
3973{
3974 if (!rs) return;
3975 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3976 rb_raise(rb_eRuntimeError, "rs modified");
3977}
3978
3979static const char *
3980search_delim(const char *p, long len, int delim, rb_encoding *enc)
3981{
3982 if (rb_enc_mbminlen(enc) == 1) {
3983 p = memchr(p, delim, len);
3984 if (p) return p + 1;
3985 }
3986 else {
3987 const char *end = p + len;
3988 while (p < end) {
3989 int r = rb_enc_precise_mbclen(p, end, enc);
3990 if (!MBCLEN_CHARFOUND_P(r)) {
3991 p += rb_enc_mbminlen(enc);
3992 continue;
3993 }
3994 int n = MBCLEN_CHARFOUND_LEN(r);
3995 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3996 return p + n;
3997 }
3998 p += n;
3999 }
4000 }
4001 return NULL;
4002}
4003
4004static int
4005read_raw_character(rb_io_t *fptr, rb_encoding *enc, char *buf)
4006{
4007 int n = 0;
4008 int r;
4009
4010 do {
4011 if (!READ_DATA_PENDING(fptr)) {
4012 READ_CHECK(fptr);
4013 if (io_fillbuf(fptr) < 0) break;
4014 }
4015 buf[n++] = *READ_DATA_PENDING_PTR(fptr);
4016 fptr->rbuf.off++;
4017 fptr->rbuf.len--;
4018 r = rb_enc_precise_mbclen(buf, buf + n, enc);
4019 } while (MBCLEN_NEEDMORE_P(r) && n < rb_enc_mbmaxlen(enc));
4020
4021 return n;
4022}
4023
4024static void
4025unread_raw_character(rb_io_t *fptr, const char *buf, int len)
4026{
4027 if (fptr->rbuf.capa - fptr->rbuf.len < len) {
4028 if (fptr->rbuf.capa > INT_MAX - len)
4029 rb_raise(rb_eIOError, "ungetbyte failed");
4030 fptr->rbuf.capa += len;
4031 REALLOC_N(fptr->rbuf.ptr, char, fptr->rbuf.capa);
4032 }
4033 io_ungetbyte(rb_str_new(buf, len), fptr);
4034}
4035
4036static const char *
4037search_wide_delim(const char *p, long len, const char *delim, int width)
4038{
4039 const char *e = p + len;
4040 int index = 0;
4041
4042 while (index < width && delim[index] == 0) index++;
4043 if (index == width) index = 0;
4044
4045 const char *candidate = p + index;
4046 while (candidate < e) {
4047 candidate = memchr(candidate, (unsigned char)delim[index], e - candidate);
4048 if (candidate == NULL) break;
4049 const char *start = candidate - index;
4050 if ((start - p) % width == 0 && start + width <= e &&
4051 memcmp(start, delim, width) == 0) {
4052 return start;
4053 }
4054 candidate++;
4055 }
4056 return NULL;
4057}
4058
4059static int
4060appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
4061{
4062 VALUE str = *strp;
4063 long limit = *lp;
4064
4065 if (NEED_READCONV(fptr)) {
4066 SET_BINARY_MODE(fptr);
4067 make_readconv(fptr, 0);
4068 do {
4069 const char *p, *e;
4070 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
4071 if (searchlen) {
4072 p = READ_CHAR_PENDING_PTR(fptr);
4073 if (0 < limit && limit < searchlen)
4074 searchlen = (int)limit;
4075 e = search_delim(p, searchlen, delim, enc);
4076 if (e) {
4077 int len = (int)(e-p);
4078 if (NIL_P(str))
4079 *strp = str = rb_str_new(p, len);
4080 else
4081 rb_str_buf_cat(str, p, len);
4082 fptr->cbuf.off += len;
4083 fptr->cbuf.len -= len;
4084 limit -= len;
4085 *lp = limit;
4086 return delim;
4087 }
4088
4089 if (NIL_P(str))
4090 *strp = str = rb_str_new(p, searchlen);
4091 else
4092 rb_str_buf_cat(str, p, searchlen);
4093 fptr->cbuf.off += searchlen;
4094 fptr->cbuf.len -= searchlen;
4095 limit -= searchlen;
4096
4097 if (limit == 0) {
4098 *lp = limit;
4099 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4100 }
4101 }
4102 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4103 clear_readconv(fptr);
4104 *lp = limit;
4105 return EOF;
4106 }
4107
4108 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4109 if (rb_enc_mbminlen(enc) != 1) {
4110 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4111 int len;
4112
4113 if (limit < 0) {
4114 int width = rb_enc_mbminlen(enc);
4115 int delim_len = rb_enc_codelen(delim, enc);
4116
4117 if (delim_len == width) {
4118 rb_enc_mbcput(delim, buf, enc);
4119 for (;;) {
4120 if (!READ_DATA_PENDING(fptr)) {
4121 READ_CHECK(fptr);
4122 if (io_fillbuf(fptr) < 0) return EOF;
4123 }
4124 long pending = READ_DATA_PENDING_COUNT(fptr);
4125 long complete = pending - pending % width;
4126 const char *p = READ_DATA_PENDING_PTR(fptr);
4127 const char *q = complete ? search_wide_delim(p, complete, buf, width) : NULL;
4128 long take = q ? q - p + width : complete;
4129
4130 if (take > 0) {
4131 if (NIL_P(str))
4132 *strp = str = rb_str_buf_new(0);
4133 rb_str_buf_cat(str, p, take);
4134 fptr->rbuf.off += (int)take;
4135 fptr->rbuf.len -= (int)take;
4136 }
4137 if (q) return delim;
4138 if (complete == pending) continue;
4139
4140 len = read_raw_character(fptr, enc, buf);
4141 if (len == 0) return EOF;
4142 if (NIL_P(str))
4143 *strp = str = rb_str_buf_new(0);
4144 rb_str_buf_cat(str, buf, len);
4145 int r = rb_enc_precise_mbclen(buf, buf + len, enc);
4146 if (MBCLEN_CHARFOUND_P(r) &&
4147 rb_enc_mbc_to_codepoint(buf, buf + len, enc) == (unsigned int)delim)
4148 return delim;
4149 }
4150 }
4151 }
4152
4153 while ((len = read_raw_character(fptr, enc, buf)) > 0) {
4154 if (NIL_P(str))
4155 *strp = str = rb_str_buf_new(0);
4156 rb_str_buf_cat(str, buf, len);
4157 if (limit > 0) {
4158 if (len > limit) {
4159 *lp = 0;
4160 return (unsigned char)buf[len - 1];
4161 }
4162 *lp = limit -= len;
4163 }
4164 int r = rb_enc_precise_mbclen(buf, buf + len, enc);
4165 if (MBCLEN_CHARFOUND_P(r) &&
4166 rb_enc_mbc_to_codepoint(buf, buf + len, enc) == (unsigned int)delim)
4167 return delim;
4168 if (limit == 0)
4169 return (unsigned char)buf[len - 1];
4170 }
4171 *lp = limit;
4172 return EOF;
4173 }
4174 do {
4175 long pending = READ_DATA_PENDING_COUNT(fptr);
4176 if (pending > 0) {
4177 const char *p = READ_DATA_PENDING_PTR(fptr);
4178 const char *e;
4179 long last;
4180
4181 if (limit > 0 && pending > limit) pending = limit;
4182 e = search_delim(p, pending, delim, enc);
4183 if (e) pending = e - p;
4184 if (!NIL_P(str)) {
4185 last = RSTRING_LEN(str);
4186 rb_str_resize(str, last + pending);
4187 }
4188 else {
4189 last = 0;
4190 *strp = str = rb_str_buf_new(pending);
4191 rb_str_set_len(str, pending);
4192 }
4193 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
4194 limit -= pending;
4195 *lp = limit;
4196 if (e) return delim;
4197 if (limit == 0)
4198 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4199 }
4200 READ_CHECK(fptr);
4201 } while (io_fillbuf(fptr) >= 0);
4202 *lp = limit;
4203 return EOF;
4204}
4205
4206static inline int
4207swallow(rb_io_t *fptr, int term)
4208{
4209 if (NEED_READCONV(fptr)) {
4210 rb_encoding *enc = io_read_encoding(fptr);
4211 int needconv = rb_enc_mbminlen(enc) != 1;
4212 SET_BINARY_MODE(fptr);
4213 make_readconv(fptr, 0);
4214 do {
4215 size_t cnt;
4216 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4217 const char *p = READ_CHAR_PENDING_PTR(fptr);
4218 int i;
4219 if (!needconv) {
4220 if (*p != term) return TRUE;
4221 i = (int)cnt;
4222 while (--i && *++p == term);
4223 }
4224 else {
4225 const char *e = p + cnt;
4226 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
4227 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4228 i = (int)(e - p);
4229 }
4230 io_shift_cbuf(fptr, (int)cnt - i, NULL);
4231 }
4232 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4233 return FALSE;
4234 }
4235
4236 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4237 rb_encoding *enc = io_read_encoding(fptr);
4238 int widechar = rb_enc_mbminlen(enc) != 1;
4239 if (widechar) {
4240 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4241 int len;
4242
4243 while ((len = read_raw_character(fptr, enc, buf)) > 0) {
4244 if (rb_enc_ascget(buf, buf + len, NULL, enc) != term) {
4245 unread_raw_character(fptr, buf, len);
4246 return TRUE;
4247 }
4248 }
4249 return FALSE;
4250 }
4251 do {
4252 size_t cnt;
4253 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4254 char buf[1024];
4255 const char *p = READ_DATA_PENDING_PTR(fptr);
4256 int i;
4257 if (cnt > sizeof buf) cnt = sizeof buf;
4258 if (*p != term) return TRUE;
4259 i = (int)cnt;
4260 while (--i && *++p == term);
4261 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4262 rb_sys_fail_path(fptr->pathv);
4263 }
4264 READ_CHECK(fptr);
4265 } while (io_fillbuf(fptr) == 0);
4266 return FALSE;
4267}
4268
4269static VALUE
4270rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4271{
4272 VALUE str = Qnil;
4273 int len = 0;
4274 long pos = 0;
4275 int cr = 0;
4276
4277 do {
4278 int pending = READ_DATA_PENDING_COUNT(fptr);
4279
4280 if (pending > 0) {
4281 const char *p = READ_DATA_PENDING_PTR(fptr);
4282 const char *e;
4283 int chomplen = 0;
4284
4285 e = memchr(p, '\n', pending);
4286 if (e) {
4287 pending = (int)(e - p + 1);
4288 if (chomp) {
4289 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4290 }
4291 }
4292 if (NIL_P(str)) {
4293 str = rb_str_new(p, pending - chomplen);
4294 fptr->rbuf.off += pending;
4295 fptr->rbuf.len -= pending;
4296 }
4297 else {
4298 rb_str_resize(str, len + pending - chomplen);
4299 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4300 fptr->rbuf.off += chomplen;
4301 fptr->rbuf.len -= chomplen;
4302 if (pending == 1 && chomplen == 1 && len > 0) {
4303 if (RSTRING_PTR(str)[len-1] == '\r') {
4304 rb_str_resize(str, --len);
4305 break;
4306 }
4307 }
4308 }
4309 len += pending - chomplen;
4310 if (cr != ENC_CODERANGE_BROKEN)
4311 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4312 if (e) break;
4313 }
4314 READ_CHECK(fptr);
4315 } while (io_fillbuf(fptr) >= 0);
4316 if (NIL_P(str)) return Qnil;
4317
4318 str = io_enc_str(str, fptr);
4319 ENC_CODERANGE_SET(str, cr);
4320 fptr->lineno++;
4321
4322 return str;
4323}
4324
4326 VALUE io;
4327 VALUE rs;
4328 long limit;
4329 unsigned int chomp: 1;
4330};
4331
4332static void
4333extract_getline_opts(VALUE opts, struct getline_arg *args)
4334{
4335 int chomp = FALSE;
4336 if (!NIL_P(opts)) {
4337 static ID kwds[1];
4338 VALUE vchomp;
4339 if (!kwds[0]) {
4340 kwds[0] = rb_intern_const("chomp");
4341 }
4342 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4343 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4344 }
4345 args->chomp = chomp;
4346}
4347
4348static void
4349extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4350{
4351 VALUE rs = rb_rs, lim = Qnil;
4352
4353 if (argc == 1) {
4354 VALUE tmp = Qnil;
4355
4356 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4357 rs = tmp;
4358 }
4359 else {
4360 lim = argv[0];
4361 }
4362 }
4363 else if (2 <= argc) {
4364 rs = argv[0], lim = argv[1];
4365 if (!NIL_P(rs))
4366 StringValue(rs);
4367 }
4368 args->rs = rs;
4369 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4370}
4371
4372static void
4373check_getline_args(VALUE *rsp, long *limit, VALUE io)
4374{
4375 rb_io_t *fptr;
4376 VALUE rs = *rsp;
4377
4378 if (!NIL_P(rs)) {
4379 rb_encoding *enc_rs, *enc_io;
4380
4381 GetOpenFile(io, fptr);
4382 enc_rs = rb_enc_get(rs);
4383 enc_io = io_read_encoding(fptr);
4384 if (enc_io != enc_rs &&
4385 (!is_ascii_string(rs) ||
4386 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4387 if (rs == rb_default_rs) {
4388 rs = rb_enc_str_new(0, 0, enc_io);
4389 rb_str_buf_cat_ascii(rs, "\n");
4390 *rsp = rs;
4391 }
4392 else {
4393 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4394 rb_enc_name(enc_io),
4395 rb_enc_name(enc_rs));
4396 }
4397 }
4398 }
4399}
4400
4401static void
4402prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4403{
4404 VALUE opts;
4405 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4406 extract_getline_args(argc, argv, args);
4407 extract_getline_opts(opts, args);
4408 check_getline_args(&args->rs, &args->limit, io);
4409}
4410
4411static VALUE
4412rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4413{
4414 VALUE str = Qnil;
4415 int nolimit = 0;
4416 rb_encoding *enc;
4417
4419 if (NIL_P(rs) && limit < 0) {
4420 str = read_all(fptr, 0, Qnil);
4421 if (RSTRING_LEN(str) == 0) return Qnil;
4422 }
4423 else if (limit == 0) {
4424 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4425 }
4426 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4427 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4428 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4429 return rb_io_getline_fast(fptr, enc, chomp);
4430 }
4431 else {
4432 int c, newline = -1;
4433 const char *rsptr = 0;
4434 long rslen = 0;
4435 int rspara = 0;
4436 int extra_limit = 16;
4437 int chomp_cr = chomp;
4438
4439 SET_BINARY_MODE(fptr);
4440 enc = io_read_encoding(fptr);
4441
4442 if (!NIL_P(rs)) {
4443 rslen = RSTRING_LEN(rs);
4444 if (rslen == 0) {
4445 rsptr = "\n\n";
4446 rslen = 2;
4447 rspara = 1;
4448 swallow(fptr, '\n');
4449 rs = 0;
4450 if (!rb_enc_asciicompat(enc)) {
4451 rs = rb_usascii_str_new(rsptr, rslen);
4452 rs = rb_str_conv_enc(rs, 0, enc);
4453 OBJ_FREEZE(rs);
4454 rsptr = RSTRING_PTR(rs);
4455 rslen = RSTRING_LEN(rs);
4456 }
4457 newline = '\n';
4458 }
4459 else if (rb_enc_mbminlen(enc) == 1) {
4460 rsptr = RSTRING_PTR(rs);
4461 newline = (unsigned char)rsptr[rslen - 1];
4462 }
4463 else {
4464 rs = rb_str_conv_enc(rs, 0, enc);
4465 rsptr = RSTRING_PTR(rs);
4466 const char *e = rsptr + rslen;
4467 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4468 int n;
4469 newline = rb_enc_codepoint_len(last, e, &n, enc);
4470 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4471 }
4472 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4473 }
4474
4475 /* MS - Optimization */
4476 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4477 const char *s, *p, *pp, *e;
4478
4479 if (c == newline && RSTRING_LEN(str) >= rslen) {
4480 s = RSTRING_PTR(str);
4481 e = RSTRING_END(str);
4482 p = e - rslen;
4483 if (at_char_boundary(s, p, e, enc)) {
4484 if (!rspara) rscheck(rsptr, rslen, rs);
4485 if (memcmp(p, rsptr, rslen) == 0) {
4486 if (chomp) {
4487 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4488 rb_str_set_len(str, p - s);
4489 }
4490 break;
4491 }
4492 }
4493 }
4494 if (limit == 0) {
4495 s = RSTRING_PTR(str);
4496 p = RSTRING_END(str);
4497 pp = rb_enc_prev_char(s, p, p, enc);
4498 if (extra_limit && pp &&
4499 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4500 /* relax the limit while incomplete character.
4501 * extra_limit limits the relax length */
4502 limit = 1;
4503 extra_limit--;
4504 }
4505 else {
4506 nolimit = 1;
4507 break;
4508 }
4509 }
4510 }
4511
4512 if (rspara && c != EOF)
4513 swallow(fptr, '\n');
4514 if (!NIL_P(str))
4515 str = io_enc_str(str, fptr);
4516 }
4517
4518 if (!NIL_P(str) && !nolimit) {
4519 fptr->lineno++;
4520 }
4521
4522 return str;
4523}
4524
4525static VALUE
4526rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4527{
4528 rb_io_t *fptr;
4529 int old_lineno, new_lineno;
4530 VALUE str;
4531
4532 GetOpenFile(io, fptr);
4533 old_lineno = fptr->lineno;
4534 str = rb_io_getline_0(rs, limit, chomp, fptr);
4535 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4536 if (io == ARGF.current_file) {
4537 ARGF.lineno += new_lineno - old_lineno;
4538 ARGF.last_lineno = ARGF.lineno;
4539 }
4540 else {
4541 ARGF.last_lineno = new_lineno;
4542 }
4543 }
4544
4545 return str;
4546}
4547
4548static VALUE
4549rb_io_getline(int argc, VALUE *argv, VALUE io)
4550{
4551 struct getline_arg args;
4552
4553 prepare_getline_args(argc, argv, &args, io);
4554 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4555}
4556
4557VALUE
4559{
4560 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4561}
4562
4563VALUE
4564rb_io_gets_limit_internal(VALUE io, long limit)
4565{
4566 rb_io_t *fptr;
4567 GetOpenFile(io, fptr);
4568 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4569}
4570
4571VALUE
4572rb_io_gets_internal(VALUE io)
4573{
4574 return rb_io_gets_limit_internal(io, -1);
4575}
4576
4577/*
4578 * call-seq:
4579 * gets(sep = $/, chomp: false) -> string or nil
4580 * gets(limit, chomp: false) -> string or nil
4581 * gets(sep, limit, chomp: false) -> string or nil
4582 *
4583 * Reads and returns a line from the stream;
4584 * assigns the return value to <tt>$_</tt>.
4585 * See {Line IO}[rdoc-ref:IO@Line+IO].
4586 *
4587 * With no arguments given, returns the next line
4588 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4589 *
4590 * f = File.open('t.txt')
4591 * f.gets # => "First line\n"
4592 * $_ # => "First line\n"
4593 * f.gets # => "\n"
4594 * f.gets # => "Fourth line\n"
4595 * f.gets # => "Fifth line\n"
4596 * f.gets # => nil
4597 * f.close
4598 *
4599 * With only string argument +sep+ given,
4600 * returns the next line as determined by line separator +sep+,
4601 * or +nil+ if none;
4602 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4603 *
4604 * f = File.new('t.txt')
4605 * f.gets('l') # => "First l"
4606 * f.gets('li') # => "ine\nSecond li"
4607 * f.gets('lin') # => "ne\n\nFourth lin"
4608 * f.gets # => "e\n"
4609 * f.close
4610 *
4611 * The two special values for +sep+ are honored:
4612 *
4613 * f = File.new('t.txt')
4614 * # Get all.
4615 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4616 * f.rewind
4617 * # Get paragraph (up to two line separators).
4618 * f.gets('') # => "First line\nSecond line\n\n"
4619 * f.close
4620 *
4621 * With only integer argument +limit+ given,
4622 * limits the number of bytes in the line;
4623 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4624 *
4625 * # No more than one line.
4626 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4627 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4628 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4629 *
4630 * With arguments +sep+ and +limit+ given,
4631 * combines the two behaviors
4632 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4633 *
4634 * Optional keyword argument +chomp+ specifies whether line separators
4635 * are to be omitted:
4636 *
4637 * f = File.open('t.txt')
4638 * # Chomp the lines.
4639 * f.gets(chomp: true) # => "First line"
4640 * f.gets(chomp: true) # => "Second line"
4641 * f.gets(chomp: true) # => ""
4642 * f.gets(chomp: true) # => "Fourth line"
4643 * f.gets(chomp: true) # => "Fifth line"
4644 * f.gets(chomp: true) # => nil
4645 * f.close
4646 *
4647 */
4648
4649static VALUE
4650rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4651{
4652 VALUE str;
4653
4654 str = rb_io_getline(argc, argv, io);
4655 rb_lastline_set(str);
4656
4657 return str;
4658}
4659
4660/*
4661 * call-seq:
4662 * lineno -> integer
4663 *
4664 * Returns the current line number for the stream;
4665 * see {Line Number}[rdoc-ref:IO@Line+Number].
4666 *
4667 */
4668
4669static VALUE
4670rb_io_lineno(VALUE io)
4671{
4672 rb_io_t *fptr;
4673
4674 GetOpenFile(io, fptr);
4676 return INT2NUM(fptr->lineno);
4677}
4678
4679/*
4680 * call-seq:
4681 * lineno = integer -> integer
4682 *
4683 * Sets and returns the line number for the stream;
4684 * see {Line Number}[rdoc-ref:IO@Line+Number].
4685 *
4686 */
4687
4688static VALUE
4689rb_io_set_lineno(VALUE io, VALUE lineno)
4690{
4691 rb_io_t *fptr;
4692
4693 GetOpenFile(io, fptr);
4695 fptr->lineno = NUM2INT(lineno);
4696 return lineno;
4697}
4698
4699/* :nodoc: */
4700static VALUE
4701io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4702{
4703 long limit = -1;
4704 if (NIL_P(lim)) {
4705 VALUE tmp = Qnil;
4706 // If sep is specified, but it's not a string and not nil, then assume
4707 // it's the limit (it should be an integer)
4708 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4709 // If the user has specified a non-nil / non-string value
4710 // for the separator, we assume it's the limit and set the
4711 // separator to default: rb_rs.
4712 lim = sep;
4713 limit = NUM2LONG(lim);
4714 sep = rb_rs;
4715 }
4716 else {
4717 sep = tmp;
4718 }
4719 }
4720 else {
4721 if (!NIL_P(sep)) StringValue(sep);
4722 limit = NUM2LONG(lim);
4723 }
4724
4725 check_getline_args(&sep, &limit, io);
4726
4727 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4728 rb_lastline_set_up(line, 1);
4729
4730 if (NIL_P(line)) {
4731 rb_eof_error();
4732 }
4733 return line;
4734}
4735
4736static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4737
4738/*
4739 * call-seq:
4740 * readlines(sep = $/, chomp: false) -> array
4741 * readlines(limit, chomp: false) -> array
4742 * readlines(sep, limit, chomp: false) -> array
4743 *
4744 * Reads and returns all remaining line from the stream;
4745 * does not modify <tt>$_</tt>.
4746 * See {Line IO}[rdoc-ref:IO@Line+IO].
4747 *
4748 * With no arguments given, returns lines
4749 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4750 *
4751 * f = File.new('t.txt')
4752 * f.readlines
4753 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4754 * f.readlines # => []
4755 * f.close
4756 *
4757 * With only string argument +sep+ given,
4758 * returns lines as determined by line separator +sep+,
4759 * or +nil+ if none;
4760 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4761 *
4762 * f = File.new('t.txt')
4763 * f.readlines('li')
4764 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4765 * f.close
4766 *
4767 * The two special values for +sep+ are honored:
4768 *
4769 * f = File.new('t.txt')
4770 * # Get all into one string.
4771 * f.readlines(nil)
4772 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4773 * # Get paragraphs (up to two line separators).
4774 * f.rewind
4775 * f.readlines('')
4776 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4777 * f.close
4778 *
4779 * With only integer argument +limit+ given,
4780 * limits the number of bytes in each line;
4781 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4782 *
4783 * f = File.new('t.txt')
4784 * f.readlines(8)
4785 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4786 * f.close
4787 *
4788 * With arguments +sep+ and +limit+ given,
4789 * combines the two behaviors
4790 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4791 *
4792 * Optional keyword argument +chomp+ specifies whether line separators
4793 * are to be omitted:
4794 *
4795 * f = File.new('t.txt')
4796 * f.readlines(chomp: true)
4797 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4798 * f.close
4799 *
4800 */
4801
4802static VALUE
4803rb_io_readlines(int argc, VALUE *argv, VALUE io)
4804{
4805 struct getline_arg args;
4806
4807 prepare_getline_args(argc, argv, &args, io);
4808 return io_readlines(&args, io);
4809}
4810
4811static VALUE
4812io_readlines(const struct getline_arg *arg, VALUE io)
4813{
4814 VALUE line, ary;
4815
4816 if (arg->limit == 0)
4817 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4818 ary = rb_ary_new();
4819 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4820 rb_ary_push(ary, line);
4821 }
4822 return ary;
4823}
4824
4825/*
4826 * call-seq:
4827 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4828 * each_line(limit, chomp: false) {|line| ... } -> self
4829 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4830 * each_line -> enumerator
4831 *
4832 * Calls the block with each remaining line read from the stream;
4833 * returns +self+.
4834 * Does nothing if already at end-of-stream;
4835 * See {Line IO}[rdoc-ref:IO@Line+IO].
4836 *
4837 * With no arguments given, reads lines
4838 * as determined by line separator <tt>$/</tt>:
4839 *
4840 * f = File.new('t.txt')
4841 * f.each_line {|line| p line }
4842 * f.each_line {|line| fail 'Cannot happen' }
4843 * f.close
4844 *
4845 * Output:
4846 *
4847 * "First line\n"
4848 * "Second line\n"
4849 * "\n"
4850 * "Fourth line\n"
4851 * "Fifth line\n"
4852 *
4853 * With only string argument +sep+ given,
4854 * reads lines as determined by line separator +sep+;
4855 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4856 *
4857 * f = File.new('t.txt')
4858 * f.each_line('li') {|line| p line }
4859 * f.close
4860 *
4861 * Output:
4862 *
4863 * "First li"
4864 * "ne\nSecond li"
4865 * "ne\n\nFourth li"
4866 * "ne\nFifth li"
4867 * "ne\n"
4868 *
4869 * The two special values for +sep+ are honored:
4870 *
4871 * f = File.new('t.txt')
4872 * # Get all into one string.
4873 * f.each_line(nil) {|line| p line }
4874 * f.close
4875 *
4876 * Output:
4877 *
4878 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4879 *
4880 * f.rewind
4881 * # Get paragraphs (up to two line separators).
4882 * f.each_line('') {|line| p line }
4883 *
4884 * Output:
4885 *
4886 * "First line\nSecond line\n\n"
4887 * "Fourth line\nFifth line\n"
4888 *
4889 * With only integer argument +limit+ given,
4890 * limits the number of bytes in each line;
4891 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4892 *
4893 * f = File.new('t.txt')
4894 * f.each_line(8) {|line| p line }
4895 * f.close
4896 *
4897 * Output:
4898 *
4899 * "First li"
4900 * "ne\n"
4901 * "Second l"
4902 * "ine\n"
4903 * "\n"
4904 * "Fourth l"
4905 * "ine\n"
4906 * "Fifth li"
4907 * "ne\n"
4908 *
4909 * With arguments +sep+ and +limit+ given,
4910 * combines the two behaviors
4911 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4912 *
4913 * Optional keyword argument +chomp+ specifies whether line separators
4914 * are to be omitted:
4915 *
4916 * f = File.new('t.txt')
4917 * f.each_line(chomp: true) {|line| p line }
4918 * f.close
4919 *
4920 * Output:
4921 *
4922 * "First line"
4923 * "Second line"
4924 * ""
4925 * "Fourth line"
4926 * "Fifth line"
4927 *
4928 * Returns an Enumerator if no block is given.
4929 */
4930
4931static VALUE
4932rb_io_each_line(int argc, VALUE *argv, VALUE io)
4933{
4934 VALUE str;
4935 struct getline_arg args;
4936
4937 RETURN_ENUMERATOR(io, argc, argv);
4938 prepare_getline_args(argc, argv, &args, io);
4939 if (args.limit == 0)
4940 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4941 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4942 rb_yield(str);
4943 }
4944 return io;
4945}
4946
4947/*
4948 * call-seq:
4949 * each_byte {|byte| ... } -> self
4950 * each_byte -> enumerator
4951 *
4952 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4953 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4954 *
4955 * File.read('t.ja') # => "こんにちは"
4956 * f = File.new('t.ja')
4957 * a = []
4958 * f.each_byte {|b| a << b }
4959 * a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
4960 * f.close
4961 *
4962 * Returns an Enumerator if no block is given.
4963 *
4964 * Related: IO#each_char, IO#each_codepoint.
4965 *
4966 */
4967
4968static VALUE
4969rb_io_each_byte(VALUE io)
4970{
4971 rb_io_t *fptr;
4972
4973 RETURN_ENUMERATOR(io, 0, 0);
4974 GetOpenFile(io, fptr);
4975
4976 do {
4977 while (fptr->rbuf.len > 0) {
4978 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4979 fptr->rbuf.len--;
4980 rb_yield(INT2FIX(*p & 0xff));
4982 errno = 0;
4983 }
4984 READ_CHECK(fptr);
4985 } while (io_fillbuf(fptr) >= 0);
4986 return io;
4987}
4988
4989static VALUE
4990io_getc(rb_io_t *fptr, rb_encoding *enc)
4991{
4992 int r, n, cr = 0;
4993 VALUE str;
4994
4995 if (NEED_READCONV(fptr)) {
4996 rb_encoding *read_enc = io_read_encoding(fptr);
4997
4998 str = Qnil;
4999 SET_BINARY_MODE(fptr);
5000 make_readconv(fptr, 0);
5001
5002 while (1) {
5003 if (fptr->cbuf.len) {
5004 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
5005 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5006 read_enc);
5007 if (!MBCLEN_NEEDMORE_P(r))
5008 break;
5009 if (fptr->cbuf.len == fptr->cbuf.capa) {
5010 rb_raise(rb_eIOError, "too long character");
5011 }
5012 }
5013
5014 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5015 if (fptr->cbuf.len == 0) {
5016 clear_readconv(fptr);
5017 return Qnil;
5018 }
5019 /* return an unit of an incomplete character just before EOF */
5020 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
5021 fptr->cbuf.off += 1;
5022 fptr->cbuf.len -= 1;
5023 if (fptr->cbuf.len == 0) clear_readconv(fptr);
5025 return str;
5026 }
5027 }
5028 if (MBCLEN_INVALID_P(r)) {
5029 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
5030 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5031 read_enc);
5032 io_shift_cbuf(fptr, r, &str);
5034 }
5035 else {
5036 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
5038 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
5039 ISASCII(RSTRING_PTR(str)[0])) {
5040 cr = ENC_CODERANGE_7BIT;
5041 }
5042 }
5043 str = io_enc_str(str, fptr);
5044 ENC_CODERANGE_SET(str, cr);
5045 return str;
5046 }
5047
5048 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5049 if (io_fillbuf(fptr) < 0) {
5050 return Qnil;
5051 }
5052 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
5053 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
5054 fptr->rbuf.off += 1;
5055 fptr->rbuf.len -= 1;
5056 cr = ENC_CODERANGE_7BIT;
5057 }
5058 else {
5059 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5060 if (MBCLEN_CHARFOUND_P(r) &&
5061 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
5062 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
5063 fptr->rbuf.off += n;
5064 fptr->rbuf.len -= n;
5066 }
5067 else if (MBCLEN_NEEDMORE_P(r)) {
5068 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
5069 fptr->rbuf.len = 0;
5070 getc_needmore:
5071 if (io_fillbuf(fptr) != -1) {
5072 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
5073 fptr->rbuf.off++;
5074 fptr->rbuf.len--;
5075 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
5076 if (MBCLEN_NEEDMORE_P(r)) {
5077 goto getc_needmore;
5078 }
5079 else if (MBCLEN_CHARFOUND_P(r)) {
5081 }
5082 }
5083 }
5084 else {
5085 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
5086 fptr->rbuf.off++;
5087 fptr->rbuf.len--;
5088 }
5089 }
5090 if (!cr) cr = ENC_CODERANGE_BROKEN;
5091 str = io_enc_str(str, fptr);
5092 ENC_CODERANGE_SET(str, cr);
5093 return str;
5094}
5095
5096/*
5097 * call-seq:
5098 * each_char {|c| ... } -> self
5099 * each_char -> enumerator
5100 *
5101 * Calls the given block with each character in the stream; returns +self+.
5102 * See {Character IO}[rdoc-ref:IO@Character+IO].
5103 *
5104 * File.read('t.ja') # => "こんにちは"
5105 * f = File.new('t.ja')
5106 * a = []
5107 * f.each_char {|c| a << c.ord }
5108 * a # => [12371, 12435, 12395, 12385, 12399]
5109 * f.close
5110 *
5111 * Returns an Enumerator if no block is given.
5112 *
5113 * Related: IO#each_byte, IO#each_codepoint.
5114 *
5115 */
5116
5117static VALUE
5118rb_io_each_char(VALUE io)
5119{
5120 rb_io_t *fptr;
5121 rb_encoding *enc;
5122 VALUE c;
5123
5124 RETURN_ENUMERATOR(io, 0, 0);
5125 GetOpenFile(io, fptr);
5127
5128 enc = io_input_encoding(fptr);
5129 READ_CHECK(fptr);
5130 while (!NIL_P(c = io_getc(fptr, enc))) {
5131 rb_yield(c);
5132 }
5133 return io;
5134}
5135
5136/*
5137 * call-seq:
5138 * each_codepoint {|c| ... } -> self
5139 * each_codepoint -> enumerator
5140 *
5141 * Calls the given block with each codepoint in the stream; returns +self+:
5142 *
5143 * File.read('t.ja') # => "こんにちは"
5144 * f = File.new('t.ja')
5145 * a = []
5146 * f.each_codepoint {|c| a << c }
5147 * a # => [12371, 12435, 12395, 12385, 12399]
5148 * f.close
5149 *
5150 * Returns an Enumerator if no block is given.
5151 *
5152 * Related: IO#each_byte, IO#each_char.
5153 *
5154 */
5155
5156static VALUE
5157rb_io_each_codepoint(VALUE io)
5158{
5159 rb_io_t *fptr;
5160 rb_encoding *enc;
5161 unsigned int c;
5162 int r, n;
5163
5164 RETURN_ENUMERATOR(io, 0, 0);
5165 GetOpenFile(io, fptr);
5167
5168 READ_CHECK(fptr);
5169 enc = io_read_encoding(fptr);
5170 if (NEED_READCONV(fptr)) {
5171 SET_BINARY_MODE(fptr);
5172 r = 1; /* no invalid char yet */
5173 for (;;) {
5174 make_readconv(fptr, 0);
5175 for (;;) {
5176 if (fptr->cbuf.len) {
5177 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
5178 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5179 enc);
5180 if (!MBCLEN_NEEDMORE_P(r))
5181 break;
5182 if (fptr->cbuf.len == fptr->cbuf.capa) {
5183 rb_raise(rb_eIOError, "too long character");
5184 }
5185 }
5186 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5187 clear_readconv(fptr);
5188 if (!MBCLEN_CHARFOUND_P(r)) {
5189 goto invalid;
5190 }
5191 return io;
5192 }
5193 }
5194 if (MBCLEN_INVALID_P(r)) {
5195 goto invalid;
5196 }
5197 n = MBCLEN_CHARFOUND_LEN(r);
5198 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
5199 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5200 enc);
5201 fptr->cbuf.off += n;
5202 fptr->cbuf.len -= n;
5203 rb_yield(UINT2NUM(c));
5205 }
5206 }
5207 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5208 while (io_fillbuf(fptr) >= 0) {
5209 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
5210 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5211 if (MBCLEN_CHARFOUND_P(r) &&
5212 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
5213 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
5214 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5215 fptr->rbuf.off += n;
5216 fptr->rbuf.len -= n;
5217 rb_yield(UINT2NUM(c));
5218 }
5219 else if (MBCLEN_INVALID_P(r)) {
5220 goto invalid;
5221 }
5222 else if (MBCLEN_NEEDMORE_P(r)) {
5223 char cbuf[8], *p = cbuf;
5224 int more = MBCLEN_NEEDMORE_LEN(r);
5225 if (more > numberof(cbuf)) goto invalid;
5226 more += n = fptr->rbuf.len;
5227 if (more > numberof(cbuf)) goto invalid;
5228 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
5229 (p += n, (more -= n) > 0)) {
5230 if (io_fillbuf(fptr) < 0) goto invalid;
5231 if ((n = fptr->rbuf.len) > more) n = more;
5232 }
5233 r = rb_enc_precise_mbclen(cbuf, p, enc);
5234 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
5235 c = rb_enc_codepoint(cbuf, p, enc);
5236 rb_yield(UINT2NUM(c));
5237 }
5238 else {
5239 continue;
5240 }
5242 }
5243 return io;
5244
5245 invalid:
5246 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
5248}
5249
5250/*
5251 * call-seq:
5252 * getc -> character or nil
5253 *
5254 * Reads and returns the next 1-character string from the stream;
5255 * returns +nil+ if already at end-of-stream.
5256 * See {Character IO}[rdoc-ref:IO@Character+IO].
5257 *
5258 * f = File.open('t.txt')
5259 * f.getc # => "F"
5260 * f.close
5261 * File.read('t.ja') # => "こんにちは"
5262 * f = File.open('t.ja')
5263 * f.getc.ord # => 12371
5264 * f.close
5265 *
5266 * Related: IO#readchar (may raise EOFError).
5267 *
5268 */
5269
5270static VALUE
5271rb_io_getc(VALUE io)
5272{
5273 rb_io_t *fptr;
5274 rb_encoding *enc;
5275
5276 GetOpenFile(io, fptr);
5278
5279 enc = io_input_encoding(fptr);
5280 READ_CHECK(fptr);
5281 return io_getc(fptr, enc);
5282}
5283
5284/*
5285 * call-seq:
5286 * readchar -> string
5287 *
5288 * Reads and returns the next 1-character string from the stream;
5289 * raises EOFError if already at end-of-stream.
5290 * See {Character IO}[rdoc-ref:IO@Character+IO].
5291 *
5292 * f = File.open('t.txt')
5293 * f.readchar # => "F"
5294 * f.close
5295 * File.read('t.ja') # => "こんにちは"
5296 * f = File.open('t.ja')
5297 * f.readchar.ord # => 12371
5298 * f.close
5299 *
5300 * Related: IO#getc (will not raise EOFError).
5301 *
5302 */
5303
5304static VALUE
5305rb_io_readchar(VALUE io)
5306{
5307 VALUE c = rb_io_getc(io);
5308
5309 if (NIL_P(c)) {
5310 rb_eof_error();
5311 }
5312 return c;
5313}
5314
5315/*
5316 * call-seq:
5317 * getbyte -> integer or nil
5318 *
5319 * Reads and returns the next byte (in range 0..255) from the stream;
5320 * returns +nil+ if already at end-of-stream.
5321 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5322 *
5323 * f = File.open('t.txt')
5324 * f.getbyte # => 70
5325 * f.close
5326 * File.read('t.ja') # => "こんにちは"
5327 * f = File.open('t.ja')
5328 * f.getbyte # => 227
5329 * f.close
5330 *
5331 * Related: IO#readbyte (may raise EOFError).
5332 */
5333
5334VALUE
5336{
5337 rb_io_t *fptr;
5338 int c;
5339
5340 GetOpenFile(io, fptr);
5342 READ_CHECK(fptr);
5343 VALUE r_stdout = rb_ractor_stdout();
5344 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5345 rb_io_t *ofp;
5346 GetOpenFile(r_stdout, ofp);
5347 if (ofp->mode & FMODE_TTY) {
5348 rb_io_flush(r_stdout);
5349 }
5350 }
5351 if (io_fillbuf(fptr) < 0) {
5352 return Qnil;
5353 }
5354 fptr->rbuf.off++;
5355 fptr->rbuf.len--;
5356 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5357 return INT2FIX(c & 0xff);
5358}
5359
5360/*
5361 * call-seq:
5362 * readbyte -> integer
5363 *
5364 * Reads and returns the next byte (in range 0..255) from the stream;
5365 * raises EOFError if already at end-of-stream.
5366 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5367 *
5368 * f = File.open('t.txt')
5369 * f.readbyte # => 70
5370 * f.close
5371 * File.read('t.ja') # => "こんにちは"
5372 * f = File.open('t.ja')
5373 * f.readbyte # => 227
5374 * f.close
5375 *
5376 * Related: IO#getbyte (will not raise EOFError).
5377 *
5378 */
5379
5380static VALUE
5381rb_io_readbyte(VALUE io)
5382{
5383 VALUE c = rb_io_getbyte(io);
5384
5385 if (NIL_P(c)) {
5386 rb_eof_error();
5387 }
5388 return c;
5389}
5390
5391/*
5392 * call-seq:
5393 * ungetbyte(integer) -> nil
5394 * ungetbyte(string) -> nil
5395 *
5396 * Pushes back ("unshifts") the given data onto the stream's buffer,
5397 * placing the data so that it is next to be read; returns +nil+.
5398 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5399 *
5400 * Note that:
5401 *
5402 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5403 * - Calling #rewind on the stream discards the pushed-back data.
5404 *
5405 * When argument +integer+ is given, uses only its low-order byte:
5406 *
5407 * File.write('t.tmp', '012')
5408 * f = File.open('t.tmp')
5409 * f.ungetbyte(0x41) # => nil
5410 * f.read # => "A012"
5411 * f.rewind
5412 * f.ungetbyte(0x4243) # => nil
5413 * f.read # => "C012"
5414 * f.close
5415 *
5416 * When argument +string+ is given, uses all bytes:
5417 *
5418 * File.write('t.tmp', '012')
5419 * f = File.open('t.tmp')
5420 * f.ungetbyte('A') # => nil
5421 * f.read # => "A012"
5422 * f.rewind
5423 * f.ungetbyte('BCDE') # => nil
5424 * f.read # => "BCDE012"
5425 * f.close
5426 *
5427 */
5428
5429VALUE
5431{
5432 rb_io_t *fptr;
5433
5434 GetOpenFile(io, fptr);
5436 switch (TYPE(b)) {
5437 case T_NIL:
5438 return Qnil;
5439 case T_FIXNUM:
5440 case T_BIGNUM: ;
5441 VALUE v = rb_int_modulo(b, INT2FIX(256));
5442 unsigned char c = NUM2INT(v) & 0xFF;
5443 b = rb_str_new((const char *)&c, 1);
5444 break;
5445 default:
5446 StringValue(b);
5447 }
5448 io_ungetbyte(b, fptr);
5449 return Qnil;
5450}
5451
5452/*
5453 * call-seq:
5454 * ungetc(integer) -> nil
5455 * ungetc(string) -> nil
5456 *
5457 * Pushes back ("unshifts") the given data onto the stream's buffer,
5458 * placing the data so that it is next to be read; returns +nil+.
5459 * See {Character IO}[rdoc-ref:IO@Character+IO].
5460 *
5461 * Note that:
5462 *
5463 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5464 * - Calling #rewind on the stream discards the pushed-back data.
5465 *
5466 * When argument +integer+ is given, interprets the integer as a character:
5467 *
5468 * File.write('t.tmp', '012')
5469 * f = File.open('t.tmp')
5470 * f.ungetc(0x41) # => nil
5471 * f.read # => "A012"
5472 * f.rewind
5473 * f.ungetc(0x0442) # => nil
5474 * f.getc.ord # => 1090
5475 * f.close
5476 *
5477 * When argument +string+ is given, uses all characters:
5478 *
5479 * File.write('t.tmp', '012')
5480 * f = File.open('t.tmp')
5481 * f.ungetc('A') # => nil
5482 * f.read # => "A012"
5483 * f.rewind
5484 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5485 * f.getc.ord # => 1090
5486 * f.getc.ord # => 1077
5487 * f.getc.ord # => 1089
5488 * f.getc.ord # => 1090
5489 * f.close
5490 *
5491 */
5492
5493VALUE
5495{
5496 rb_io_t *fptr;
5497 long len;
5498
5499 GetOpenFile(io, fptr);
5501 if (FIXNUM_P(c)) {
5502 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5503 }
5504 else if (RB_BIGNUM_TYPE_P(c)) {
5505 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5506 }
5507 else {
5508 StringValue(c);
5509 }
5510 if (NEED_READCONV(fptr)) {
5511 SET_BINARY_MODE(fptr);
5512 len = RSTRING_LEN(c);
5513#if SIZEOF_LONG > SIZEOF_INT
5514 if (len > INT_MAX)
5515 rb_raise(rb_eIOError, "ungetc failed");
5516#endif
5517 make_readconv(fptr, (int)len);
5518 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5519 rb_raise(rb_eIOError, "ungetc failed");
5520 if (fptr->cbuf.off < len) {
5521 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5522 fptr->cbuf.ptr+fptr->cbuf.off,
5523 char, fptr->cbuf.len);
5524 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5525 }
5526 fptr->cbuf.off -= (int)len;
5527 fptr->cbuf.len += (int)len;
5528 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5529 }
5530 else {
5531 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5532 io_ungetbyte(c, fptr);
5533 }
5534 return Qnil;
5535}
5536
5537/*
5538 * call-seq:
5539 * isatty -> true or false
5540 *
5541 * Returns +true+ if the stream is associated with a terminal device (tty),
5542 * +false+ otherwise:
5543 *
5544 * f = File.new('t.txt').isatty #=> false
5545 * f.close
5546 * f = File.new('/dev/tty').isatty #=> true
5547 * f.close
5548 *
5549 */
5550
5551static VALUE
5552rb_io_isatty(VALUE io)
5553{
5554 rb_io_t *fptr;
5555
5556 GetOpenFile(io, fptr);
5557 return RBOOL(isatty(fptr->fd) != 0);
5558}
5559
5560#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5561/*
5562 * call-seq:
5563 * close_on_exec? -> true or false
5564 *
5565 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5566 *
5567 * f = File.open('t.txt')
5568 * f.close_on_exec? # => true
5569 * f.close_on_exec = false
5570 * f.close_on_exec? # => false
5571 * f.close
5572 *
5573 */
5574
5575static VALUE
5576rb_io_close_on_exec_p(VALUE io)
5577{
5578 rb_io_t *fptr;
5579 VALUE write_io;
5580 int fd, ret;
5581
5582 write_io = GetWriteIO(io);
5583 if (io != write_io) {
5584 GetOpenFile(write_io, fptr);
5585 if (fptr && 0 <= (fd = fptr->fd)) {
5586 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5587 if (!(ret & FD_CLOEXEC)) return Qfalse;
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)) return Qfalse;
5595 }
5596 return Qtrue;
5597}
5598#else
5599#define rb_io_close_on_exec_p rb_f_notimplement
5600#endif
5601
5602#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5603/*
5604 * call-seq:
5605 * self.close_on_exec = bool -> true or false
5606 *
5607 * Sets a close-on-exec flag.
5608 *
5609 * f = File.open(File::NULL)
5610 * f.close_on_exec = true
5611 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5612 * f.closed? #=> false
5613 *
5614 * Ruby sets close-on-exec flags of all file descriptors by default
5615 * since Ruby 2.0.0.
5616 * So you don't need to set by yourself.
5617 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5618 * if another thread use fork() and exec() (via system() method for example).
5619 * If you really needs file descriptor inheritance to child process,
5620 * use spawn()'s argument such as fd=>fd.
5621 */
5622
5623static VALUE
5624rb_io_set_close_on_exec(VALUE io, VALUE arg)
5625{
5626 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5627 rb_io_t *fptr;
5628 VALUE write_io;
5629 int fd, ret;
5630
5631 write_io = GetWriteIO(io);
5632 if (io != write_io) {
5633 GetOpenFile(write_io, fptr);
5634 if (fptr && 0 <= (fd = fptr->fd)) {
5635 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5636 if ((ret & FD_CLOEXEC) != flag) {
5637 ret = (ret & ~FD_CLOEXEC) | flag;
5638 ret = fcntl(fd, F_SETFD, ret);
5639 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5640 }
5641 }
5642
5643 }
5644
5645 GetOpenFile(io, fptr);
5646 if (fptr && 0 <= (fd = fptr->fd)) {
5647 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5648 if ((ret & FD_CLOEXEC) != flag) {
5649 ret = (ret & ~FD_CLOEXEC) | flag;
5650 ret = fcntl(fd, F_SETFD, ret);
5651 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5652 }
5653 }
5654 return Qnil;
5655}
5656#else
5657#define rb_io_set_close_on_exec rb_f_notimplement
5658#endif
5659
5660#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5661#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5662
5663static VALUE
5664finish_writeconv(rb_io_t *fptr, int noalloc)
5665{
5666 unsigned char *ds, *dp, *de;
5668
5669 if (!fptr->wbuf.ptr) {
5670 unsigned char buf[1024];
5671
5673 while (res == econv_destination_buffer_full) {
5674 ds = dp = buf;
5675 de = buf + sizeof(buf);
5676 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5677 while (dp-ds) {
5678 size_t remaining = dp-ds;
5679 long result = rb_io_write_memory(fptr, ds, remaining);
5680
5681 if (result > 0) {
5682 ds += result;
5683 if ((size_t)result == remaining) break;
5684 }
5685 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5686 if (fptr->fd < 0)
5687 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5688 }
5689 else {
5690 return noalloc ? Qtrue : INT2NUM(errno);
5691 }
5692 }
5693 if (res == econv_invalid_byte_sequence ||
5694 res == econv_incomplete_input ||
5696 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5697 }
5698 }
5699
5700 return Qnil;
5701 }
5702
5704 while (res == econv_destination_buffer_full) {
5705 if (fptr->wbuf.len == fptr->wbuf.capa) {
5706 if (io_fflush(fptr) < 0) {
5707 return noalloc ? Qtrue : INT2NUM(errno);
5708 }
5709 }
5710
5711 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5712 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5713 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5714 fptr->wbuf.len += (int)(dp - ds);
5715 if (res == econv_invalid_byte_sequence ||
5716 res == econv_incomplete_input ||
5718 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5719 }
5720 }
5721 return Qnil;
5722}
5723
5725 rb_io_t *fptr;
5726 int noalloc;
5727};
5728
5729static VALUE
5730finish_writeconv_sync(VALUE arg)
5731{
5732 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5733 return finish_writeconv(p->fptr, p->noalloc);
5734}
5735
5736static void*
5737nogvl_close(void *ptr)
5738{
5739 int *fd = ptr;
5740
5741 return (void*)(intptr_t)close(*fd);
5742}
5743
5744static int
5745maygvl_close(int fd, int keepgvl)
5746{
5747 if (keepgvl)
5748 return close(fd);
5749
5750 /*
5751 * close() may block for certain file types (NFS, SO_LINGER sockets,
5752 * inotify), so let other threads run.
5753 */
5754 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5755}
5756
5757static void*
5758nogvl_fclose(void *ptr)
5759{
5760 FILE *file = ptr;
5761
5762 return (void*)(intptr_t)fclose(file);
5763}
5764
5765static int
5766maygvl_fclose(FILE *file, int keepgvl)
5767{
5768 if (keepgvl)
5769 return fclose(file);
5770
5771 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5772}
5773
5774static void free_io_buffer(rb_io_buffer_t *buf);
5775
5776static void
5777fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5778{
5779 VALUE error = Qnil;
5780 int fd = fptr->fd;
5781 FILE *stdio_file = fptr->stdio_file;
5782 int mode = fptr->mode;
5783
5784 if (fptr->writeconv) {
5785 if (!NIL_P(fptr->write_lock) && !noraise) {
5786 struct finish_writeconv_arg arg;
5787 arg.fptr = fptr;
5788 arg.noalloc = noraise;
5789 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5790 }
5791 else {
5792 error = finish_writeconv(fptr, noraise);
5793 }
5794 }
5795 /* Do not flush the write buffer on close when the stream is in sync
5796 * mode. In sync mode Ruby's write buffer is not authoritative (writes go
5797 * straight to the OS), so any bytes left in the buffer are the result of
5798 * writes made while sync was disabled. Setting sync = true is therefore a
5799 * way to abandon that pending output rather than replaying it on close,
5800 * which matters after an interrupted write where the amount actually
5801 * written is indeterminate. Call flush before enabling sync if the
5802 * buffered data should still be sent. */
5803 if (fptr->wbuf.len && !(fptr->mode & FMODE_SYNC)) {
5804 if (noraise) {
5805 io_flush_buffer_sync(fptr);
5806 }
5807 else {
5808 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5809 error = INT2NUM(errno);
5810 }
5811 }
5812 }
5813
5814 int done = 0;
5815
5816 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5817 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5818 done = 1;
5819 }
5820
5821 fptr->fd = -1;
5822 fptr->stdio_file = 0;
5824
5825 // Wait for blocking operations to ensure they do not hit EBADF:
5826 rb_thread_io_close_wait(fptr);
5827
5828 if (!done && stdio_file) {
5829 // stdio_file is deallocated anyway even if fclose failed.
5830 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5831 if (!noraise) {
5832 error = INT2NUM(errno);
5833 }
5834 }
5835
5836 done = 1;
5837 }
5838
5839 VALUE scheduler = rb_fiber_scheduler_current();
5840 if (!done && fd >= 0 && scheduler != Qnil) {
5841 VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
5842
5843 if (!UNDEF_P(result)) {
5844 done = RTEST(result);
5845 }
5846 }
5847
5848 if (!done && fd >= 0) {
5849 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5850 // We assumes it is closed.
5851
5852 keepgvl |= !(mode & FMODE_WRITABLE);
5853 keepgvl |= noraise;
5854 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5855 if (!noraise) {
5856 error = INT2NUM(errno);
5857 }
5858 }
5859
5860 done = 1;
5861 }
5862
5863 if (!NIL_P(error) && !noraise) {
5864 if (RB_INTEGER_TYPE_P(error))
5865 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5866 else
5867 rb_exc_raise(error);
5868 }
5869}
5870
5871static void
5872fptr_finalize(rb_io_t *fptr, int noraise)
5873{
5874 fptr_finalize_flush(fptr, noraise, FALSE);
5875 free_io_buffer(&fptr->rbuf);
5876 free_io_buffer(&fptr->wbuf);
5877 clear_codeconv(fptr);
5878}
5879
5880static void
5881rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5882{
5883 if (fptr->finalize) {
5884 (*fptr->finalize)(fptr, noraise);
5885 }
5886 else {
5887 fptr_finalize(fptr, noraise);
5888 }
5889}
5890
5891static void
5892free_io_buffer(rb_io_buffer_t *buf)
5893{
5894 if (buf->ptr) {
5895 ruby_xfree_sized(buf->ptr, (size_t)buf->capa);
5896 buf->ptr = NULL;
5897 }
5898 buf->off = buf->len = buf->capa = 0;
5899}
5900
5901static void
5902clear_readconv(rb_io_t *fptr)
5903{
5904 if (fptr->readconv) {
5905 rb_econv_close(fptr->readconv);
5906 fptr->readconv = NULL;
5907 }
5908 free_io_buffer(&fptr->cbuf);
5909}
5910
5911static void
5912clear_writeconv(rb_io_t *fptr)
5913{
5914 if (fptr->writeconv) {
5916 fptr->writeconv = NULL;
5917 }
5918 fptr->writeconv_initialized = 0;
5919}
5920
5921static void
5922clear_codeconv(rb_io_t *fptr)
5923{
5924 clear_readconv(fptr);
5925 clear_writeconv(fptr);
5926}
5927
5928static void
5929rb_io_fptr_cleanup_all(rb_io_t *fptr)
5930{
5931 fptr->pathv = Qnil;
5932 if (0 <= fptr->fd)
5933 rb_io_fptr_cleanup(fptr, TRUE);
5934 fptr->write_lock = Qnil;
5935 free_io_buffer(&fptr->rbuf);
5936 free_io_buffer(&fptr->wbuf);
5937 clear_codeconv(fptr);
5938}
5939
5940int
5942{
5943 if (!io) return 0;
5944 rb_io_fptr_cleanup_all(io);
5945 free(io);
5946
5947 return 1;
5948}
5949
5950bool
5951rb_io_fptr_finalize_closed(struct rb_io *io)
5952{
5953 if (!io) return true;
5954 if (io->fd >= 0) return false;
5956 return true;
5957}
5958
5959size_t
5960rb_io_memsize(const rb_io_t *io)
5961{
5962 size_t size = sizeof(rb_io_t);
5963 size += io->rbuf.capa;
5964 size += io->wbuf.capa;
5965 size += io->cbuf.capa;
5966 if (io->readconv) size += rb_econv_memsize(io->readconv);
5967 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5968
5969 struct rb_io_blocking_operation *blocking_operation = 0;
5970
5971 // 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.
5972 rb_serial_t fork_generation = GET_VM()->fork_gen;
5973 if (io->fork_generation == fork_generation) {
5974 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5975 size += sizeof(struct rb_io_blocking_operation);
5976 }
5977 }
5978
5979 return size;
5980}
5981
5982#ifdef _WIN32
5983/* keep GVL while closing to prevent crash on Windows */
5984# define KEEPGVL TRUE
5985#else
5986# define KEEPGVL FALSE
5987#endif
5988
5989static rb_io_t *
5990io_close_fptr(VALUE io)
5991{
5992 rb_io_t *fptr;
5993 VALUE write_io;
5994 rb_io_t *write_fptr;
5995
5996 write_io = GetWriteIO(io);
5997 if (io != write_io) {
5998 write_fptr = RFILE(write_io)->fptr;
5999 if (write_fptr && 0 <= write_fptr->fd) {
6000 rb_io_fptr_cleanup(write_fptr, TRUE);
6001 }
6002 }
6003
6004 fptr = RFILE(io)->fptr;
6005 if (!fptr) return 0;
6006 if (fptr->fd < 0) return 0;
6007
6008 // This guards against multiple threads closing the same IO object:
6009 if (rb_thread_io_close_interrupt(fptr)) {
6010 /* calls close(fptr->fd): */
6011 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
6012 }
6013
6014 rb_io_fptr_cleanup(fptr, FALSE);
6015 return fptr;
6016}
6017
6018static void
6019fptr_waitpid(rb_io_t *fptr, int nohang)
6020{
6021 int status;
6022 if (fptr->pid) {
6023 rb_last_status_clear();
6024 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
6025 fptr->pid = 0;
6026 }
6027}
6028
6029VALUE
6031{
6032 rb_io_t *fptr = io_close_fptr(io);
6033 if (fptr) fptr_waitpid(fptr, 0);
6034 return Qnil;
6035}
6036
6037/*
6038 * call-seq:
6039 * close -> nil
6040 *
6041 * Closes the stream for both reading and writing
6042 * if open for either or both; returns +nil+.
6043 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6044 *
6045 * If the stream is open for writing, flushes any buffered writes
6046 * to the operating system before closing.
6047 *
6048 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
6049 * (child exit status).
6050 *
6051 * It is not an error to close an IO object that has already been closed.
6052 * It just returns nil.
6053 *
6054 * Example:
6055 *
6056 * IO.popen('ruby', 'r+') do |pipe|
6057 * puts pipe.closed?
6058 * pipe.close
6059 * puts $?
6060 * puts pipe.closed?
6061 * end
6062 *
6063 * Output:
6064 *
6065 * false
6066 * pid 13760 exit 0
6067 * true
6068 *
6069 * Related: IO#close_read, IO#close_write, IO#closed?.
6070 */
6071
6072static VALUE
6073rb_io_close_m(VALUE io)
6074{
6075 rb_io_t *fptr = rb_io_get_fptr(io);
6076 if (fptr->fd < 0) {
6077 return Qnil;
6078 }
6079 rb_io_close(io);
6080 return Qnil;
6081}
6082
6083static VALUE
6084io_call_close(VALUE io)
6085{
6086 rb_check_funcall(io, rb_intern("close"), 0, 0);
6087 return io;
6088}
6089
6090static VALUE
6091ignore_closed_stream(VALUE io, VALUE exc)
6092{
6093 enum {mesg_len = sizeof(closed_stream)-1};
6094 VALUE mesg = rb_attr_get(exc, idMesg);
6095 if (!RB_TYPE_P(mesg, T_STRING) ||
6096 RSTRING_LEN(mesg) != mesg_len ||
6097 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
6098 rb_exc_raise(exc);
6099 }
6100 return io;
6101}
6102
6103static VALUE
6104io_close(VALUE io)
6105{
6106 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
6107 if (!UNDEF_P(closed) && RTEST(closed)) return io;
6108 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
6109 rb_eIOError, (VALUE)0);
6110 return io;
6111}
6112
6113/*
6114 * call-seq:
6115 * closed? -> true or false
6116 *
6117 * Returns +true+ if the stream is closed for both reading and writing,
6118 * +false+ otherwise.
6119 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6120 *
6121 * IO.popen('ruby', 'r+') do |pipe|
6122 * puts pipe.closed?
6123 * pipe.close_read
6124 * puts pipe.closed?
6125 * pipe.close_write
6126 * puts pipe.closed?
6127 * end
6128 *
6129 * Output:
6130 *
6131 * false
6132 * false
6133 * true
6134 *
6135 * Related: IO#close_read, IO#close_write, IO#close.
6136 */
6137VALUE
6139{
6140 rb_io_t *fptr;
6141 VALUE write_io;
6142 rb_io_t *write_fptr;
6143
6144 write_io = GetWriteIO(io);
6145 if (io != write_io) {
6146 write_fptr = RFILE(write_io)->fptr;
6147 if (write_fptr && 0 <= write_fptr->fd) {
6148 return Qfalse;
6149 }
6150 }
6151
6152 fptr = rb_io_get_fptr(io);
6153 return RBOOL(0 > fptr->fd);
6154}
6155
6156/*
6157 * call-seq:
6158 * close_read -> nil
6159 *
6160 * Closes the stream for reading if open for reading;
6161 * returns +nil+.
6162 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6163 *
6164 * If the stream was opened by IO.popen and is also closed for writing,
6165 * sets global variable <tt>$?</tt> (child exit status).
6166 *
6167 * Example:
6168 *
6169 * IO.popen('ruby', 'r+') do |pipe|
6170 * puts pipe.closed?
6171 * pipe.close_write
6172 * puts pipe.closed?
6173 * pipe.close_read
6174 * puts $?
6175 * puts pipe.closed?
6176 * end
6177 *
6178 * Output:
6179 *
6180 * false
6181 * false
6182 * pid 14748 exit 0
6183 * true
6184 *
6185 * Related: IO#close, IO#close_write, IO#closed?.
6186 */
6187
6188static VALUE
6189rb_io_close_read(VALUE io)
6190{
6191 rb_io_t *fptr;
6192 VALUE write_io;
6193
6194 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6195 if (fptr->fd < 0) return Qnil;
6196 if (is_socket(fptr->fd, fptr->pathv)) {
6197#ifndef SHUT_RD
6198# define SHUT_RD 0
6199#endif
6200 if (shutdown(fptr->fd, SHUT_RD) < 0)
6201 rb_sys_fail_path(fptr->pathv);
6202 fptr->mode &= ~FMODE_READABLE;
6203 if (!(fptr->mode & FMODE_WRITABLE))
6204 return rb_io_close(io);
6205 return Qnil;
6206 }
6207
6208 write_io = GetWriteIO(io);
6209 if (io != write_io) {
6210 rb_io_t *wfptr;
6211 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6212 wfptr->pid = fptr->pid;
6213 fptr->pid = 0;
6214 RFILE(io)->fptr = wfptr;
6215 /* bind to write_io temporarily to get rid of memory/fd leak */
6216 fptr->tied_io_for_writing = 0;
6217 RFILE(write_io)->fptr = fptr;
6218 rb_io_fptr_cleanup(fptr, FALSE);
6219 /* should not finalize fptr because another thread may be reading it */
6220 return Qnil;
6221 }
6222
6223 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
6224 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
6225 }
6226 return rb_io_close(io);
6227}
6228
6229/*
6230 * call-seq:
6231 * close_write -> nil
6232 *
6233 * Closes the stream for writing if open for writing;
6234 * returns +nil+.
6235 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6236 *
6237 * Flushes any buffered writes to the operating system before closing.
6238 *
6239 * If the stream was opened by IO.popen and is also closed for reading,
6240 * sets global variable <tt>$?</tt> (child exit status).
6241 *
6242 * IO.popen('ruby', 'r+') do |pipe|
6243 * puts pipe.closed?
6244 * pipe.close_read
6245 * puts pipe.closed?
6246 * pipe.close_write
6247 * puts $?
6248 * puts pipe.closed?
6249 * end
6250 *
6251 * Output:
6252 *
6253 * false
6254 * false
6255 * pid 15044 exit 0
6256 * true
6257 *
6258 * Related: IO#close, IO#close_read, IO#closed?.
6259 */
6260
6261static VALUE
6262rb_io_close_write(VALUE io)
6263{
6264 rb_io_t *fptr;
6265 VALUE write_io;
6266
6267 write_io = GetWriteIO(io);
6268 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6269 if (fptr->fd < 0) return Qnil;
6270 if (is_socket(fptr->fd, fptr->pathv)) {
6271#ifndef SHUT_WR
6272# define SHUT_WR 1
6273#endif
6274 /* Flush any buffered data before shutting down the write side.
6275 * Otherwise the buffered bytes are silently dropped here, and a
6276 * subsequent #close would try to flush them into the now
6277 * shutdown(SHUT_WR) socket and fail with EPIPE. This matches the
6278 * behaviour of the non-socket path below, which flushes via
6279 * rb_io_close(). */
6280 if (fptr->mode & FMODE_WRITABLE) {
6281 if (io_fflush(fptr) < 0)
6282 rb_sys_fail_on_write(fptr);
6283 }
6284 if (shutdown(fptr->fd, SHUT_WR) < 0)
6285 rb_sys_fail_path(fptr->pathv);
6286 fptr->mode &= ~FMODE_WRITABLE;
6287 if (!(fptr->mode & FMODE_READABLE))
6288 return rb_io_close(write_io);
6289 return Qnil;
6290 }
6291
6292 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6293 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6294 }
6295
6296 if (io != write_io) {
6297 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6298 fptr->tied_io_for_writing = 0;
6299 }
6300 rb_io_close(write_io);
6301 return Qnil;
6302}
6303
6304/*
6305 * call-seq:
6306 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6307 *
6308 * Behaves like IO#seek, except that it:
6309 *
6310 * - Uses low-level system functions.
6311 * - Returns the new position.
6312 *
6313 */
6314
6315static VALUE
6316rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6317{
6318 VALUE offset, ptrname;
6319 int whence = SEEK_SET;
6320 rb_io_t *fptr;
6321 rb_off_t pos;
6322
6323 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6324 whence = interpret_seek_whence(ptrname);
6325 }
6326 pos = NUM2OFFT(offset);
6327 GetOpenFile(io, fptr);
6328 if ((fptr->mode & FMODE_READABLE) &&
6329 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6330 rb_raise(rb_eIOError, "sysseek for buffered IO");
6331 }
6332 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6333 rb_warn("sysseek for buffered IO");
6334 }
6335 errno = 0;
6336 pos = lseek(fptr->fd, pos, whence);
6337 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6338
6339 return OFFT2NUM(pos);
6340}
6341
6342/*
6343 * call-seq:
6344 * syswrite(object) -> integer
6345 *
6346 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6347 * returns the number bytes written.
6348 * If +object+ is not a string is converted via method to_s:
6349 *
6350 * f = File.new('t.tmp', 'w')
6351 * f.syswrite('foo') # => 3
6352 * f.syswrite(30) # => 2
6353 * f.syswrite(:foo) # => 3
6354 * f.close
6355 *
6356 * This methods should not be used with other stream-writer methods.
6357 *
6358 */
6359
6360static VALUE
6361rb_io_syswrite(VALUE io, VALUE str)
6362{
6363 VALUE tmp;
6364 rb_io_t *fptr;
6365 long n, len;
6366 const char *ptr;
6367
6368 if (!RB_TYPE_P(str, T_STRING))
6369 str = rb_obj_as_string(str);
6370
6371 io = GetWriteIO(io);
6372 GetOpenFile(io, fptr);
6374
6375 if (fptr->wbuf.len) {
6376 rb_warn("syswrite for buffered IO");
6377 }
6378
6379 tmp = rb_str_tmp_frozen_acquire(str);
6380 RSTRING_GETMEM(tmp, ptr, len);
6381 n = rb_io_write_memory(fptr, ptr, len);
6382 if (n < 0) rb_sys_fail_path(fptr->pathv);
6383 rb_str_tmp_frozen_release(str, tmp);
6384
6385 return LONG2FIX(n);
6386}
6387
6388/*
6389 * call-seq:
6390 * sysread(maxlen) -> string
6391 * sysread(maxlen, out_string) -> string
6392 *
6393 * Behaves like IO#readpartial, except that it uses low-level system functions.
6394 *
6395 * This method should not be used with other stream-reader methods.
6396 *
6397 */
6398
6399static VALUE
6400rb_io_sysread(int argc, VALUE *argv, VALUE io)
6401{
6402 VALUE len, str;
6403 rb_io_t *fptr;
6404 long n, ilen;
6405 struct io_internal_read_struct iis;
6406 int shrinkable;
6407
6408 rb_scan_args(argc, argv, "11", &len, &str);
6409 ilen = NUM2LONG(len);
6410
6411 shrinkable = io_setstrbuf(&str, ilen);
6412 if (ilen == 0) return str;
6413
6414 GetOpenFile(io, fptr);
6416
6417 if (READ_DATA_BUFFERED(fptr)) {
6418 rb_raise(rb_eIOError, "sysread for buffered IO");
6419 }
6420
6421 rb_io_check_closed(fptr);
6422
6423 io_setstrbuf(&str, ilen);
6424 iis.th = rb_thread_current();
6425 iis.fptr = fptr;
6426 iis.nonblock = 0;
6427 iis.fd = fptr->fd;
6428 iis.buf = RSTRING_PTR(str);
6429 iis.capa = ilen;
6430 iis.timeout = NULL;
6431 n = io_read_memory_locktmp(str, &iis);
6432
6433 if (n < 0) {
6434 rb_sys_fail_path(fptr->pathv);
6435 }
6436
6437 io_set_read_length(str, n, shrinkable);
6438
6439 if (n == 0 && ilen > 0) {
6440 rb_eof_error();
6441 }
6442
6443 return str;
6444}
6445
6447 struct rb_io *io;
6448 int fd;
6449 void *buf;
6450 size_t count;
6451 rb_off_t offset;
6452};
6453
6454static VALUE
6455internal_pread_func(void *_arg)
6456{
6457 struct prdwr_internal_arg *arg = _arg;
6458
6459 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6460}
6461
6462static VALUE
6463pread_internal_call(VALUE _arg)
6464{
6465 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6466
6467 VALUE scheduler = rb_fiber_scheduler_current();
6468 if (scheduler != Qnil) {
6469 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6470
6471 if (!UNDEF_P(result)) {
6473 }
6474 }
6475
6476 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6477}
6478
6479/*
6480 * call-seq:
6481 * pread(maxlen, offset) -> string
6482 * pread(maxlen, offset, out_string) -> string
6483 *
6484 * Behaves like IO#readpartial, except that it:
6485 *
6486 * - Reads at the given +offset+ (in bytes).
6487 * - Disregards, and does not modify, the stream's position
6488 * (see {Position}[rdoc-ref:IO@Position]).
6489 * - Bypasses any user space buffering in the stream.
6490 *
6491 * Because this method does not disturb the stream's state
6492 * (its position, in particular), +pread+ allows multiple threads and processes
6493 * to use the same \IO object for reading at various offsets.
6494 *
6495 * f = File.open('t.txt')
6496 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6497 * f.pos # => 52
6498 * # Read 12 bytes at offset 0.
6499 * f.pread(12, 0) # => "First line\n"
6500 * # Read 9 bytes at offset 8.
6501 * f.pread(9, 8) # => "ne\nSecon"
6502 * f.close
6503 *
6504 * Not available on some platforms.
6505 *
6506 */
6507static VALUE
6508rb_io_pread(int argc, VALUE *argv, VALUE io)
6509{
6510 VALUE len, offset, str;
6511 rb_io_t *fptr;
6512 ssize_t n;
6513 struct prdwr_internal_arg arg;
6514 int shrinkable;
6515
6516 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6517 arg.count = NUM2SIZET(len);
6518 arg.offset = NUM2OFFT(offset);
6519
6520 shrinkable = io_setstrbuf(&str, (long)arg.count);
6521 if (arg.count == 0) return str;
6522 arg.buf = RSTRING_PTR(str);
6523
6524 GetOpenFile(io, fptr);
6526
6527 arg.io = fptr;
6528 arg.fd = fptr->fd;
6529 rb_io_check_closed(fptr);
6530
6531 rb_str_locktmp(str);
6532 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6533
6534 if (n < 0) {
6535 rb_sys_fail_path(fptr->pathv);
6536 }
6537 io_set_read_length(str, n, shrinkable);
6538 if (n == 0 && arg.count > 0) {
6539 rb_eof_error();
6540 }
6541
6542 return str;
6543}
6544
6545static VALUE
6546internal_pwrite_func(void *_arg)
6547{
6548 struct prdwr_internal_arg *arg = _arg;
6549
6550 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6551}
6552
6553static VALUE
6554pwrite_internal_call(VALUE _arg)
6555{
6556 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6557
6558 VALUE scheduler = rb_fiber_scheduler_current();
6559 if (scheduler != Qnil) {
6560 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6561
6562 if (!UNDEF_P(result)) {
6564 }
6565 }
6566
6567 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
6568}
6569
6570/*
6571 * call-seq:
6572 * pwrite(object, offset) -> integer
6573 *
6574 * Behaves like IO#write, except that it:
6575 *
6576 * - Writes at the given +offset+ (in bytes).
6577 * - Disregards, and does not modify, the stream's position
6578 * (see {Position}[rdoc-ref:IO@Position]).
6579 * - Bypasses any user space buffering in the stream.
6580 *
6581 * Because this method does not disturb the stream's state
6582 * (its position, in particular), +pwrite+ allows multiple threads and processes
6583 * to use the same \IO object for writing at various offsets.
6584 *
6585 * f = File.open('t.tmp', 'w+')
6586 * # Write 6 bytes at offset 3.
6587 * f.pwrite('ABCDEF', 3) # => 6
6588 * f.rewind
6589 * f.read # => "\u0000\u0000\u0000ABCDEF"
6590 * f.close
6591 *
6592 * Not available on some platforms.
6593 *
6594 */
6595static VALUE
6596rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6597{
6598 rb_io_t *fptr;
6599 ssize_t n;
6600 struct prdwr_internal_arg arg;
6601 VALUE tmp;
6602
6603 if (!RB_TYPE_P(str, T_STRING))
6604 str = rb_obj_as_string(str);
6605
6606 arg.offset = NUM2OFFT(offset);
6607
6608 io = GetWriteIO(io);
6609 GetOpenFile(io, fptr);
6611
6612 arg.io = fptr;
6613 arg.fd = fptr->fd;
6614
6615 tmp = rb_str_tmp_frozen_acquire(str);
6616 arg.buf = RSTRING_PTR(tmp);
6617 arg.count = (size_t)RSTRING_LEN(tmp);
6618
6619 n = (ssize_t)pwrite_internal_call((VALUE)&arg);
6620 if (n < 0) rb_sys_fail_path(fptr->pathv);
6621 rb_str_tmp_frozen_release(str, tmp);
6622
6623 return SSIZET2NUM(n);
6624}
6625
6626VALUE
6628{
6629 rb_io_t *fptr;
6630
6631 GetOpenFile(io, fptr);
6632 if (fptr->readconv)
6634 if (fptr->writeconv)
6636 fptr->mode |= FMODE_BINMODE;
6637 fptr->mode &= ~FMODE_TEXTMODE;
6638 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6639#ifdef O_BINARY
6640 if (!fptr->readconv) {
6641 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6642 }
6643 else {
6644 setmode(fptr->fd, O_BINARY);
6645 }
6646#endif
6647 return io;
6648}
6649
6650static void
6651io_ascii8bit_binmode(rb_io_t *fptr)
6652{
6653 if (fptr->readconv) {
6654 rb_econv_close(fptr->readconv);
6655 fptr->readconv = NULL;
6656 }
6657 if (fptr->writeconv) {
6659 fptr->writeconv = NULL;
6660 }
6661 fptr->mode |= FMODE_BINMODE;
6662 fptr->mode &= ~FMODE_TEXTMODE;
6663 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6664
6665 fptr->encs.enc = rb_ascii8bit_encoding();
6666 fptr->encs.enc2 = NULL;
6667 fptr->encs.ecflags = 0;
6668 fptr->encs.ecopts = Qnil;
6669 clear_codeconv(fptr);
6670}
6671
6672VALUE
6674{
6675 rb_io_t *fptr;
6676
6677 GetOpenFile(io, fptr);
6678 io_ascii8bit_binmode(fptr);
6679
6680 return io;
6681}
6682
6683/*
6684 * call-seq:
6685 * binmode -> self
6686 *
6687 * Sets the stream's data mode as binary
6688 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6689 *
6690 * A stream's data mode may not be changed from binary to text.
6691 *
6692 */
6693
6694static VALUE
6695rb_io_binmode_m(VALUE io)
6696{
6697 VALUE write_io;
6698
6700
6701 write_io = GetWriteIO(io);
6702 if (write_io != io)
6703 rb_io_ascii8bit_binmode(write_io);
6704 return io;
6705}
6706
6707/*
6708 * call-seq:
6709 * binmode? -> true or false
6710 *
6711 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6712 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6713 *
6714 */
6715static VALUE
6716rb_io_binmode_p(VALUE io)
6717{
6718 rb_io_t *fptr;
6719 GetOpenFile(io, fptr);
6720 return RBOOL(fptr->mode & FMODE_BINMODE);
6721}
6722
6723static const char*
6724rb_io_fmode_modestr(enum rb_io_mode fmode)
6725{
6726 if (fmode & FMODE_APPEND) {
6727 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6728 return MODE_BTMODE("a+", "ab+", "at+");
6729 }
6730 return MODE_BTMODE("a", "ab", "at");
6731 }
6732 switch (fmode & FMODE_READWRITE) {
6733 default:
6734 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6735 case FMODE_READABLE:
6736 return MODE_BTMODE("r", "rb", "rt");
6737 case FMODE_WRITABLE:
6738 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6739 case FMODE_READWRITE:
6740 if (fmode & FMODE_CREATE) {
6741 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6742 }
6743 return MODE_BTMODE("r+", "rb+", "rt+");
6744 }
6745}
6746
6747static const char bom_prefix[] = "bom|";
6748static const char utf_prefix[] = "utf-";
6749enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6750enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6751
6752static int
6753io_encname_bom_p(const char *name, long len)
6754{
6755 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6756}
6757
6758enum rb_io_mode
6759rb_io_modestr_fmode(const char *modestr)
6760{
6761 enum rb_io_mode fmode = 0;
6762 const char *m = modestr, *p = NULL;
6763
6764 switch (*m++) {
6765 case 'r':
6766 fmode |= FMODE_READABLE;
6767 break;
6768 case 'w':
6770 break;
6771 case 'a':
6773 break;
6774 default:
6775 goto error;
6776 }
6777
6778 while (*m) {
6779 switch (*m++) {
6780 case 'b':
6781 fmode |= FMODE_BINMODE;
6782 break;
6783 case 't':
6784 fmode |= FMODE_TEXTMODE;
6785 break;
6786 case '+':
6787 fmode |= FMODE_READWRITE;
6788 break;
6789 case 'x':
6790 if (modestr[0] != 'w')
6791 goto error;
6792 fmode |= FMODE_EXCL;
6793 break;
6794 default:
6795 goto error;
6796 case ':':
6797 p = strchr(m, ':');
6798 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6799 fmode |= FMODE_SETENC_BY_BOM;
6800 goto finished;
6801 }
6802 }
6803
6804 finished:
6805 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6806 goto error;
6807
6808 return fmode;
6809
6810 error:
6811 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6813}
6814
6815int
6816rb_io_oflags_fmode(int oflags)
6817{
6818 enum rb_io_mode fmode = 0;
6819
6820 switch (oflags & O_ACCMODE) {
6821 case O_RDONLY:
6822 fmode = FMODE_READABLE;
6823 break;
6824 case O_WRONLY:
6825 fmode = FMODE_WRITABLE;
6826 break;
6827 case O_RDWR:
6828 fmode = FMODE_READWRITE;
6829 break;
6830 }
6831
6832 if (oflags & O_APPEND) {
6833 fmode |= FMODE_APPEND;
6834 }
6835 if (oflags & O_TRUNC) {
6836 fmode |= FMODE_TRUNC;
6837 }
6838 if (oflags & O_CREAT) {
6839 fmode |= FMODE_CREATE;
6840 }
6841 if (oflags & O_EXCL) {
6842 fmode |= FMODE_EXCL;
6843 }
6844#ifdef O_BINARY
6845 if (oflags & O_BINARY) {
6846 fmode |= FMODE_BINMODE;
6847 }
6848#endif
6849
6850 return fmode;
6851}
6852
6853static int
6854rb_io_fmode_oflags(enum rb_io_mode fmode)
6855{
6856 int oflags = 0;
6857
6858 switch (fmode & FMODE_READWRITE) {
6859 case FMODE_READABLE:
6860 oflags |= O_RDONLY;
6861 break;
6862 case FMODE_WRITABLE:
6863 oflags |= O_WRONLY;
6864 break;
6865 case FMODE_READWRITE:
6866 oflags |= O_RDWR;
6867 break;
6868 }
6869
6870 if (fmode & FMODE_APPEND) {
6871 oflags |= O_APPEND;
6872 }
6873 if (fmode & FMODE_TRUNC) {
6874 oflags |= O_TRUNC;
6875 }
6876 if (fmode & FMODE_CREATE) {
6877 oflags |= O_CREAT;
6878 }
6879 if (fmode & FMODE_EXCL) {
6880 oflags |= O_EXCL;
6881 }
6882#ifdef O_BINARY
6883 if (fmode & FMODE_BINMODE) {
6884 oflags |= O_BINARY;
6885 }
6886#endif
6887
6888 return oflags;
6889}
6890
6891int
6892rb_io_modestr_oflags(const char *modestr)
6893{
6894 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6895}
6896
6897static const char*
6898rb_io_oflags_modestr(int oflags)
6899{
6900#ifdef O_BINARY
6901# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6902#else
6903# define MODE_BINARY(a,b) (a)
6904#endif
6905 int accmode;
6906 if (oflags & O_EXCL) {
6907 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6908 }
6909 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6910 if (oflags & O_APPEND) {
6911 if (accmode == O_WRONLY) {
6912 return MODE_BINARY("a", "ab");
6913 }
6914 if (accmode == O_RDWR) {
6915 return MODE_BINARY("a+", "ab+");
6916 }
6917 }
6918 switch (accmode) {
6919 default:
6920 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6921 case O_RDONLY:
6922 return MODE_BINARY("r", "rb");
6923 case O_WRONLY:
6924 return MODE_BINARY("w", "wb");
6925 case O_RDWR:
6926 if (oflags & O_TRUNC) {
6927 return MODE_BINARY("w+", "wb+");
6928 }
6929 return MODE_BINARY("r+", "rb+");
6930 }
6931}
6932
6933/*
6934 * Convert external/internal encodings to enc/enc2
6935 * NULL => use default encoding
6936 * Qnil => no encoding specified (internal only)
6937 */
6938static void
6939rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6940{
6941 int default_ext = 0;
6942
6943 if (ext == NULL) {
6944 ext = rb_default_external_encoding();
6945 default_ext = 1;
6946 }
6947 if (rb_is_ascii8bit_enc(ext)) {
6948 /* If external is ASCII-8BIT, no transcoding */
6949 intern = NULL;
6950 }
6951 else if (intern == NULL) {
6952 intern = rb_default_internal_encoding();
6953 }
6954 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6955 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6956 /* No internal encoding => use external + no transcoding */
6957 *enc = (default_ext && intern != ext) ? NULL : ext;
6958 *enc2 = NULL;
6959 }
6960 else {
6961 *enc = intern;
6962 *enc2 = ext;
6963 }
6964}
6965
6966static void
6967unsupported_encoding(const char *name, rb_encoding *enc)
6968{
6969 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6970}
6971
6972static void
6973parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6974 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6975{
6976 const char *p;
6977 char encname[ENCODING_MAXNAMELEN+1];
6978 int idx, idx2;
6979 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6980 rb_encoding *ext_enc, *int_enc;
6981 long len;
6982
6983 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6984
6985 p = strrchr(estr, ':');
6986 len = p ? (p++ - estr) : (long)strlen(estr);
6987 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6988 estr += bom_prefix_len;
6989 len -= bom_prefix_len;
6990 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6991 fmode |= FMODE_SETENC_BY_BOM;
6992 }
6993 else {
6994 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6995 fmode &= ~FMODE_SETENC_BY_BOM;
6996 }
6997 }
6998 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6999 idx = -1;
7000 }
7001 else {
7002 if (p) {
7003 memcpy(encname, estr, len);
7004 encname[len] = '\0';
7005 estr = encname;
7006 }
7007 idx = rb_enc_find_index(estr);
7008 }
7009 if (fmode_p) *fmode_p = fmode;
7010
7011 if (idx >= 0)
7012 ext_enc = rb_enc_from_index(idx);
7013 else {
7014 if (idx != -2)
7015 unsupported_encoding(estr, estr_enc);
7016 ext_enc = NULL;
7017 }
7018
7019 int_enc = NULL;
7020 if (p) {
7021 if (*p == '-' && *(p+1) == '\0') {
7022 /* Special case - "-" => no transcoding */
7023 int_enc = (rb_encoding *)Qnil;
7024 }
7025 else {
7026 idx2 = rb_enc_find_index(p);
7027 if (idx2 < 0)
7028 unsupported_encoding(p, estr_enc);
7029 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
7030 int_enc = (rb_encoding *)Qnil;
7031 }
7032 else
7033 int_enc = rb_enc_from_index(idx2);
7034 }
7035 }
7036
7037 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
7038}
7039
7040int
7041rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
7042{
7043 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
7044 int extracted = 0;
7045 rb_encoding *extencoding = NULL;
7046 rb_encoding *intencoding = NULL;
7047
7048 if (!NIL_P(opt)) {
7049 VALUE v;
7050 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
7051 if (v != Qnil) encoding = v;
7052 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
7053 if (v != Qnil) extenc = v;
7054 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
7055 if (!UNDEF_P(v)) intenc = v;
7056 }
7057 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
7058 if (!NIL_P(ruby_verbose)) {
7059 int idx = rb_to_encoding_index(encoding);
7060 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
7061 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
7062 encoding, UNDEF_P(extenc) ? "internal" : "external");
7063 }
7064 encoding = Qnil;
7065 }
7066 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
7067 extencoding = rb_to_encoding(extenc);
7068 }
7069 if (!UNDEF_P(intenc)) {
7070 if (NIL_P(intenc)) {
7071 /* internal_encoding: nil => no transcoding */
7072 intencoding = (rb_encoding *)Qnil;
7073 }
7074 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
7075 char *p = StringValueCStr(tmp);
7076
7077 if (*p == '-' && *(p+1) == '\0') {
7078 /* Special case - "-" => no transcoding */
7079 intencoding = (rb_encoding *)Qnil;
7080 }
7081 else {
7082 intencoding = rb_to_encoding(intenc);
7083 }
7084 }
7085 else {
7086 intencoding = rb_to_encoding(intenc);
7087 }
7088 if (extencoding == intencoding) {
7089 intencoding = (rb_encoding *)Qnil;
7090 }
7091 }
7092 if (!NIL_P(encoding)) {
7093 extracted = 1;
7094 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
7095 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
7096 enc_p, enc2_p, fmode_p);
7097 }
7098 else {
7099 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
7100 }
7101 }
7102 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
7103 extracted = 1;
7104 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
7105 }
7106 return extracted;
7107}
7108
7109static void
7110validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
7111{
7112 enum rb_io_mode fmode = *fmode_p;
7113
7114 if ((fmode & FMODE_READABLE) &&
7115 !enc2 &&
7116 !(fmode & FMODE_BINMODE) &&
7117 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
7118 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
7119
7120 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
7121 rb_raise(rb_eArgError, "newline decorator with binary mode");
7122 }
7123 if (!(fmode & FMODE_BINMODE) &&
7124 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
7125 fmode |= FMODE_TEXTMODE;
7126 *fmode_p = fmode;
7127 }
7128#if !DEFAULT_TEXTMODE
7129 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
7130 fmode &= ~FMODE_TEXTMODE;
7131 *fmode_p = fmode;
7132 }
7133#endif
7134}
7135
7136static void
7137extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
7138{
7139 if (!NIL_P(opthash)) {
7140 VALUE v;
7141 v = rb_hash_aref(opthash, sym_textmode);
7142 if (!NIL_P(v)) {
7143 if (*fmode & FMODE_TEXTMODE)
7144 rb_raise(rb_eArgError, "textmode specified twice");
7145 if (*fmode & FMODE_BINMODE)
7146 rb_raise(rb_eArgError, "both textmode and binmode specified");
7147 if (RTEST(v))
7148 *fmode |= FMODE_TEXTMODE;
7149 }
7150 v = rb_hash_aref(opthash, sym_binmode);
7151 if (!NIL_P(v)) {
7152 if (*fmode & FMODE_BINMODE)
7153 rb_raise(rb_eArgError, "binmode specified twice");
7154 if (*fmode & FMODE_TEXTMODE)
7155 rb_raise(rb_eArgError, "both textmode and binmode specified");
7156 if (RTEST(v))
7157 *fmode |= FMODE_BINMODE;
7158 }
7159
7160 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
7161 rb_raise(rb_eArgError, "both textmode and binmode specified");
7162 }
7163}
7164
7165void
7166rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
7167 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
7168{
7169 VALUE vmode;
7170 int oflags;
7171 enum rb_io_mode fmode;
7172 rb_encoding *enc, *enc2;
7173 int ecflags;
7174 VALUE ecopts;
7175 int has_enc = 0, has_vmode = 0;
7176 VALUE intmode;
7177
7178 vmode = *vmode_p;
7179
7180 /* Set to defaults */
7181 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
7182
7183 vmode_handle:
7184 if (NIL_P(vmode)) {
7185 fmode = FMODE_READABLE;
7186 oflags = O_RDONLY;
7187 }
7188 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
7189 vmode = intmode;
7190 oflags = NUM2INT(intmode);
7191 fmode = rb_io_oflags_fmode(oflags);
7192 }
7193 else {
7194 const char *p;
7195
7196 StringValue(vmode);
7197 p = StringValueCStr(vmode);
7198 fmode = rb_io_modestr_fmode(p);
7199 oflags = rb_io_fmode_oflags(fmode);
7200 p = strchr(p, ':');
7201 if (p) {
7202 has_enc = 1;
7203 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
7204 }
7205 else {
7206 rb_encoding *e;
7207
7208 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7209 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
7210 }
7211 }
7212
7213 if (NIL_P(opthash)) {
7214 ecflags = (fmode & FMODE_READABLE) ?
7217#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7218 ecflags |= (fmode & FMODE_WRITABLE) ?
7219 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7220 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7221#endif
7222 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7223 ecopts = Qnil;
7224 if (fmode & FMODE_BINMODE) {
7225#ifdef O_BINARY
7226 oflags |= O_BINARY;
7227#endif
7228 if (!has_enc)
7229 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7230 }
7231#if DEFAULT_TEXTMODE
7232 else if (NIL_P(vmode)) {
7233 fmode |= DEFAULT_TEXTMODE;
7234 }
7235#endif
7236 }
7237 else {
7238 VALUE v;
7239 if (!has_vmode) {
7240 v = rb_hash_aref(opthash, sym_mode);
7241 if (!NIL_P(v)) {
7242 if (!NIL_P(vmode)) {
7243 rb_raise(rb_eArgError, "mode specified twice");
7244 }
7245 has_vmode = 1;
7246 vmode = v;
7247 goto vmode_handle;
7248 }
7249 }
7250 v = rb_hash_aref(opthash, sym_flags);
7251 if (!NIL_P(v)) {
7252 v = rb_to_int(v);
7253 oflags |= NUM2INT(v);
7254 vmode = INT2NUM(oflags);
7255 fmode = rb_io_oflags_fmode(oflags);
7256 }
7257 extract_binmode(opthash, &fmode);
7258 if (fmode & FMODE_BINMODE) {
7259#ifdef O_BINARY
7260 oflags |= O_BINARY;
7261#endif
7262 if (!has_enc)
7263 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7264 }
7265#if DEFAULT_TEXTMODE
7266 else if (NIL_P(vmode)) {
7267 fmode |= DEFAULT_TEXTMODE;
7268 }
7269#endif
7270 v = rb_hash_aref(opthash, sym_perm);
7271 if (!NIL_P(v)) {
7272 if (vperm_p) {
7273 if (!NIL_P(*vperm_p)) {
7274 rb_raise(rb_eArgError, "perm specified twice");
7275 }
7276 *vperm_p = v;
7277 }
7278 else {
7279 /* perm no use, just ignore */
7280 }
7281 }
7282 ecflags = (fmode & FMODE_READABLE) ?
7285#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7286 ecflags |= (fmode & FMODE_WRITABLE) ?
7287 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7288 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7289#endif
7290
7291 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7292 if (has_enc) {
7293 rb_raise(rb_eArgError, "encoding specified twice");
7294 }
7295 }
7296 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7297 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7298 }
7299
7300 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7301
7302 *vmode_p = vmode;
7303
7304 *oflags_p = oflags;
7305 *fmode_p = fmode;
7306 convconfig_p->enc = enc;
7307 convconfig_p->enc2 = enc2;
7308 convconfig_p->ecflags = ecflags;
7309 convconfig_p->ecopts = ecopts;
7310}
7311
7313 VALUE fname;
7314 int oflags;
7315 mode_t perm;
7316};
7317
7318static void *
7319sysopen_func(void *ptr)
7320{
7321 const struct sysopen_struct *data = ptr;
7322 const char *fname = RSTRING_PTR(data->fname);
7323 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7324}
7325
7326static inline int
7327rb_sysopen_internal(struct sysopen_struct *data)
7328{
7329 int fd;
7330 do {
7331 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7332 } while (fd < 0 && errno == EINTR);
7333 if (0 <= fd)
7334 rb_update_max_fd(fd);
7335 return fd;
7336}
7337
7338static int
7339rb_sysopen(VALUE fname, int oflags, mode_t perm)
7340{
7341 int fd = -1;
7342 struct sysopen_struct data;
7343
7344 data.fname = rb_str_encode_ospath(fname);
7345 StringValueCStr(data.fname);
7346 data.oflags = oflags;
7347 data.perm = perm;
7348
7349 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7350 rb_syserr_fail_path(first_errno, fname);
7351 }
7352 return fd;
7353}
7354
7355static inline FILE *
7356fdopen_internal(int fd, const char *modestr)
7357{
7358 FILE *file;
7359
7360#if defined(__sun)
7361 errno = 0;
7362#endif
7363 file = fdopen(fd, modestr);
7364 if (!file) {
7365#ifdef _WIN32
7366 if (errno == 0) errno = EINVAL;
7367#elif defined(__sun)
7368 if (errno == 0) errno = EMFILE;
7369#endif
7370 }
7371 return file;
7372}
7373
7374FILE *
7375rb_fdopen(int fd, const char *modestr)
7376{
7377 FILE *file = 0;
7378
7379 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7380 rb_syserr_fail(first_errno, 0);
7381 }
7382
7383 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7384#ifdef USE_SETVBUF
7385 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7386 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7387#endif
7388 return file;
7389}
7390
7391static int
7392io_check_tty(rb_io_t *fptr)
7393{
7394 int t = isatty(fptr->fd);
7395 if (t)
7396 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7397 return t;
7398}
7399
7400static VALUE rb_io_internal_encoding(VALUE);
7401static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7402
7403static int
7404io_strip_bom(VALUE io)
7405{
7406 VALUE b1, b2, b3, b4;
7407 rb_io_t *fptr;
7408
7409 GetOpenFile(io, fptr);
7410 if (!(fptr->mode & FMODE_READABLE)) return 0;
7411 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7412 switch (b1) {
7413 case INT2FIX(0xEF):
7414 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7415 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7416 if (b3 == INT2FIX(0xBF)) {
7417 return rb_utf8_encindex();
7418 }
7419 rb_io_ungetbyte(io, b3);
7420 }
7421 rb_io_ungetbyte(io, b2);
7422 break;
7423
7424 case INT2FIX(0xFE):
7425 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7426 if (b2 == INT2FIX(0xFF)) {
7427 return ENCINDEX_UTF_16BE;
7428 }
7429 rb_io_ungetbyte(io, b2);
7430 break;
7431
7432 case INT2FIX(0xFF):
7433 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7434 if (b2 == INT2FIX(0xFE)) {
7435 b3 = rb_io_getbyte(io);
7436 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7437 if (b4 == INT2FIX(0)) {
7438 return ENCINDEX_UTF_32LE;
7439 }
7440 rb_io_ungetbyte(io, b4);
7441 }
7442 rb_io_ungetbyte(io, b3);
7443 return ENCINDEX_UTF_16LE;
7444 }
7445 rb_io_ungetbyte(io, b2);
7446 break;
7447
7448 case INT2FIX(0):
7449 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7450 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7451 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7452 if (b4 == INT2FIX(0xFF)) {
7453 return ENCINDEX_UTF_32BE;
7454 }
7455 rb_io_ungetbyte(io, b4);
7456 }
7457 rb_io_ungetbyte(io, b3);
7458 }
7459 rb_io_ungetbyte(io, b2);
7460 break;
7461 }
7462 rb_io_ungetbyte(io, b1);
7463 return 0;
7464}
7465
7466static rb_encoding *
7467io_set_encoding_by_bom(VALUE io)
7468{
7469 int idx = io_strip_bom(io);
7470 rb_io_t *fptr;
7471 rb_encoding *extenc = NULL;
7472
7473 GetOpenFile(io, fptr);
7474 if (idx) {
7475 extenc = rb_enc_from_index(idx);
7476 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7477 rb_io_internal_encoding(io), Qnil);
7478 }
7479 else {
7480 fptr->encs.enc2 = NULL;
7481 }
7482 return extenc;
7483}
7484
7485static VALUE
7486rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7487 const struct rb_io_encoding *convconfig, mode_t perm)
7488{
7489 VALUE pathv;
7490 rb_io_t *fptr;
7491 struct rb_io_encoding cc;
7492 if (!convconfig) {
7493 /* Set to default encodings */
7494 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7495 cc.ecflags = 0;
7496 cc.ecopts = Qnil;
7497 convconfig = &cc;
7498 }
7499 validate_enc_binmode(&fmode, convconfig->ecflags,
7500 convconfig->enc, convconfig->enc2);
7501
7502 MakeOpenFile(io, fptr);
7503 fptr->mode = fmode;
7504 fptr->encs = *convconfig;
7505 pathv = rb_str_new_frozen(filename);
7506#ifdef O_TMPFILE
7507 if (!(oflags & O_TMPFILE)) {
7508 fptr->pathv = pathv;
7509 }
7510#else
7511 fptr->pathv = pathv;
7512#endif
7513 fptr->fd = rb_sysopen(pathv, oflags, perm);
7514 io_check_tty(fptr);
7515 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7516
7517 return io;
7518}
7519
7520static VALUE
7521rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7522{
7523 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7524 const char *p = strchr(modestr, ':');
7525 struct rb_io_encoding convconfig;
7526
7527 if (p) {
7528 parse_mode_enc(p+1, rb_usascii_encoding(),
7529 &convconfig.enc, &convconfig.enc2, &fmode);
7530 }
7531 else {
7532 rb_encoding *e;
7533 /* Set to default encodings */
7534
7535 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7536 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7537 }
7538
7539 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7542#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7543 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7544 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7545 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7546#endif
7547 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7548 convconfig.ecopts = Qnil;
7549
7550 return rb_file_open_generic(io, filename,
7551 rb_io_fmode_oflags(fmode),
7552 fmode,
7553 &convconfig,
7554 0666);
7555}
7556
7557VALUE
7558rb_file_open_str(VALUE fname, const char *modestr)
7559{
7560 FilePathValue(fname);
7561 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7562}
7563
7564VALUE
7565rb_file_open(const char *fname, const char *modestr)
7566{
7567 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7568}
7569
7570#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7571static struct pipe_list {
7572 rb_io_t *fptr;
7573 struct pipe_list *next;
7574} *pipe_list;
7575
7576static void
7577pipe_add_fptr(rb_io_t *fptr)
7578{
7579 struct pipe_list *list;
7580
7581 list = ALLOC(struct pipe_list);
7582 list->fptr = fptr;
7583 list->next = pipe_list;
7584 pipe_list = list;
7585}
7586
7587static void
7588pipe_del_fptr(rb_io_t *fptr)
7589{
7590 struct pipe_list **prev = &pipe_list;
7591 struct pipe_list *tmp;
7592
7593 while ((tmp = *prev) != 0) {
7594 if (tmp->fptr == fptr) {
7595 *prev = tmp->next;
7596 free(tmp);
7597 return;
7598 }
7599 prev = &tmp->next;
7600 }
7601}
7602
7603#if defined (_WIN32) || defined(__CYGWIN__)
7604static void
7605pipe_atexit(void)
7606{
7607 struct pipe_list *list = pipe_list;
7608 struct pipe_list *tmp;
7609
7610 /* The CRT calls this on whichever thread calls ExitProcess, which can be
7611 * one Ruby does not know, e.g. the console control handler on Ctrl+Break. */
7612 if (!rb_current_execution_context(false)) return;
7613
7614 while (list) {
7615 tmp = list->next;
7616 rb_io_fptr_finalize(list->fptr);
7617 list = tmp;
7618 }
7619}
7620#endif
7621
7622static void
7623pipe_finalize(rb_io_t *fptr, int noraise)
7624{
7625#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7626 int status = 0;
7627 if (fptr->stdio_file) {
7628 status = pclose(fptr->stdio_file);
7629 }
7630 fptr->fd = -1;
7631 fptr->stdio_file = 0;
7632 rb_last_status_set(status, fptr->pid);
7633#else
7634 fptr_finalize(fptr, noraise);
7635#endif
7636 pipe_del_fptr(fptr);
7637}
7638#endif
7639
7640static void
7641fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7642{
7643#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7644 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7645
7646 if (old_finalize == orig->finalize) return;
7647#endif
7648
7649 fptr->finalize = orig->finalize;
7650
7651#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7652 if (old_finalize != pipe_finalize) {
7653 struct pipe_list *list;
7654 for (list = pipe_list; list; list = list->next) {
7655 if (list->fptr == fptr) break;
7656 }
7657 if (!list) pipe_add_fptr(fptr);
7658 }
7659 else {
7660 pipe_del_fptr(fptr);
7661 }
7662#endif
7663}
7664
7665void
7667{
7669 fptr->mode |= FMODE_SYNC;
7670}
7671
7672
7673int
7674rb_pipe(int *pipes)
7675{
7676 int ret;
7677 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7678 if (ret == 0) {
7679 rb_update_max_fd(pipes[0]);
7680 rb_update_max_fd(pipes[1]);
7681 }
7682 return ret;
7683}
7684
7685#ifdef _WIN32
7686#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7687#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7688#endif
7689
7690#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7691struct popen_arg {
7692 VALUE execarg_obj;
7693 struct rb_execarg *eargp;
7694 int modef;
7695 int pair[2];
7696 int write_pair[2];
7697};
7698#endif
7699
7700#ifdef HAVE_WORKING_FORK
7701# ifndef __EMSCRIPTEN__
7702static void
7703popen_redirect(struct popen_arg *p)
7704{
7705 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7706 close(p->write_pair[1]);
7707 if (p->write_pair[0] != 0) {
7708 dup2(p->write_pair[0], 0);
7709 close(p->write_pair[0]);
7710 }
7711 close(p->pair[0]);
7712 if (p->pair[1] != 1) {
7713 dup2(p->pair[1], 1);
7714 close(p->pair[1]);
7715 }
7716 }
7717 else if (p->modef & FMODE_READABLE) {
7718 close(p->pair[0]);
7719 if (p->pair[1] != 1) {
7720 dup2(p->pair[1], 1);
7721 close(p->pair[1]);
7722 }
7723 }
7724 else {
7725 close(p->pair[1]);
7726 if (p->pair[0] != 0) {
7727 dup2(p->pair[0], 0);
7728 close(p->pair[0]);
7729 }
7730 }
7731}
7732# endif
7733
7734#if defined(__linux__)
7735/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7736 * Since /proc may not be available, linux_get_maxfd is just a hint.
7737 * This function, linux_get_maxfd, must be async-signal-safe.
7738 * I.e. opendir() is not usable.
7739 *
7740 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7741 * However they are easy to re-implement in async-signal-safe manner.
7742 * (Also note that there is missing/memcmp.c.)
7743 */
7744static int
7745linux_get_maxfd(void)
7746{
7747 int fd;
7748 char buf[4096], *p, *np, *e;
7749 ssize_t ss;
7750 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7751 if (fd < 0) return fd;
7752 ss = read(fd, buf, sizeof(buf));
7753 if (ss < 0) goto err;
7754 p = buf;
7755 e = buf + ss;
7756 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7757 (np = memchr(p, '\n', e-p)) != NULL) {
7758 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7759 int fdsize;
7760 p += sizeof("FDSize:")-1;
7761 *np = '\0';
7762 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7763 close(fd);
7764 return fdsize;
7765 }
7766 p = np+1;
7767 }
7768 /* fall through */
7769
7770 err:
7771 close(fd);
7772 return (int)ss;
7773}
7774#endif
7775
7776/* This function should be async-signal-safe. */
7777void
7778rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7779{
7780#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7781 int fd, ret;
7782 int max = (int)max_file_descriptor;
7783# ifdef F_MAXFD
7784 /* F_MAXFD is available since NetBSD 2.0. */
7785 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7786 if (ret != -1)
7787 maxhint = max = ret;
7788# elif defined(__linux__)
7789 ret = linux_get_maxfd();
7790 if (maxhint < ret)
7791 maxhint = ret;
7792 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7793# endif
7794 if (max < maxhint)
7795 max = maxhint;
7796 for (fd = lowfd; fd <= max; fd++) {
7797 if (!NIL_P(noclose_fds) &&
7798 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7799 continue;
7800 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7801 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7802 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7803 }
7804# define CONTIGUOUS_CLOSED_FDS 20
7805 if (ret != -1) {
7806 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7807 max = fd + CONTIGUOUS_CLOSED_FDS;
7808 }
7809 }
7810#endif
7811}
7812
7813# ifndef __EMSCRIPTEN__
7814static int
7815popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7816{
7817 struct popen_arg *p = (struct popen_arg*)pp;
7818
7819 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7820}
7821# endif
7822#endif
7823
7824#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7825static VALUE
7826rb_execarg_fixup_v(VALUE execarg_obj)
7827{
7828 rb_execarg_parent_start(execarg_obj);
7829 return Qnil;
7830}
7831#else
7832char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7833#endif
7834
7835#ifndef __EMSCRIPTEN__
7836static VALUE
7837pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7838 const struct rb_io_encoding *convconfig)
7839{
7840 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7841 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7842 rb_pid_t pid = 0;
7843 rb_io_t *fptr;
7844 VALUE port;
7845 rb_io_t *write_fptr;
7846 VALUE write_port;
7847#if defined(HAVE_WORKING_FORK)
7848 int status;
7849 char errmsg[80] = { '\0' };
7850#endif
7851#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7852 int state;
7853 struct popen_arg arg;
7854#endif
7855 int e = 0;
7856#if defined(HAVE_SPAWNV)
7857# define DO_SPAWN(cmd, args) ((args) ? \
7858 spawnv(P_NOWAIT, (cmd), (args)) : \
7859 spawn(P_NOWAIT, (cmd)))
7860# if !defined(HAVE_WORKING_FORK)
7861 char **args = NULL;
7862# endif
7863#endif
7864#if !defined(HAVE_WORKING_FORK)
7865 struct rb_execarg sarg, *sargp = &sarg;
7866#endif
7867 FILE *fp = 0;
7868 int fd = -1;
7869 int write_fd = -1;
7870#if !defined(HAVE_WORKING_FORK)
7871 const char *cmd = 0;
7872
7873 if (prog)
7874 cmd = StringValueCStr(prog);
7875#endif
7876
7877#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7878 arg.execarg_obj = execarg_obj;
7879 arg.eargp = eargp;
7880 arg.modef = fmode;
7881 arg.pair[0] = arg.pair[1] = -1;
7882 arg.write_pair[0] = arg.write_pair[1] = -1;
7883# if !defined(HAVE_WORKING_FORK)
7884 if (eargp && !eargp->use_shell) {
7885 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7886 }
7887# endif
7888 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7890 if (rb_pipe(arg.write_pair) < 0)
7891 rb_sys_fail_str(prog);
7892 if (rb_pipe(arg.pair) < 0) {
7893 e = errno;
7894 close(arg.write_pair[0]);
7895 close(arg.write_pair[1]);
7896 rb_syserr_fail_str(e, prog);
7897 }
7898 if (eargp) {
7899 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7900 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7901 }
7902 break;
7903 case FMODE_READABLE:
7904 if (rb_pipe(arg.pair) < 0)
7905 rb_sys_fail_str(prog);
7906 if (eargp)
7907 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7908 break;
7909 case FMODE_WRITABLE:
7910 if (rb_pipe(arg.pair) < 0)
7911 rb_sys_fail_str(prog);
7912 if (eargp)
7913 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7914 break;
7915 default:
7916 rb_sys_fail_str(prog);
7917 }
7918 if (!NIL_P(execarg_obj)) {
7919 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7920 if (state) {
7921 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7922 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7923 if (0 <= arg.pair[0]) close(arg.pair[0]);
7924 if (0 <= arg.pair[1]) close(arg.pair[1]);
7925 rb_execarg_parent_end(execarg_obj);
7926 rb_jump_tag(state);
7927 }
7928
7929# if defined(HAVE_WORKING_FORK)
7930 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7931# else
7932 rb_execarg_run_options(eargp, sargp, NULL, 0);
7933 while ((pid = DO_SPAWN(cmd, args)) < 0) {
7934 /* exec failed */
7935 switch (e = errno) {
7936 case EAGAIN:
7937# if EWOULDBLOCK != EAGAIN
7938 case EWOULDBLOCK:
7939# endif
7940 rb_thread_sleep(1);
7941 continue;
7942 }
7943 break;
7944 }
7945 if (eargp)
7946 rb_execarg_run_options(sargp, NULL, NULL, 0);
7947# endif
7948 rb_execarg_parent_end(execarg_obj);
7949 }
7950 else {
7951# if defined(HAVE_WORKING_FORK)
7952 pid = rb_call_proc__fork();
7953 if (pid == 0) { /* child */
7954 popen_redirect(&arg);
7955 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7956 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7957 return Qnil;
7958 }
7959# else
7960 rb_notimplement();
7961# endif
7962 }
7963
7964 /* parent */
7965 if (pid < 0) {
7966# if defined(HAVE_WORKING_FORK)
7967 e = errno;
7968# endif
7969 close(arg.pair[0]);
7970 close(arg.pair[1]);
7972 close(arg.write_pair[0]);
7973 close(arg.write_pair[1]);
7974 }
7975# if defined(HAVE_WORKING_FORK)
7976 if (errmsg[0])
7977 rb_syserr_fail(e, errmsg);
7978# endif
7979 rb_syserr_fail_str(e, prog);
7980 }
7981 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7982 close(arg.pair[1]);
7983 fd = arg.pair[0];
7984 close(arg.write_pair[0]);
7985 write_fd = arg.write_pair[1];
7986 }
7987 else if (fmode & FMODE_READABLE) {
7988 close(arg.pair[1]);
7989 fd = arg.pair[0];
7990 }
7991 else {
7992 close(arg.pair[0]);
7993 fd = arg.pair[1];
7994 }
7995#else
7996 cmd = rb_execarg_commandline(eargp, &prog);
7997 if (!NIL_P(execarg_obj)) {
7998 rb_execarg_parent_start(execarg_obj);
7999 rb_execarg_run_options(eargp, sargp, NULL, 0);
8000 }
8001 fp = popen(cmd, modestr);
8002 e = errno;
8003 if (eargp) {
8004 rb_execarg_parent_end(execarg_obj);
8005 rb_execarg_run_options(sargp, NULL, NULL, 0);
8006 }
8007 if (!fp) rb_syserr_fail_path(e, prog);
8008 fd = fileno(fp);
8009#endif
8010
8011 port = io_alloc(rb_cIO);
8012 MakeOpenFile(port, fptr);
8013 fptr->fd = fd;
8014 fptr->stdio_file = fp;
8015 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
8016 if (convconfig) {
8017 fptr->encs = *convconfig;
8018#if RUBY_CRLF_ENVIRONMENT
8021 }
8022#endif
8023 }
8024 else {
8025 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
8027 }
8028#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
8029 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
8030 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
8031 }
8032#endif
8033 }
8034 fptr->pid = pid;
8035
8036 if (0 <= write_fd) {
8037 write_port = io_alloc(rb_cIO);
8038 MakeOpenFile(write_port, write_fptr);
8039 write_fptr->fd = write_fd;
8040 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
8041 fptr->mode &= ~FMODE_WRITABLE;
8042 fptr->tied_io_for_writing = write_port;
8043 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
8044 }
8045
8046#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
8047 fptr->finalize = pipe_finalize;
8048 pipe_add_fptr(fptr);
8049#endif
8050 return port;
8051}
8052#else
8053static VALUE
8054pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
8055 const struct rb_io_encoding *convconfig)
8056{
8057 rb_raise(rb_eNotImpError, "popen() is not available");
8058}
8059#endif
8060
8061static int
8062is_popen_fork(VALUE prog)
8063{
8064 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
8065#if !defined(HAVE_WORKING_FORK)
8066 rb_raise(rb_eNotImpError,
8067 "fork() function is unimplemented on this machine");
8068#else
8069 return TRUE;
8070#endif
8071 }
8072 return FALSE;
8073}
8074
8075static VALUE
8076pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
8077 const struct rb_io_encoding *convconfig)
8078{
8079 int argc = 1;
8080 VALUE *argv = &prog;
8081 VALUE execarg_obj = Qnil;
8082
8083 if (!is_popen_fork(prog))
8084 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
8085 return pipe_open(execarg_obj, modestr, fmode, convconfig);
8086}
8087
8088static VALUE
8089pipe_close(VALUE io)
8090{
8091 rb_io_t *fptr = io_close_fptr(io);
8092 if (fptr) {
8093 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
8094 }
8095 return Qnil;
8096}
8097
8098static VALUE popen_finish(VALUE port, VALUE klass);
8099
8100/*
8101 * call-seq:
8102 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
8103 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
8104 *
8105 * Executes the given command +cmd+ as a subprocess
8106 * whose $stdin and $stdout are connected to a new stream +io+.
8107 *
8108 * This method has potential security vulnerabilities if called with untrusted input;
8109 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
8110 *
8111 * If no block is given, returns the new stream,
8112 * which depending on given +mode+ may be open for reading, writing, or both.
8113 * The stream should be explicitly closed (eventually) to avoid resource leaks.
8114 *
8115 * If a block is given, the stream is passed to the block
8116 * (again, open for reading, writing, or both);
8117 * when the block exits, the stream is closed,
8118 * the block's value is returned,
8119 * and the global variable <tt>$?</tt> is set to the child's exit status.
8120 *
8121 * Optional argument +mode+ may be any valid \IO mode.
8122 * See {Access Modes}[rdoc-ref:File@Access+Modes].
8123 *
8124 * Required argument +cmd+ determines which of the following occurs:
8125 *
8126 * - The process forks.
8127 * - A specified program runs in a shell.
8128 * - A specified program runs with specified arguments.
8129 * - A specified program runs with specified arguments and a specified +argv0+.
8130 *
8131 * Each of these is detailed below.
8132 *
8133 * The optional hash argument +env+ specifies name/value pairs that are to be added
8134 * to the environment variables for the subprocess:
8135 *
8136 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
8137 * pipe.puts 'puts ENV["FOO"]'
8138 * pipe.close_write
8139 * pipe.gets
8140 * end => "bar\n"
8141 *
8142 * Optional keyword arguments +opts+ specify:
8143 *
8144 * - {Open options}[rdoc-ref:IO@Open+Options].
8145 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8146 * - Options for Kernel#spawn.
8147 *
8148 * <b>Forked Process</b>
8149 *
8150 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
8151 * IO.popen('-') do |pipe|
8152 * if pipe
8153 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
8154 * else
8155 * $stderr.puts "In child, pid is #{$$}\n"
8156 * end
8157 * end
8158 *
8159 * Output:
8160 *
8161 * In parent, child pid is 26253
8162 * In child, pid is 26253
8163 *
8164 * Note that this is not supported on all platforms.
8165 *
8166 * <b>Shell Subprocess</b>
8167 *
8168 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
8169 * the program named +cmd+ is run as a shell command:
8170 *
8171 * IO.popen('uname') do |pipe|
8172 * pipe.readlines
8173 * end
8174 *
8175 * Output:
8176 *
8177 * ["Linux\n"]
8178 *
8179 * Another example:
8180 *
8181 * IO.popen('/bin/sh', 'r+') do |pipe|
8182 * pipe.puts('ls')
8183 * pipe.close_write
8184 * $stderr.puts pipe.readlines.size
8185 * end
8186 *
8187 * Output:
8188 *
8189 * 213
8190 *
8191 * <b>Program Subprocess</b>
8192 *
8193 * When argument +cmd+ is an array of strings,
8194 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
8195 *
8196 * IO.popen(['du', '..', '.']) do |pipe|
8197 * $stderr.puts pipe.readlines.size
8198 * end
8199 *
8200 * Output:
8201 *
8202 * 1111
8203 *
8204 * <b>Program Subprocess with <tt>argv0</tt></b>
8205 *
8206 * When argument +cmd+ is an array whose first element is a 2-element string array
8207 * and whose remaining elements (if any) are strings:
8208 *
8209 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
8210 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
8211 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
8212 *
8213 * Example (sets <tt>$0</tt> to 'foo'):
8214 *
8215 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
8216 *
8217 * <b>Some Special Examples</b>
8218 *
8219 * # Set IO encoding.
8220 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
8221 * euc_jp_string = nkf_io.read
8222 * }
8223 *
8224 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
8225 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
8226 * ls_result_with_error = io.read
8227 * end
8228 *
8229 * # Use mixture of spawn options and IO options.
8230 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
8231 * ls_result_with_error = io.read
8232 * end
8233 *
8234 * f = IO.popen("uname")
8235 * p f.readlines
8236 * f.close
8237 * puts "Parent is #{Process.pid}"
8238 * IO.popen("date") {|f| puts f.gets }
8239 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
8240 * p $?
8241 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
8242 * f.puts "bar"; f.close_write; puts f.gets
8243 * }
8244 *
8245 * Output (from last section):
8246 *
8247 * ["Linux\n"]
8248 * Parent is 21346
8249 * Thu Jan 15 22:41:19 JST 2009
8250 * 21346 is here, f is #<IO:fd 3>
8251 * 21352 is here, f is nil
8252 * #<Process::Status: pid 21352 exit 0>
8253 * <foo>bar;zot;
8254 *
8255 * Raises exceptions that IO.pipe and Kernel.spawn raise.
8256 *
8257 */
8258
8259static VALUE
8260rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
8261{
8262 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
8263
8264 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8265 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8266 switch (argc) {
8267 case 2:
8268 pmode = argv[1];
8269 case 1:
8270 pname = argv[0];
8271 break;
8272 default:
8273 {
8274 int ex = !NIL_P(opt);
8275 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8276 }
8277 }
8278 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8279}
8280
8281VALUE
8282rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8283{
8284 const char *modestr;
8285 VALUE tmp, execarg_obj = Qnil;
8286 int oflags;
8287 enum rb_io_mode fmode;
8288 struct rb_io_encoding convconfig;
8289
8290 tmp = rb_check_array_type(pname);
8291 if (!NIL_P(tmp)) {
8292 long len = RARRAY_LEN(tmp);
8293#if SIZEOF_LONG > SIZEOF_INT
8294 if (len > INT_MAX) {
8295 rb_raise(rb_eArgError, "too many arguments");
8296 }
8297#endif
8298 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8299 RB_GC_GUARD(tmp);
8300 }
8301 else {
8302 StringValue(pname);
8303 execarg_obj = Qnil;
8304 if (!is_popen_fork(pname))
8305 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8306 }
8307 if (!NIL_P(execarg_obj)) {
8308 if (!NIL_P(opt))
8309 opt = rb_execarg_extract_options(execarg_obj, opt);
8310 if (!NIL_P(env))
8311 rb_execarg_setenv(execarg_obj, env);
8312 }
8313 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8314 modestr = rb_io_oflags_modestr(oflags);
8315
8316 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8317}
8318
8319static VALUE
8320popen_finish(VALUE port, VALUE klass)
8321{
8322 if (NIL_P(port)) {
8323 /* child */
8324 if (rb_block_given_p()) {
8325 rb_protect(rb_yield, Qnil, NULL);
8326 rb_io_flush(rb_ractor_stdout());
8327 rb_io_flush(rb_ractor_stderr());
8328 _exit(EXIT_SUCCESS);
8329 }
8330 return Qnil;
8331 }
8332 RBASIC_SET_CLASS(port, klass);
8333 if (rb_block_given_p()) {
8334 return rb_ensure(rb_yield, port, pipe_close, port);
8335 }
8336 return port;
8337}
8338
8339#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8340struct popen_writer_arg {
8341 char *const *argv;
8342 struct popen_arg popen;
8343};
8344
8345static int
8346exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8347{
8348 struct popen_writer_arg *pw = arg;
8349 pw->popen.modef = FMODE_WRITABLE;
8350 popen_redirect(&pw->popen);
8351 execv(pw->argv[0], pw->argv);
8352 strlcpy(errmsg, strerror(errno), buflen);
8353 return -1;
8354}
8355#endif
8356
8357FILE *
8358ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8359{
8360#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8361# ifdef HAVE_WORKING_FORK
8362 struct popen_writer_arg pw;
8363 int *const write_pair = pw.popen.pair;
8364# else
8365 int write_pair[2];
8366# endif
8367
8368 *pid = -1;
8369 if (cloexec_pipe(write_pair, 0, false) == 0) {
8370# ifdef HAVE_WORKING_FORK
8371 pw.argv = argv;
8372 int status;
8373 char errmsg[80] = {'\0'};
8374 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8375# else
8376 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8377 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8378# endif
8379 close(write_pair[0]);
8380 if (*pid < 0) {
8381 close(write_pair[1]);
8382 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8383 }
8384 else {
8385 return fdopen(write_pair[1], "w");
8386 }
8387 }
8388#endif
8389 return NULL;
8390}
8391
8392static VALUE
8393rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8394{
8395 int oflags;
8396 enum rb_io_mode fmode;
8397 struct rb_io_encoding convconfig;
8398 mode_t perm;
8399
8400 FilePathValue(fname);
8401
8402 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8403 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8404
8405 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8406
8407 return io;
8408}
8409
8410/*
8411 * Document-method: File::open
8412 *
8413 * :markup: markdown
8414 *
8415 * call-seq:
8416 * File.open(path, mode = 'r', permissions = 0666, **options) -> file
8417 * File.open(path, mode = 'r', permissions = 0666, **options) {|file| ... } -> object
8418 *
8419 * Creates a new \File object via File.new with the given arguments.
8420 *
8421 * With no block given, returns the \File object.
8422 *
8423 * With a block given, calls the block with the \File object,
8424 * closes the \File object, and returns the block's value:
8425 *
8426 * ```ruby
8427 * File.open('doc/maintainers.md') {|file| file.size } # => 14900
8428 * ```
8429 *
8430 * Note that the \File object is automatically closed
8431 * even if the block raises an exception.
8432 */
8433
8434/*
8435 * Document-method: IO::open
8436 *
8437 * :markup: markdown
8438 *
8439 * call-seq:
8440 * IO.open(fd, mode = 'r', **options) -> io
8441 * IO.open(fd, mode = 'r', **options) {|io| ... } -> object
8442 *
8443 * Creates a new \IO object via IO.new with the given arguments.
8444 *
8445 * With no block given, returns the \IO object.
8446 *
8447 * With a block given, calls the block with the \IO object,
8448 * closes the \IO object, and returns the block’s value:
8449 *
8450 * ```ruby
8451 * fd = File.sysopen('doc/maintainers.md') # => 6
8452 * IO.open(fd) {|io| io.read.size } # => 14897
8453 * ```
8454 */
8455
8456static VALUE
8457rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8458{
8460
8461 if (rb_block_given_p()) {
8462 return rb_ensure(rb_yield, io, io_close, io);
8463 }
8464
8465 return io;
8466}
8467
8468/*
8469 * call-seq:
8470 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8471 *
8472 * Opens the file at the given path with the given mode and permissions;
8473 * returns the integer file descriptor.
8474 *
8475 * If the file is to be readable, it must exist;
8476 * if the file is to be writable and does not exist,
8477 * it is created with the given permissions:
8478 *
8479 * File.write('t.tmp', '') # => 0
8480 * IO.sysopen('t.tmp') # => 8
8481 * IO.sysopen('t.tmp', 'w') # => 9
8482 *
8483 *
8484 */
8485
8486static VALUE
8487rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8488{
8489 VALUE fname, vmode, vperm;
8490 VALUE intmode;
8491 int oflags, fd;
8492 mode_t perm;
8493
8494 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8495 FilePathValue(fname);
8496
8497 if (NIL_P(vmode))
8498 oflags = O_RDONLY;
8499 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8500 oflags = NUM2INT(intmode);
8501 else {
8502 StringValue(vmode);
8503 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8504 }
8505 if (NIL_P(vperm)) perm = 0666;
8506 else perm = NUM2MODET(vperm);
8507
8508 RB_GC_GUARD(fname) = rb_str_new4(fname);
8509 fd = rb_sysopen(fname, oflags, perm);
8510 return INT2NUM(fd);
8511}
8512
8513/*
8514 * call-seq:
8515 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8516 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8517 *
8518 * Creates an IO object connected to the given file.
8519 *
8520 * With no block given, file stream is returned:
8521 *
8522 * open('t.txt') # => #<File:t.txt>
8523 *
8524 * With a block given, calls the block with the open file stream,
8525 * then closes the stream:
8526 *
8527 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8528 *
8529 * Output:
8530 *
8531 * #<File:t.txt>
8532 *
8533 * See File.open for details.
8534 *
8535 */
8536
8537static VALUE
8538rb_f_open(int argc, VALUE *argv, VALUE _)
8539{
8540 ID to_open = 0;
8541 int redirect = FALSE;
8542
8543 if (argc >= 1) {
8544 CONST_ID(to_open, "to_open");
8545 if (rb_respond_to(argv[0], to_open)) {
8546 redirect = TRUE;
8547 }
8548 else {
8549 VALUE tmp = argv[0];
8550 FilePathValue(tmp);
8551 if (NIL_P(tmp)) {
8552 redirect = TRUE;
8553 }
8554 else {
8555 argv[0] = tmp;
8556 }
8557 }
8558 }
8559 if (redirect) {
8560 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8561
8562 if (rb_block_given_p()) {
8563 return rb_ensure(rb_yield, io, io_close, io);
8564 }
8565 return io;
8566 }
8567 return rb_io_s_open(argc, argv, rb_cFile);
8568}
8569
8570static VALUE
8571rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8572 const struct rb_io_encoding *convconfig, mode_t perm)
8573{
8574 return rb_file_open_generic(io_alloc(klass), filename,
8575 oflags, fmode, convconfig, perm);
8576}
8577
8578static VALUE
8579rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8580{
8581 int oflags;
8582 enum rb_io_mode fmode;
8583 struct rb_io_encoding convconfig;
8584 mode_t perm;
8585
8586 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8587 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8588 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8589}
8590
8591static VALUE
8592io_reopen(VALUE io, VALUE nfile)
8593{
8594 rb_io_t *fptr, *orig;
8595 int fd, fd2;
8596 rb_off_t pos = 0;
8597
8598 nfile = rb_io_get_io(nfile);
8599 GetOpenFile(io, fptr);
8600 GetOpenFile(nfile, orig);
8601
8602 if (fptr == orig) return io;
8603 if (RUBY_IO_EXTERNAL_P(fptr)) {
8604 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8605 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8606 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8607 rb_raise(rb_eArgError,
8608 "%s can't change access mode from \"%s\" to \"%s\"",
8609 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8610 rb_io_fmode_modestr(orig->mode));
8611 }
8612 }
8613 flush_before_seek(fptr, true);
8614 /* in flush_before_seek, clear_codeconv called only if rbuf is filled */
8615 clear_codeconv(fptr);
8616 if (orig->mode & FMODE_READABLE) {
8617 pos = io_tell(orig);
8618 }
8619 if (orig->mode & FMODE_WRITABLE) {
8620 if (io_fflush(orig) < 0)
8621 rb_sys_fail_on_write(fptr);
8622 }
8623
8624 /* copy rb_io_t structure */
8625 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8626 fptr->encs = orig->encs;
8627 fptr->pid = orig->pid;
8628 fptr->lineno = orig->lineno;
8629 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8630 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8631 fptr_copy_finalizer(fptr, orig);
8632
8633 fd = fptr->fd;
8634 fd2 = orig->fd;
8635 if (fd != fd2) {
8636 // Interrupt all usage of the old file descriptor:
8637 rb_thread_io_close_interrupt(fptr);
8638 rb_thread_io_close_wait(fptr);
8639
8640 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8641 /* need to keep FILE objects of stdin, stdout and stderr */
8642 if (rb_cloexec_dup2(fd2, fd) < 0)
8643 rb_sys_fail_path(orig->pathv);
8644 rb_update_max_fd(fd);
8645 }
8646 else {
8647 fclose(fptr->stdio_file);
8648 fptr->stdio_file = 0;
8649 fptr->fd = -1;
8650 if (rb_cloexec_dup2(fd2, fd) < 0)
8651 rb_sys_fail_path(orig->pathv);
8652 rb_update_max_fd(fd);
8653 fptr->fd = fd;
8654 }
8655
8656 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8657 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8658 rb_sys_fail_path(fptr->pathv);
8659 }
8660 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8661 rb_sys_fail_path(orig->pathv);
8662 }
8663 }
8664 }
8665
8666 if (fptr->mode & FMODE_BINMODE) {
8667 rb_io_binmode(io);
8668 }
8669
8670 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8671 return io;
8672}
8673
8674#ifdef _WIN32
8675int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8676#else
8677static int
8678rb_freopen(VALUE fname, const char *mode, FILE *fp)
8679{
8680 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8681 RB_GC_GUARD(fname);
8682 return errno;
8683 }
8684 return 0;
8685}
8686#endif
8687
8688/*
8689 * call-seq:
8690 * reopen(other_io) -> self
8691 * reopen(path, mode = 'r', **opts) -> self
8692 *
8693 * Reassociates the stream with another stream,
8694 * which may be of a different class.
8695 * This method may be used to redirect an existing stream
8696 * to a new destination.
8697 *
8698 * With argument +other_io+ given, reassociates with that stream:
8699 *
8700 * # Redirect $stdin from a file.
8701 * f = File.open('t.txt')
8702 * $stdin.reopen(f)
8703 * f.close
8704 *
8705 * # Redirect $stdout to a file.
8706 * f = File.open('t.tmp', 'w')
8707 * $stdout.reopen(f)
8708 * f.close
8709 *
8710 * With argument +path+ given, reassociates with a new stream to that file path:
8711 *
8712 * $stdin.reopen('t.txt')
8713 * $stdout.reopen('t.tmp', 'w')
8714 *
8715 * Optional keyword arguments +opts+ specify:
8716 *
8717 * - {Open Options}[rdoc-ref:IO@Open+Options].
8718 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8719 *
8720 */
8721
8722static VALUE
8723rb_io_reopen(int argc, VALUE *argv, VALUE file)
8724{
8725 VALUE fname, nmode, opt;
8726 int oflags;
8727 rb_io_t *fptr;
8728
8729 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8730 VALUE tmp = rb_io_check_io(fname);
8731 if (!NIL_P(tmp)) {
8732 return io_reopen(file, tmp);
8733 }
8734 }
8735
8736 FilePathValue(fname);
8737 rb_io_taint_check(file);
8738 fptr = RFILE(file)->fptr;
8739 if (!fptr) {
8740 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8741 }
8742
8743 if (!NIL_P(nmode) || !NIL_P(opt)) {
8744 enum rb_io_mode fmode;
8745 struct rb_io_encoding convconfig;
8746
8747 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8748 if (RUBY_IO_EXTERNAL_P(fptr) &&
8749 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8750 (fptr->mode & FMODE_READWRITE)) {
8751 rb_raise(rb_eArgError,
8752 "%s can't change access mode from \"%s\" to \"%s\"",
8753 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8754 rb_io_fmode_modestr(fmode));
8755 }
8756 fptr->mode = fmode;
8757 fptr->encs = convconfig;
8758 }
8759 else {
8760 oflags = rb_io_fmode_oflags(fptr->mode);
8761 }
8762
8763 fptr->pathv = fname;
8764 if (fptr->fd < 0) {
8765 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8766 fptr->stdio_file = 0;
8767 return file;
8768 }
8769
8770 if (fptr->mode & FMODE_WRITABLE) {
8771 if (io_fflush(fptr) < 0)
8772 rb_sys_fail_on_write(fptr);
8773 }
8774 fptr->rbuf.off = fptr->rbuf.len = 0;
8775 clear_codeconv(fptr);
8776
8777 if (fptr->stdio_file) {
8778 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8779 rb_io_oflags_modestr(oflags),
8780 fptr->stdio_file);
8781 if (e) rb_syserr_fail_path(e, fptr->pathv);
8782 fptr->fd = fileno(fptr->stdio_file);
8783 rb_fd_fix_cloexec(fptr->fd);
8784#ifdef USE_SETVBUF
8785 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8786 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8787#endif
8788 if (fptr->stdio_file == stderr) {
8789 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8790 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8791 }
8792 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8793 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8794 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8795 }
8796 }
8797 else {
8798 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8799 int err = 0;
8800 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8801 err = errno;
8802 (void)close(tmpfd);
8803 if (err) {
8804 rb_syserr_fail_path(err, fptr->pathv);
8805 }
8806 }
8807
8808 return file;
8809}
8810
8811/* :nodoc: */
8812static VALUE
8813rb_io_init_copy(VALUE dest, VALUE io)
8814{
8815 rb_io_t *fptr, *orig;
8816 int fd;
8817 VALUE write_io;
8818 rb_off_t pos;
8819
8820 io = rb_io_get_io(io);
8821 if (!OBJ_INIT_COPY(dest, io)) return dest;
8822 GetOpenFile(io, orig);
8823 MakeOpenFile(dest, fptr);
8824
8825 rb_io_flush(io);
8826
8827 /* copy rb_io_t structure */
8828 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8829 fptr->encs = orig->encs;
8830 fptr->pid = orig->pid;
8831 fptr->lineno = orig->lineno;
8832 fptr->timeout = orig->timeout;
8833
8834 ccan_list_head_init(&fptr->blocking_operations);
8835 fptr->closing_ec = NULL;
8836 fptr->wakeup_mutex = Qnil;
8837 fptr->fork_generation = GET_VM()->fork_gen;
8838
8839 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8840 fptr_copy_finalizer(fptr, orig);
8841
8842 fd = ruby_dup(orig->fd);
8843 fptr->fd = fd;
8844 pos = io_tell(orig);
8845 if (0 <= pos)
8846 io_seek(fptr, pos, SEEK_SET);
8847 if (fptr->mode & FMODE_BINMODE) {
8848 rb_io_binmode(dest);
8849 }
8850
8851 write_io = GetWriteIO(io);
8852 if (io != write_io) {
8853 write_io = rb_obj_dup(write_io);
8854 fptr->tied_io_for_writing = write_io;
8855 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8856 }
8857
8858 return dest;
8859}
8860
8861/*
8862 * call-seq:
8863 * printf(format_string, *objects) -> nil
8864 *
8865 * Formats and writes +objects+ to the stream.
8866 *
8867 * For details on +format_string+, see
8868 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8869 *
8870 */
8871
8872VALUE
8873rb_io_printf(int argc, const VALUE *argv, VALUE out)
8874{
8875 rb_io_write(out, rb_f_sprintf(argc, argv));
8876 return Qnil;
8877}
8878
8879/*
8880 * call-seq:
8881 * printf(format_string, *objects) -> nil
8882 * printf(io, format_string, *objects) -> nil
8883 *
8884 * Equivalent to:
8885 *
8886 * io.write(sprintf(format_string, *objects))
8887 *
8888 * For details on +format_string+, see
8889 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8890 *
8891 * With the single argument +format_string+, formats +objects+ into the string,
8892 * then writes the formatted string to $stdout:
8893 *
8894 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8895 *
8896 * Output (on $stdout):
8897 *
8898 * 0024 24 24.00#
8899 *
8900 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8901 * then writes the formatted string to +io+:
8902 *
8903 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8904 *
8905 * Output (on $stderr):
8906 *
8907 * 0024 24 24.00# => nil
8908 *
8909 * With no arguments, does nothing.
8910 *
8911 */
8912
8913static VALUE
8914rb_f_printf(int argc, VALUE *argv, VALUE _)
8915{
8916 VALUE out;
8917
8918 if (argc == 0) return Qnil;
8919 if (RB_TYPE_P(argv[0], T_STRING)) {
8920 out = rb_ractor_stdout();
8921 }
8922 else {
8923 out = argv[0];
8924 argv++;
8925 argc--;
8926 }
8927 rb_io_write(out, rb_f_sprintf(argc, argv));
8928
8929 return Qnil;
8930}
8931
8932extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
8933
8934static void
8935deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8936{
8937 rb_deprecated_str_setter(val, id, &val);
8938 if (!NIL_P(val)) {
8939 if (rb_str_equal(val, rb_default_rs)) {
8940 val = rb_default_rs;
8941 }
8942 else {
8943 val = rb_str_frozen_bare_string(val);
8944 }
8945 }
8946 *var = val;
8947}
8948
8949/*
8950 * call-seq:
8951 * print(*objects) -> nil
8952 *
8953 * Writes the given objects to the stream; returns +nil+.
8954 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8955 * (<tt>$\</tt>), if it is not +nil+.
8956 * See {Line IO}[rdoc-ref:IO@Line+IO].
8957 *
8958 * With argument +objects+ given, for each object:
8959 *
8960 * - Converts via its method +to_s+ if not a string.
8961 * - Writes to the stream.
8962 * - If not the last object, writes the output field separator
8963 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8964 *
8965 * With default separators:
8966 *
8967 * f = File.open('t.tmp', 'w+')
8968 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8969 * p $OUTPUT_RECORD_SEPARATOR
8970 * p $OUTPUT_FIELD_SEPARATOR
8971 * f.print(*objects)
8972 * f.rewind
8973 * p f.read
8974 * f.close
8975 *
8976 * Output:
8977 *
8978 * nil
8979 * nil
8980 * "00.00/10+0izerozero"
8981 *
8982 * With specified separators:
8983 *
8984 * $\ = "\n"
8985 * $, = ','
8986 * f.rewind
8987 * f.print(*objects)
8988 * f.rewind
8989 * p f.read
8990 *
8991 * Output:
8992 *
8993 * "0,0.0,0/1,0+0i,zero,zero\n"
8994 *
8995 * With no argument given, writes the content of <tt>$_</tt>
8996 * (which is usually the most recent user input):
8997 *
8998 * f = File.open('t.tmp', 'w+')
8999 * gets # Sets $_ to the most recent user input.
9000 * f.print
9001 * f.close
9002 *
9003 */
9004
9005VALUE
9006rb_io_print(int argc, const VALUE *argv, VALUE out)
9007{
9008 int i;
9009 VALUE line;
9010
9011 /* if no argument given, print `$_' */
9012 if (argc == 0) {
9013 argc = 1;
9014 line = rb_lastline_get();
9015 argv = &line;
9016 }
9017 if (argc > 1 && !NIL_P(rb_output_fs)) {
9018 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
9019 }
9020 for (i=0; i<argc; i++) {
9021 if (!NIL_P(rb_output_fs) && i>0) {
9022 rb_io_write(out, rb_output_fs);
9023 }
9024 rb_io_write(out, argv[i]);
9025 }
9026 if (argc > 0 && !NIL_P(rb_output_rs)) {
9027 rb_io_write(out, rb_output_rs);
9028 }
9029
9030 return Qnil;
9031}
9032
9033/*
9034 * call-seq:
9035 * print(*objects) -> nil
9036 *
9037 * Equivalent to <tt>$stdout.print(*objects)</tt>,
9038 * this method is the straightforward way to write to <tt>$stdout</tt>.
9039 *
9040 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
9041 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
9042 * (<tt>$\</tt>), if it is not +nil+.
9043 *
9044 * With argument +objects+ given, for each object:
9045 *
9046 * - Converts via its method +to_s+ if not a string.
9047 * - Writes to <tt>stdout</tt>.
9048 * - If not the last object, writes the output field separator
9049 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
9050 *
9051 * With default separators:
9052 *
9053 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
9054 * $OUTPUT_RECORD_SEPARATOR
9055 * $OUTPUT_FIELD_SEPARATOR
9056 * print(*objects)
9057 *
9058 * Output:
9059 *
9060 * nil
9061 * nil
9062 * 00.00/10+0izerozero
9063 *
9064 * With specified separators:
9065 *
9066 * $OUTPUT_RECORD_SEPARATOR = "\n"
9067 * $OUTPUT_FIELD_SEPARATOR = ','
9068 * print(*objects)
9069 *
9070 * Output:
9071 *
9072 * 0,0.0,0/1,0+0i,zero,zero
9073 *
9074 * With no argument given, writes the content of <tt>$_</tt>
9075 * (which is usually the most recent user input):
9076 *
9077 * gets # Sets $_ to the most recent user input.
9078 * print # Prints $_.
9079 *
9080 */
9081
9082static VALUE
9083rb_f_print(int argc, const VALUE *argv, VALUE _)
9084{
9085 rb_io_print(argc, argv, rb_ractor_stdout());
9086 return Qnil;
9087}
9088
9089/*
9090 * call-seq:
9091 * putc(object) -> object
9092 *
9093 * Writes a character to the stream.
9094 * See {Character IO}[rdoc-ref:IO@Character+IO].
9095 *
9096 * If +object+ is numeric, converts to integer if necessary,
9097 * then writes the character whose code is the
9098 * least significant byte;
9099 * if +object+ is a string, writes the first character:
9100 *
9101 * $stdout.putc "A"
9102 * $stdout.putc 65
9103 *
9104 * Output:
9105 *
9106 * AA
9107 *
9108 */
9109
9110static VALUE
9111rb_io_putc(VALUE io, VALUE ch)
9112{
9113 VALUE str;
9114 if (RB_TYPE_P(ch, T_STRING)) {
9115 str = rb_str_substr(ch, 0, 1);
9116 }
9117 else {
9118 char c = NUM2CHR(ch);
9119 str = rb_str_new(&c, 1);
9120 }
9121 rb_io_write(io, str);
9122 return ch;
9123}
9124
9125#define forward(obj, id, argc, argv) \
9126 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9127#define forward_public(obj, id, argc, argv) \
9128 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9129#define forward_current(id, argc, argv) \
9130 forward_public(ARGF.current_file, id, argc, argv)
9131
9132/*
9133 * call-seq:
9134 * putc(int) -> int
9135 *
9136 * Equivalent to:
9137 *
9138 * $stdout.putc(int)
9139 *
9140 * See IO#putc for important information regarding multi-byte characters.
9141 *
9142 */
9143
9144static VALUE
9145rb_f_putc(VALUE recv, VALUE ch)
9146{
9147 VALUE r_stdout = rb_ractor_stdout();
9148 if (recv == r_stdout) {
9149 return rb_io_putc(recv, ch);
9150 }
9151 return forward(r_stdout, rb_intern("putc"), 1, &ch);
9152}
9153
9154
9155int
9156rb_str_end_with_asciichar(VALUE str, int c)
9157{
9158 long len = RSTRING_LEN(str);
9159 const char *ptr = RSTRING_PTR(str);
9160 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
9161 int n;
9162
9163 if (len == 0) return 0;
9164 if ((n = rb_enc_mbminlen(enc)) == 1) {
9165 return ptr[len - 1] == c;
9166 }
9167 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
9168}
9169
9170static VALUE
9171io_puts_ary(VALUE ary, VALUE out, int recur)
9172{
9173 VALUE tmp;
9174 long i;
9175
9176 if (recur) {
9177 tmp = rb_str_new2("[...]");
9178 rb_io_puts(1, &tmp, out);
9179 return Qtrue;
9180 }
9181 ary = rb_check_array_type(ary);
9182 if (NIL_P(ary)) return Qfalse;
9183 for (i=0; i<RARRAY_LEN(ary); i++) {
9184 tmp = RARRAY_AREF(ary, i);
9185 rb_io_puts(1, &tmp, out);
9186 }
9187 return Qtrue;
9188}
9189
9190/*
9191 * call-seq:
9192 * puts(*objects) -> nil
9193 *
9194 * Writes the given +objects+ to the stream, which must be open for writing;
9195 * returns +nil+.\
9196 * Writes a newline after each that does not already end with a newline sequence.
9197 * If called without arguments, writes a newline.
9198 * See {Line IO}[rdoc-ref:IO@Line+IO].
9199 *
9200 * Note that each added newline is the character <tt>"\n"</tt>,
9201 * not the output record separator (<tt>$\</tt>).
9202 *
9203 * Treatment for each object:
9204 *
9205 * - String: writes the string.
9206 * - Neither string nor array: writes <tt>object.to_s</tt>.
9207 * - Array: writes each element of the array; arrays may be nested.
9208 *
9209 * To keep these examples brief, we define this helper method:
9210 *
9211 * def show(*objects)
9212 * # Puts objects to file.
9213 * f = File.new('t.tmp', 'w+')
9214 * f.puts(objects)
9215 * # Return file content.
9216 * f.rewind
9217 * p f.read
9218 * f.close
9219 * end
9220 *
9221 * # Strings without newlines.
9222 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
9223 * # Strings, some with newlines.
9224 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
9225 *
9226 * # Neither strings nor arrays:
9227 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
9228 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
9229 *
9230 * # Array of strings.
9231 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
9232 * # Nested arrays.
9233 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
9234 *
9235 */
9236
9237VALUE
9238rb_io_puts(int argc, const VALUE *argv, VALUE out)
9239{
9240 VALUE line, args[2];
9241
9242 /* if no argument given, print newline. */
9243 if (argc == 0) {
9244 rb_io_write(out, rb_default_rs);
9245 return Qnil;
9246 }
9247 for (int i = 0; i < argc; i++) {
9248 // Convert the argument to a string:
9249 if (RB_TYPE_P(argv[i], T_STRING)) {
9250 line = argv[i];
9251 }
9252 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9253 continue;
9254 }
9255 else {
9256 line = rb_obj_as_string(argv[i]);
9257 }
9258
9259 // Write the line:
9260 int n = 0;
9261 if (RSTRING_LEN(line) == 0) {
9262 args[n++] = rb_default_rs;
9263 }
9264 else {
9265 args[n++] = line;
9266 if (!rb_str_end_with_asciichar(line, '\n')) {
9267 args[n++] = rb_default_rs;
9268 }
9269 }
9270
9271 rb_io_writev(out, n, args);
9272 }
9273
9274 return Qnil;
9275}
9276
9277/*
9278 * call-seq:
9279 * puts(*objects) -> nil
9280 *
9281 * Equivalent to
9282 *
9283 * $stdout.puts(objects)
9284 */
9285
9286static VALUE
9287rb_f_puts(int argc, VALUE *argv, VALUE recv)
9288{
9289 VALUE r_stdout = rb_ractor_stdout();
9290 if (recv == r_stdout) {
9291 return rb_io_puts(argc, argv, recv);
9292 }
9293 return forward(r_stdout, rb_intern("puts"), argc, argv);
9294}
9295
9296static VALUE
9297rb_p_write(VALUE str)
9298{
9299 VALUE args[2];
9300 args[0] = str;
9301 args[1] = rb_default_rs;
9302 VALUE r_stdout = rb_ractor_stdout();
9303 if (RB_TYPE_P(r_stdout, T_FILE) &&
9304 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9305 io_writev(2, args, r_stdout);
9306 }
9307 else {
9308 rb_io_writev(r_stdout, 2, args);
9309 }
9310 return Qnil;
9311}
9312
9313void
9314rb_p(VALUE obj) /* for debug print within C code */
9315{
9316 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9317}
9318
9319static VALUE
9320rb_p_result(int argc, const VALUE *argv)
9321{
9322 VALUE ret = Qnil;
9323
9324 if (argc == 1) {
9325 ret = argv[0];
9326 }
9327 else if (argc > 1) {
9328 ret = rb_ary_new4(argc, argv);
9329 }
9330 VALUE r_stdout = rb_ractor_stdout();
9331 if (RB_TYPE_P(r_stdout, T_FILE)) {
9332 rb_uninterruptible(rb_io_flush, r_stdout);
9333 }
9334 return ret;
9335}
9336
9337/*
9338 * call-seq:
9339 * p(object) -> obj
9340 * p(*objects) -> array of objects
9341 * p -> nil
9342 *
9343 * For each object +obj+, executes:
9344 *
9345 * $stdout.write(obj.inspect, "\n")
9346 *
9347 * With one object given, returns the object;
9348 * with multiple objects given, returns an array containing the objects;
9349 * with no object given, returns +nil+.
9350 *
9351 * Examples:
9352 *
9353 * r = Range.new(0, 4)
9354 * p r # => 0..4
9355 * p [r, r, r] # => [0..4, 0..4, 0..4]
9356 * p # => nil
9357 *
9358 * Output:
9359 *
9360 * 0..4
9361 * [0..4, 0..4, 0..4]
9362 *
9363 * Kernel#p is designed for debugging purposes.
9364 * Ruby implementations may define Kernel#p to be uninterruptible
9365 * in whole or in part.
9366 * On CRuby, Kernel#p's writing of data is uninterruptible.
9367 */
9368
9369static VALUE
9370rb_f_p(int argc, VALUE *argv, VALUE self)
9371{
9372 int i;
9373 for (i=0; i<argc; i++) {
9374 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9375 rb_uninterruptible(rb_p_write, inspected);
9376 }
9377 return rb_p_result(argc, argv);
9378}
9379
9380/*
9381 * call-seq:
9382 * display(port = $>) -> nil
9383 *
9384 * Writes +self+ on the given port:
9385 *
9386 * 1.display
9387 * "cat".display
9388 * [ 4, 5, 6 ].display
9389 * puts
9390 *
9391 * Output:
9392 *
9393 * 1cat[4, 5, 6]
9394 *
9395 */
9396
9397static VALUE
9398rb_obj_display(int argc, VALUE *argv, VALUE self)
9399{
9400 VALUE out;
9401
9402 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9403 rb_io_write(out, self);
9404
9405 return Qnil;
9406}
9407
9408static int
9409rb_stderr_to_original_p(VALUE err)
9410{
9411 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9412}
9413
9414void
9415rb_write_error2(const char *mesg, long len)
9416{
9417 VALUE out = rb_ractor_stderr();
9418 if (rb_stderr_to_original_p(out)) {
9419#ifdef _WIN32
9420 if (isatty(fileno(stderr))) {
9421 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9422 }
9423#endif
9424 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9425 /* failed to write to stderr, what can we do? */
9426 return;
9427 }
9428 }
9429 else {
9430 rb_io_write(out, rb_str_new(mesg, len));
9431 }
9432}
9433
9434void
9435rb_write_error(const char *mesg)
9436{
9437 rb_write_error2(mesg, strlen(mesg));
9438}
9439
9440void
9441rb_write_error_str(VALUE mesg)
9442{
9443 VALUE out = rb_ractor_stderr();
9444 /* a stopgap measure for the time being */
9445 if (rb_stderr_to_original_p(out)) {
9446 size_t len = (size_t)RSTRING_LEN(mesg);
9447#ifdef _WIN32
9448 if (isatty(fileno(stderr))) {
9449 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9450 }
9451#endif
9452 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9453 RB_GC_GUARD(mesg);
9454 return;
9455 }
9456 }
9457 else {
9458 /* may unlock GVL, and */
9459 rb_io_write(out, mesg);
9460 }
9461}
9462
9463int
9464rb_stderr_tty_p(void)
9465{
9466 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9467 return isatty(fileno(stderr));
9468 return 0;
9469}
9470
9471static void
9472must_respond_to(ID mid, VALUE val, ID id)
9473{
9474 if (!rb_respond_to(val, mid)) {
9475 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9476 rb_id2str(id), rb_id2str(mid),
9477 rb_obj_class(val));
9478 }
9479}
9480
9481static void
9482stdin_setter(VALUE val, ID id, VALUE *ptr)
9483{
9485}
9486
9487static VALUE
9488stdin_getter(ID id, VALUE *ptr)
9489{
9490 return rb_ractor_stdin();
9491}
9492
9493static void
9494stdout_setter(VALUE val, ID id, VALUE *ptr)
9495{
9496 must_respond_to(id_write, val, id);
9498}
9499
9500static VALUE
9501stdout_getter(ID id, VALUE *ptr)
9502{
9503 return rb_ractor_stdout();
9504}
9505
9506static void
9507stderr_setter(VALUE val, ID id, VALUE *ptr)
9508{
9509 must_respond_to(id_write, val, id);
9511}
9512
9513static VALUE
9514stderr_getter(ID id, VALUE *ptr)
9515{
9516 return rb_ractor_stderr();
9517}
9518
9519static VALUE
9520allocate_and_open_new_file(VALUE klass)
9521{
9522 VALUE self = io_alloc(klass);
9523 rb_io_make_open_file(self);
9524 return self;
9525}
9526
9527VALUE
9528rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9529{
9530 int state;
9531 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9532 if (state) {
9533 /* if we raised an exception allocating an IO object, but the caller
9534 intended to transfer ownership of this FD to us, close the fd before
9535 raising the exception. Otherwise, we would leak a FD - the caller
9536 expects GC to close the file, but we never got around to assigning
9537 it to a rb_io. */
9538 if (!(mode & FMODE_EXTERNAL)) {
9539 maygvl_close(descriptor, 0);
9540 }
9541 rb_jump_tag(state);
9542 }
9543
9544
9545 rb_io_t *io = RFILE(self)->fptr;
9546 io->self = self;
9547 io->fd = descriptor;
9548 io->mode = mode;
9549
9550 /* At this point, Ruby fully owns the descriptor, and will close it when
9551 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9552 in the rest of this method. */
9553
9554 if (NIL_P(path)) {
9555 io->pathv = Qnil;
9556 }
9557 else {
9558 StringValue(path);
9559 io->pathv = rb_str_new_frozen(path);
9560 }
9561
9562 io->timeout = timeout;
9563
9564 ccan_list_head_init(&io->blocking_operations);
9565 io->closing_ec = NULL;
9566 io->wakeup_mutex = Qnil;
9567 io->fork_generation = GET_VM()->fork_gen;
9568
9569 if (encoding) {
9570 io->encs = *encoding;
9571 }
9572
9573 rb_update_max_fd(descriptor);
9574
9575 return self;
9576}
9577
9578static VALUE
9579prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9580{
9581 VALUE path_value = Qnil;
9582 rb_encoding *e;
9583 struct rb_io_encoding convconfig;
9584
9585 if (path) {
9586 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9587 }
9588
9589 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9590 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9591 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9594#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9595 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9596 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9597 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9598#endif
9599 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9600 convconfig.ecopts = Qnil;
9601
9602 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9603 rb_io_t*io = RFILE(self)->fptr;
9604
9605 if (!io_check_tty(io)) {
9606#ifdef __CYGWIN__
9607 io->mode |= FMODE_BINMODE;
9608 setmode(fd, O_BINARY);
9609#endif
9610 }
9611
9612 return self;
9613}
9614
9615VALUE
9616rb_io_fdopen(int fd, int oflags, const char *path)
9617{
9618 VALUE klass = rb_cIO;
9619
9620 if (path && strcmp(path, "-")) klass = rb_cFile;
9621 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9622}
9623
9624static VALUE
9625prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9626{
9627 rb_io_t *fptr;
9628 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9629
9630 GetOpenFile(io, fptr);
9632#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9633 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9634 if (fmode & FMODE_READABLE) {
9636 }
9637#endif
9638 fptr->stdio_file = f;
9639
9640 return io;
9641}
9642
9643VALUE
9644rb_io_prep_stdin(void)
9645{
9646 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9647}
9648
9649VALUE
9650rb_io_prep_stdout(void)
9651{
9652 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9653}
9654
9655VALUE
9656rb_io_prep_stderr(void)
9657{
9658 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9659}
9660
9661FILE *
9663{
9664 if (!fptr->stdio_file) {
9665 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9666 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9667 }
9668 return fptr->stdio_file;
9669}
9670
9671static inline void
9672rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9673{
9674 buf->ptr = NULL;
9675 buf->off = 0;
9676 buf->len = 0;
9677 buf->capa = 0;
9678}
9679
9680static inline rb_io_t *
9681rb_io_fptr_new(void)
9682{
9683 rb_io_t *fp = ALLOC(rb_io_t);
9684 fp->self = Qnil;
9685 fp->fd = -1;
9686 fp->stdio_file = NULL;
9687 fp->mode = 0;
9688 fp->pid = 0;
9689 fp->lineno = 0;
9690 fp->pathv = Qnil;
9691 fp->finalize = 0;
9692 rb_io_buffer_init(&fp->wbuf);
9693 rb_io_buffer_init(&fp->rbuf);
9694 rb_io_buffer_init(&fp->cbuf);
9695 fp->readconv = NULL;
9696 fp->writeconv = NULL;
9698 fp->writeconv_pre_ecflags = 0;
9700 fp->writeconv_initialized = 0;
9701 fp->tied_io_for_writing = 0;
9702 fp->encs.enc = NULL;
9703 fp->encs.enc2 = NULL;
9704 fp->encs.ecflags = 0;
9705 fp->encs.ecopts = Qnil;
9706 fp->write_lock = Qnil;
9707 fp->timeout = Qnil;
9708 ccan_list_head_init(&fp->blocking_operations);
9709 fp->closing_ec = NULL;
9710 fp->wakeup_mutex = Qnil;
9711 fp->fork_generation = GET_VM()->fork_gen;
9712 return fp;
9713}
9714
9715rb_io_t *
9716rb_io_make_open_file(VALUE obj)
9717{
9718 rb_io_t *fp = 0;
9719
9720 Check_Type(obj, T_FILE);
9721 if (RFILE(obj)->fptr) {
9722 rb_io_close(obj);
9723 rb_io_fptr_finalize(RFILE(obj)->fptr);
9724 RFILE(obj)->fptr = 0;
9725 }
9726 fp = rb_io_fptr_new();
9727 fp->self = obj;
9728 RFILE(obj)->fptr = fp;
9729 return fp;
9730}
9731
9732static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9733
9734/*
9735 * call-seq:
9736 * IO.new(fd, mode = 'r', **opts) -> io
9737 *
9738 * Creates and returns a new \IO object (file stream) from a file descriptor.
9739 *
9740 * \IO.new may be useful for interaction with low-level libraries.
9741 * For higher-level interactions, it may be simpler to create
9742 * the file stream using File.open.
9743 *
9744 * Argument +fd+ must be a valid file descriptor (integer):
9745 *
9746 * path = 't.tmp'
9747 * fd = IO.sysopen(path) # => 3
9748 * IO.new(fd) # => #<IO:fd 3>
9749 *
9750 * The new \IO object does not inherit encoding
9751 * (because the integer file descriptor does not have an encoding):
9752 *
9753 * File.read('t.ja') # => "こんにちは"
9754 * fd = IO.sysopen('t.ja', 'rb')
9755 * io = IO.new(fd)
9756 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9757 *
9758 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9759 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9760 *
9761 * IO.new(fd, 'w') # => #<IO:fd 3>
9762 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9763 *
9764 * Optional keyword arguments +opts+ specify:
9765 *
9766 * - {Open Options}[rdoc-ref:IO@Open+Options].
9767 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9768 *
9769 * Examples:
9770 *
9771 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9772 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9773 *
9774 */
9775
9776static VALUE
9777rb_io_initialize(int argc, VALUE *argv, VALUE io)
9778{
9779 VALUE fnum, vmode;
9780 VALUE opt;
9781
9782 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9783 return io_initialize(io, fnum, vmode, opt);
9784}
9785
9786static VALUE
9787io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9788{
9789 rb_io_t *fp;
9790 int fd, oflags = O_RDONLY;
9791 enum rb_io_mode fmode;
9792 struct rb_io_encoding convconfig;
9793#if defined(HAVE_FCNTL) && defined(F_GETFL)
9794 int ofmode;
9795#else
9796 struct stat st;
9797#endif
9798
9799 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9800
9801 fd = NUM2INT(fnum);
9802 if (rb_reserved_fd_p(fd)) {
9803 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9804 }
9805#if defined(HAVE_FCNTL) && defined(F_GETFL)
9806 oflags = fcntl(fd, F_GETFL);
9807 if (oflags == -1) rb_sys_fail(0);
9808#else
9809 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9810#endif
9811 rb_update_max_fd(fd);
9812#if defined(HAVE_FCNTL) && defined(F_GETFL)
9813 ofmode = rb_io_oflags_fmode(oflags);
9814 if (NIL_P(vmode)) {
9815 fmode = ofmode;
9816 }
9817 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9818 VALUE error = INT2FIX(EINVAL);
9820 }
9821#endif
9822 VALUE path = Qnil;
9823
9824 if (!NIL_P(opt)) {
9825 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9826 fmode |= FMODE_EXTERNAL;
9827 }
9828
9829 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9830 if (!NIL_P(path)) {
9831 StringValue(path);
9832 path = rb_str_new_frozen(path);
9833 }
9834 }
9835
9836 MakeOpenFile(io, fp);
9837 fp->self = io;
9838 fp->fd = fd;
9839 fp->mode = fmode;
9840 fp->encs = convconfig;
9841 fp->pathv = path;
9842 fp->timeout = Qnil;
9843 ccan_list_head_init(&fp->blocking_operations);
9844 fp->closing_ec = NULL;
9845 fp->wakeup_mutex = Qnil;
9846 fp->fork_generation = GET_VM()->fork_gen;
9847 clear_codeconv(fp);
9848 io_check_tty(fp);
9849 if (fileno(stdin) == fd)
9850 fp->stdio_file = stdin;
9851 else if (fileno(stdout) == fd)
9852 fp->stdio_file = stdout;
9853 else if (fileno(stderr) == fd)
9854 fp->stdio_file = stderr;
9855
9856 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9857 return io;
9858}
9859
9860/*
9861 * call-seq:
9862 * set_encoding_by_bom -> encoding or nil
9863 *
9864 * If the stream begins with a BOM
9865 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9866 * consumes the BOM and sets the external encoding accordingly;
9867 * returns the result encoding if found, or +nil+ otherwise:
9868 *
9869 * File.write('t.tmp', "\u{FEFF}abc")
9870 * io = File.open('t.tmp', 'rb')
9871 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9872 * io.close
9873 *
9874 * File.write('t.tmp', 'abc')
9875 * io = File.open('t.tmp', 'rb')
9876 * io.set_encoding_by_bom # => nil
9877 * io.close
9878 *
9879 * Raises an exception if the stream is not binmode
9880 * or its encoding has already been set.
9881 *
9882 */
9883
9884static VALUE
9885rb_io_set_encoding_by_bom(VALUE io)
9886{
9887 rb_io_t *fptr;
9888
9889 GetOpenFile(io, fptr);
9890 if (!(fptr->mode & FMODE_BINMODE)) {
9891 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9892 }
9893 if (fptr->encs.enc2) {
9894 rb_raise(rb_eArgError, "encoding conversion is set");
9895 }
9896 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9897 rb_raise(rb_eArgError, "encoding is set to %s already",
9898 rb_enc_name(fptr->encs.enc));
9899 }
9900 if (!io_set_encoding_by_bom(io)) return Qnil;
9901 return rb_enc_from_encoding(fptr->encs.enc);
9902}
9903
9904/*
9905 * :markup: markdown
9906 *
9907 * call-seq:
9908 * File.new(path, mode = 'r', permissions = 0666, **options) -> file
9909 *
9910 * Opens the file as specified by the given arguments.
9911 * Creates and returns a new open \File object for that file;
9912 * the opened file is in non-synchronous mode.
9913 *
9914 * Argument `path` must the string path to an existing filesystem entry:
9915 *
9916 * ```ruby
9917 * file = File.new('doc/maintainers.md') # => #<File:doc/maintainers.md>
9918 * file.close # Clean up.
9919 * tty = File.new('/dev/tty') # => #<File:/dev/tty>
9920 * tty.close # Clean up.
9921 * ```
9922 *
9923 * Note that the caller is responsible for closing the file;
9924 * see File.open for automatic closing.
9925 *
9926 * Optional argument `mode` (defaults to `'r'`) must specify a valid mode;
9927 * see [Access Modes](rdoc-ref:File@Access+Modes):
9928 *
9929 * ```ruby
9930 * file = File.new('t.tmp', 'w') # => #<File:t.tmp>
9931 * file.close # Clean up.
9932 * file = File.new('t.tmp', File::RDONLY) # => #<File:t.tmp>
9933 * file.close # Clean up.
9934 * ```
9935 *
9936 * Optional argument `permissions` (defaults to `0666`) must specify valid permissions;
9937 * see [File Permissions](rdoc-ref:File@File+Permissions):
9938 *
9939 * ```ruby
9940 * file = File.new('t.tmp', 'w', 0644) # => #<File:t.tmp>
9941 * file.close # Clean up.
9942 * file = File.new('t.tmp', 'w', 0444) # => #<File:t.tmp>
9943 * file.close # Clean up.
9944 * ```
9945 *
9946 * Optional keyword arguments `options` specify:
9947 *
9948 * - [Open Options](rdoc-ref:IO@Open+Options).
9949 * - [Encoding options](rdoc-ref:encodings.rdoc@Encoding+Options).
9950 *
9951 */
9952
9953static VALUE
9954rb_file_initialize(int argc, VALUE *argv, VALUE io)
9955{
9956 if (RFILE(io)->fptr) {
9957 rb_raise(rb_eRuntimeError, "reinitializing File");
9958 }
9959 VALUE fname, vmode, vperm, opt;
9960 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9961 if (posargc < 3) { /* perm is File only */
9962 VALUE fd = rb_check_to_int(fname);
9963
9964 if (!NIL_P(fd)) {
9965 return io_initialize(io, fd, vmode, opt);
9966 }
9967 }
9968 return rb_open_file(io, fname, vmode, vperm, opt);
9969}
9970
9971/* :nodoc: */
9972static VALUE
9973rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9974{
9975 if (rb_block_given_p()) {
9976 VALUE cname = rb_obj_as_string(klass);
9977
9978 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9979 cname, cname);
9980 }
9981 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9982}
9983
9984
9985/*
9986 * call-seq:
9987 * IO.for_fd(fd, mode = 'r', **opts) -> io
9988 *
9989 * Synonym for IO.new.
9990 *
9991 */
9992
9993static VALUE
9994rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9995{
9996 VALUE io = rb_obj_alloc(klass);
9997 rb_io_initialize(argc, argv, io);
9998 return io;
9999}
10000
10001/*
10002 * call-seq:
10003 * ios.autoclose? -> true or false
10004 *
10005 * Returns +true+ if the underlying file descriptor of _ios_ will be
10006 * closed at its finalization or at calling #close, otherwise +false+.
10007 */
10008
10009static VALUE
10010rb_io_autoclose_p(VALUE io)
10011{
10012 rb_io_t *fptr = RFILE(io)->fptr;
10013 rb_io_check_closed(fptr);
10014 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
10015}
10016
10017/*
10018 * call-seq:
10019 * io.autoclose = bool -> true or false
10020 *
10021 * Sets auto-close flag.
10022 *
10023 * f = File.open(File::NULL)
10024 * IO.for_fd(f.fileno).close
10025 * f.gets # raises Errno::EBADF
10026 *
10027 * f = File.open(File::NULL)
10028 * g = IO.for_fd(f.fileno)
10029 * g.autoclose = false
10030 * g.close
10031 * f.gets # won't cause Errno::EBADF
10032 */
10033
10034static VALUE
10035rb_io_set_autoclose(VALUE io, VALUE autoclose)
10036{
10037 rb_io_t *fptr;
10038 GetOpenFile(io, fptr);
10039 if (!RTEST(autoclose))
10040 fptr->mode |= FMODE_EXTERNAL;
10041 else
10042 fptr->mode &= ~FMODE_EXTERNAL;
10043 return autoclose;
10044}
10045
10046static VALUE
10047io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
10048{
10049 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
10050
10051 if (!RB_TEST(result)) {
10052 return Qnil;
10053 }
10054
10055 int mask = RB_NUM2INT(result);
10056
10057 if (mask & event) {
10058 if (return_io)
10059 return io;
10060 else
10061 return result;
10062 }
10063 else {
10064 return Qfalse;
10065 }
10066}
10067
10068/*
10069 * call-seq:
10070 * io.wait_readable -> truthy or falsy
10071 * io.wait_readable(timeout) -> truthy or falsy
10072 *
10073 * Waits until IO is readable and returns a truthy value, or a falsy
10074 * value when times out. Returns a truthy value immediately when
10075 * buffered data is available.
10076 */
10077
10078static VALUE
10079io_wait_readable(int argc, VALUE *argv, VALUE io)
10080{
10081 rb_io_t *fptr;
10082
10083 RB_IO_POINTER(io, fptr);
10085
10086 if (rb_io_read_pending(fptr)) return Qtrue;
10087
10088 rb_check_arity(argc, 0, 1);
10089 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
10090
10091 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
10092}
10093
10094/*
10095 * call-seq:
10096 * io.wait_writable -> truthy or falsy
10097 * io.wait_writable(timeout) -> truthy or falsy
10098 *
10099 * Waits until IO is writable and returns a truthy value or a falsy
10100 * value when times out.
10101 */
10102static VALUE
10103io_wait_writable(int argc, VALUE *argv, VALUE io)
10104{
10105 rb_io_t *fptr;
10106
10107 RB_IO_POINTER(io, fptr);
10109
10110 rb_check_arity(argc, 0, 1);
10111 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
10112
10113 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
10114}
10115
10116/*
10117 * call-seq:
10118 * io.wait_priority -> truthy or falsy
10119 * io.wait_priority(timeout) -> truthy or falsy
10120 *
10121 * Waits until IO is priority and returns a truthy value or a falsy
10122 * value when times out. Priority data is sent and received using
10123 * the Socket::MSG_OOB flag and is typically limited to streams.
10124 */
10125static VALUE
10126io_wait_priority(int argc, VALUE *argv, VALUE io)
10127{
10128 rb_io_t *fptr = NULL;
10129
10130 RB_IO_POINTER(io, fptr);
10132
10133 if (rb_io_read_pending(fptr)) return Qtrue;
10134
10135 rb_check_arity(argc, 0, 1);
10136 VALUE timeout = argc == 1 ? argv[0] : Qnil;
10137
10138 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
10139}
10140
10141static int
10142wait_mode_sym(VALUE mode)
10143{
10144 if (mode == ID2SYM(rb_intern("r"))) {
10145 return RB_WAITFD_IN;
10146 }
10147 if (mode == ID2SYM(rb_intern("read"))) {
10148 return RB_WAITFD_IN;
10149 }
10150 if (mode == ID2SYM(rb_intern("readable"))) {
10151 return RB_WAITFD_IN;
10152 }
10153 if (mode == ID2SYM(rb_intern("w"))) {
10154 return RB_WAITFD_OUT;
10155 }
10156 if (mode == ID2SYM(rb_intern("write"))) {
10157 return RB_WAITFD_OUT;
10158 }
10159 if (mode == ID2SYM(rb_intern("writable"))) {
10160 return RB_WAITFD_OUT;
10161 }
10162 if (mode == ID2SYM(rb_intern("rw"))) {
10163 return RB_WAITFD_IN|RB_WAITFD_OUT;
10164 }
10165 if (mode == ID2SYM(rb_intern("read_write"))) {
10166 return RB_WAITFD_IN|RB_WAITFD_OUT;
10167 }
10168 if (mode == ID2SYM(rb_intern("readable_writable"))) {
10169 return RB_WAITFD_IN|RB_WAITFD_OUT;
10170 }
10171
10172 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
10173}
10174
10175static inline enum rb_io_event
10176io_event_from_value(VALUE value)
10177{
10178 int events = RB_NUM2INT(value);
10179
10180 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
10181
10182 return events;
10183}
10184
10185/*
10186 * call-seq:
10187 * io.wait(events, timeout) -> event mask, false or nil
10188 * io.wait(*event_symbols[, timeout]) -> self, true, or false
10189 *
10190 * Waits until the IO becomes ready for the specified events and returns the
10191 * subset of events that become ready, or a falsy value when times out.
10192 *
10193 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
10194 * +IO::PRIORITY+.
10195 *
10196 * Returns an event mask (truthy value) immediately when buffered data is
10197 * available.
10198 *
10199 * The second form: if one or more event symbols (+:read+, +:write+, or
10200 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
10201 * corresponding to those symbols. In this form, +timeout+ is optional, the
10202 * order of the arguments is arbitrary, and returns +io+ if any of the
10203 * events is ready.
10204 */
10205
10206static VALUE
10207io_wait(int argc, VALUE *argv, VALUE io)
10208{
10209 VALUE timeout = Qundef;
10210 enum rb_io_event events = 0;
10211 int return_io = 0;
10212
10213 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
10214 // We'd prefer to return the actual mask, but this form would return the io itself:
10215 return_io = 1;
10216
10217 // Slow/messy path:
10218 for (int i = 0; i < argc; i += 1) {
10219 if (RB_SYMBOL_P(argv[i])) {
10220 events |= wait_mode_sym(argv[i]);
10221 }
10222 else if (UNDEF_P(timeout)) {
10223 rb_time_interval(timeout = argv[i]);
10224 }
10225 else {
10226 rb_raise(rb_eArgError, "timeout given more than once");
10227 }
10228 }
10229
10230 if (UNDEF_P(timeout)) timeout = Qnil;
10231
10232 if (events == 0) {
10233 events = RUBY_IO_READABLE;
10234 }
10235 }
10236 else /* argc == 2 and neither are symbols */ {
10237 // This is the fast path:
10238 events = io_event_from_value(argv[0]);
10239 timeout = argv[1];
10240 }
10241
10242 if (events & RUBY_IO_READABLE) {
10243 rb_io_t *fptr = NULL;
10244 RB_IO_POINTER(io, fptr);
10245
10246 if (rb_io_read_pending(fptr)) {
10247 // This was the original behaviour:
10248 if (return_io) return Qtrue;
10249 // New behaviour always returns an event mask:
10250 else return RB_INT2NUM(RUBY_IO_READABLE);
10251 }
10252 }
10253
10254 return io_wait_event(io, events, timeout, return_io);
10255}
10256
10257static void
10258argf_mark_and_move(void *ptr)
10259{
10260 struct argf *p = ptr;
10261 rb_gc_mark_and_move(&p->filename);
10262 rb_gc_mark_and_move(&p->current_file);
10263 rb_gc_mark_and_move(&p->argv);
10264 rb_gc_mark_and_move(&p->inplace);
10265 rb_gc_mark_and_move(&p->encs.ecopts);
10266}
10267
10268static size_t
10269argf_memsize(const void *ptr)
10270{
10271 const struct argf *p = ptr;
10272 size_t size = sizeof(*p);
10273 return size;
10274}
10275
10276static const rb_data_type_t argf_type = {
10277 "ARGF",
10278 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10279 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10280};
10281
10282static inline void
10283argf_init(VALUE argf, struct argf *p, VALUE v)
10284{
10285 p->filename = Qnil;
10286 p->current_file = Qnil;
10287 p->lineno = 0;
10288 RB_OBJ_WRITE(argf, &p->argv, v);
10289}
10290
10291static VALUE
10292argf_alloc(VALUE klass)
10293{
10294 struct argf *p;
10295 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10296
10297 argf_init(argf, p, Qnil);
10298 return argf;
10299}
10300
10301#undef rb_argv
10302
10303/* :nodoc: */
10304static VALUE
10305argf_initialize(VALUE argf, VALUE argv)
10306{
10307 memset(&ARGF, 0, sizeof(ARGF));
10308 argf_init(argf, &ARGF, argv);
10309
10310 return argf;
10311}
10312
10313/* :nodoc: */
10314static VALUE
10315argf_initialize_copy(VALUE argf, VALUE orig)
10316{
10317 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10318 ARGF = argf_of(orig);
10319 rb_gc_writebarrier_remember(argf);
10320 ARGF_SET(argv, rb_obj_dup(ARGF.argv));
10321 return argf;
10322}
10323
10324/*
10325 * call-seq:
10326 * ARGF.lineno = integer -> integer
10327 *
10328 * Sets the line number of ARGF as a whole to the given Integer.
10329 *
10330 * ARGF sets the line number automatically as you read data, so normally
10331 * you will not need to set it explicitly. To access the current line number
10332 * use ARGF.lineno.
10333 *
10334 * For example:
10335 *
10336 * ARGF.lineno #=> 0
10337 * ARGF.readline #=> "This is line 1\n"
10338 * ARGF.lineno #=> 1
10339 * ARGF.lineno = 0 #=> 0
10340 * ARGF.lineno #=> 0
10341 */
10342static VALUE
10343argf_set_lineno(VALUE argf, VALUE val)
10344{
10345 ARGF.lineno = NUM2INT(val);
10346 ARGF.last_lineno = ARGF.lineno;
10347 return val;
10348}
10349
10350/*
10351 * call-seq:
10352 * ARGF.lineno -> integer
10353 *
10354 * Returns the current line number of ARGF as a whole. This value
10355 * can be set manually with ARGF.lineno=.
10356 *
10357 * For example:
10358 *
10359 * ARGF.lineno #=> 0
10360 * ARGF.readline #=> "This is line 1\n"
10361 * ARGF.lineno #=> 1
10362 */
10363static VALUE
10364argf_lineno(VALUE argf)
10365{
10366 return INT2FIX(ARGF.lineno);
10367}
10368
10369static VALUE
10370argf_forward(int argc, VALUE *argv, VALUE argf)
10371{
10372 return forward_current(rb_frame_this_func(), argc, argv);
10373}
10374
10375#define next_argv() argf_next_argv(argf)
10376#define ARGF_GENERIC_INPUT_P() \
10377 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10378#define ARGF_FORWARD(argc, argv) do {\
10379 if (ARGF_GENERIC_INPUT_P())\
10380 return argf_forward((argc), (argv), argf);\
10381} while (0)
10382#define NEXT_ARGF_FORWARD(argc, argv) do {\
10383 if (!next_argv()) return Qnil;\
10384 ARGF_FORWARD((argc), (argv));\
10385} while (0)
10386
10387static void
10388argf_close(VALUE argf)
10389{
10390 VALUE file = ARGF.current_file;
10391 if (file == rb_stdin) return;
10392 if (RB_TYPE_P(file, T_FILE)) {
10393 rb_io_set_write_io(file, Qnil);
10394 }
10395 io_close(file);
10396 ARGF.init_p = -1;
10397}
10398
10399static int
10400argf_next_argv(VALUE argf)
10401{
10402 char *fn;
10403 rb_io_t *fptr;
10404 int stdout_binmode = 0;
10405 enum rb_io_mode fmode;
10406
10407 VALUE r_stdout = rb_ractor_stdout();
10408
10409 if (RB_TYPE_P(r_stdout, T_FILE)) {
10410 GetOpenFile(r_stdout, fptr);
10411 if (fptr->mode & FMODE_BINMODE)
10412 stdout_binmode = 1;
10413 }
10414
10415 if (ARGF.init_p == 0) {
10416 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10417 ARGF.next_p = 1;
10418 }
10419 else {
10420 ARGF.next_p = -1;
10421 }
10422 ARGF.init_p = 1;
10423 }
10424 else {
10425 if (NIL_P(ARGF.argv)) {
10426 ARGF.next_p = -1;
10427 }
10428 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10429 ARGF.next_p = 1;
10430 }
10431 }
10432
10433 if (ARGF.next_p == 1) {
10434 if (ARGF.init_p == 1) argf_close(argf);
10435 retry:
10436 if (RARRAY_LEN(ARGF.argv) > 0) {
10437 VALUE filename = rb_ary_shift(ARGF.argv);
10438 FilePathValue(filename);
10439 ARGF_SET(filename, filename);
10440 filename = rb_str_encode_ospath(filename);
10441 fn = StringValueCStr(filename);
10442 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10443 ARGF_SET(current_file, rb_stdin);
10444 if (ARGF.inplace) {
10445 rb_warn("Can't do inplace edit for stdio; skipping");
10446 goto retry;
10447 }
10448 }
10449 else {
10450 VALUE write_io = Qnil;
10451 int fr = rb_sysopen(filename, O_RDONLY, 0);
10452
10453 if (ARGF.inplace) {
10454 struct stat st;
10455#ifndef NO_SAFE_RENAME
10456 struct stat st2;
10457#endif
10458 VALUE str;
10459 int fw;
10460
10461 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10462 rb_io_close(r_stdout);
10463 }
10464 fstat(fr, &st);
10465 str = filename;
10466 if (!NIL_P(ARGF.inplace)) {
10467 VALUE suffix = ARGF.inplace;
10468 str = rb_str_dup(str);
10469 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10470 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10471 rb_enc_get(suffix), 0, Qnil))) {
10472 rb_str_append(str, suffix);
10473 }
10474#ifdef NO_SAFE_RENAME
10475 (void)close(fr);
10476 (void)unlink(RSTRING_PTR(str));
10477 if (rename(fn, RSTRING_PTR(str)) < 0) {
10478 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10479 filename, str, strerror(errno));
10480 goto retry;
10481 }
10482 fr = rb_sysopen(str, O_RDONLY, 0);
10483#else
10484 if (rename(fn, RSTRING_PTR(str)) < 0) {
10485 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10486 filename, str, strerror(errno));
10487 close(fr);
10488 goto retry;
10489 }
10490#endif
10491 }
10492 else {
10493#ifdef NO_SAFE_RENAME
10494 rb_fatal("Can't do inplace edit without backup");
10495#else
10496 if (unlink(fn) < 0) {
10497 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10498 filename, strerror(errno));
10499 close(fr);
10500 goto retry;
10501 }
10502#endif
10503 }
10504 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10505#ifndef NO_SAFE_RENAME
10506 fstat(fw, &st2);
10507#ifdef HAVE_FCHMOD
10508 fchmod(fw, st.st_mode);
10509#else
10510 chmod(fn, st.st_mode);
10511#endif
10512 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10513 int err;
10514#ifdef HAVE_FCHOWN
10515 err = fchown(fw, st.st_uid, st.st_gid);
10516#else
10517 err = chown(fn, st.st_uid, st.st_gid);
10518#endif
10519 if (err && getuid() == 0 && st2.st_uid == 0) {
10520 const char *wkfn = RSTRING_PTR(filename);
10521 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10522 filename, str, strerror(errno));
10523 (void)close(fr);
10524 (void)close(fw);
10525 (void)unlink(wkfn);
10526 goto retry;
10527 }
10528 }
10529#endif
10530 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10531 rb_ractor_stdout_set(write_io);
10532 if (stdout_binmode) rb_io_binmode(rb_stdout);
10533 }
10534 fmode = FMODE_READABLE;
10535 if (!ARGF.binmode) {
10536 fmode |= DEFAULT_TEXTMODE;
10537 }
10538 ARGF_SET(current_file, prep_io(fr, fmode, rb_cFile, fn));
10539 if (!NIL_P(write_io)) {
10540 rb_io_set_write_io(ARGF.current_file, write_io);
10541 }
10542 RB_GC_GUARD(filename);
10543 }
10544 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10545 GetOpenFile(ARGF.current_file, fptr);
10546 if (ARGF.encs.enc) {
10547 fptr->encs = ARGF.encs;
10548 clear_codeconv(fptr);
10549 }
10550 else {
10551 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10552 if (!ARGF.binmode) {
10554#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10555 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10556#endif
10557 }
10558 }
10559 ARGF.next_p = 0;
10560 }
10561 else {
10562 ARGF.next_p = 1;
10563 return FALSE;
10564 }
10565 }
10566 else if (ARGF.next_p == -1) {
10567 ARGF_SET(current_file, rb_stdin);
10568 ARGF_SET(filename, rb_str_new2("-"));
10569 if (ARGF.inplace) {
10570 rb_warn("Can't do inplace edit for stdio");
10571 rb_ractor_stdout_set(orig_stdout);
10572 }
10573 }
10574 if (ARGF.init_p == -1) ARGF.init_p = 1;
10575 return TRUE;
10576}
10577
10578static VALUE
10579argf_getline(int argc, VALUE *argv, VALUE argf)
10580{
10581 VALUE line;
10582 long lineno = ARGF.lineno;
10583
10584 retry:
10585 if (!next_argv()) return Qnil;
10586 if (ARGF_GENERIC_INPUT_P()) {
10587 line = forward_current(idGets, argc, argv);
10588 }
10589 else {
10590 if (argc == 0 && rb_rs == rb_default_rs) {
10591 line = rb_io_gets(ARGF.current_file);
10592 }
10593 else {
10594 line = rb_io_getline(argc, argv, ARGF.current_file);
10595 }
10596 if (NIL_P(line) && ARGF.next_p != -1) {
10597 argf_close(argf);
10598 ARGF.next_p = 1;
10599 goto retry;
10600 }
10601 }
10602 if (!NIL_P(line)) {
10603 ARGF.lineno = ++lineno;
10604 ARGF.last_lineno = ARGF.lineno;
10605 }
10606 return line;
10607}
10608
10609static VALUE
10610argf_lineno_getter(ID id, VALUE *var)
10611{
10612 VALUE argf = *var;
10613 return INT2FIX(ARGF.last_lineno);
10614}
10615
10616static void
10617argf_lineno_setter(VALUE val, ID id, VALUE *var)
10618{
10619 VALUE argf = *var;
10620 int n = NUM2INT(val);
10621 ARGF.last_lineno = ARGF.lineno = n;
10622}
10623
10624void
10625rb_reset_argf_lineno(long n)
10626{
10627 ARGF.last_lineno = ARGF.lineno = n;
10628}
10629
10630static VALUE argf_gets(int, VALUE *, VALUE);
10631
10632/*
10633 * call-seq:
10634 * gets(sep=$/ [, getline_args]) -> string or nil
10635 * gets(limit [, getline_args]) -> string or nil
10636 * gets(sep, limit [, getline_args]) -> string or nil
10637 *
10638 * Returns (and assigns to <code>$_</code>) the next line from the list
10639 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10640 * no files are present on the command line. Returns +nil+ at end of
10641 * file. The optional argument specifies the record separator. The
10642 * separator is included with the contents of each record. A separator
10643 * of +nil+ reads the entire contents, and a zero-length separator
10644 * reads the input one paragraph at a time, where paragraphs are
10645 * divided by two consecutive newlines. If the first argument is an
10646 * integer, or optional second argument is given, the returning string
10647 * would not be longer than the given value in bytes. If multiple
10648 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10649 * the contents one file at a time.
10650 *
10651 * ARGV << "testfile"
10652 * print while gets
10653 *
10654 * <em>produces:</em>
10655 *
10656 * This is line one
10657 * This is line two
10658 * This is line three
10659 * And so on...
10660 *
10661 * The style of programming using <code>$_</code> as an implicit
10662 * parameter is gradually losing favor in the Ruby community.
10663 */
10664
10665static VALUE
10666rb_f_gets(int argc, VALUE *argv, VALUE recv)
10667{
10668 if (recv == argf) {
10669 return argf_gets(argc, argv, argf);
10670 }
10671 return forward(argf, idGets, argc, argv);
10672}
10673
10674/*
10675 * call-seq:
10676 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10677 * ARGF.gets(limit [, getline_args]) -> string or nil
10678 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10679 *
10680 * Returns the next line from the current file in ARGF.
10681 *
10682 * By default lines are assumed to be separated by <code>$/</code>;
10683 * to use a different character as a separator, supply it as a String
10684 * for the _sep_ argument.
10685 *
10686 * The optional _limit_ argument specifies how many characters of each line
10687 * to return. By default all characters are returned.
10688 *
10689 * See IO.readlines for details about getline_args.
10690 *
10691 */
10692static VALUE
10693argf_gets(int argc, VALUE *argv, VALUE argf)
10694{
10695 VALUE line;
10696
10697 line = argf_getline(argc, argv, argf);
10698 rb_lastline_set(line);
10699
10700 return line;
10701}
10702
10703VALUE
10705{
10706 VALUE line;
10707
10708 if (rb_rs != rb_default_rs) {
10709 return rb_f_gets(0, 0, argf);
10710 }
10711
10712 retry:
10713 if (!next_argv()) return Qnil;
10714 line = rb_io_gets(ARGF.current_file);
10715 if (NIL_P(line) && ARGF.next_p != -1) {
10716 rb_io_close(ARGF.current_file);
10717 ARGF.next_p = 1;
10718 goto retry;
10719 }
10720 rb_lastline_set(line);
10721 if (!NIL_P(line)) {
10722 ARGF.lineno++;
10723 ARGF.last_lineno = ARGF.lineno;
10724 }
10725
10726 return line;
10727}
10728
10729static VALUE argf_readline(int, VALUE *, VALUE);
10730
10731/*
10732 * call-seq:
10733 * readline(sep = $/, chomp: false) -> string
10734 * readline(limit, chomp: false) -> string
10735 * readline(sep, limit, chomp: false) -> string
10736 *
10737 * Equivalent to method Kernel#gets, except that it raises an exception
10738 * if called at end-of-stream:
10739 *
10740 * $ cat t.txt | ruby -e "p readlines; readline"
10741 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10742 * in `readline': end of file reached (EOFError)
10743 *
10744 * Optional keyword argument +chomp+ specifies whether line separators
10745 * are to be omitted.
10746 */
10747
10748static VALUE
10749rb_f_readline(int argc, VALUE *argv, VALUE recv)
10750{
10751 if (recv == argf) {
10752 return argf_readline(argc, argv, argf);
10753 }
10754 return forward(argf, rb_intern("readline"), argc, argv);
10755}
10756
10757
10758/*
10759 * call-seq:
10760 * ARGF.readline(sep=$/) -> string
10761 * ARGF.readline(limit) -> string
10762 * ARGF.readline(sep, limit) -> string
10763 *
10764 * Returns the next line from the current file in ARGF.
10765 *
10766 * By default lines are assumed to be separated by <code>$/</code>;
10767 * to use a different character as a separator, supply it as a String
10768 * for the _sep_ argument.
10769 *
10770 * The optional _limit_ argument specifies how many characters of each line
10771 * to return. By default all characters are returned.
10772 *
10773 * An EOFError is raised at the end of the file.
10774 */
10775static VALUE
10776argf_readline(int argc, VALUE *argv, VALUE argf)
10777{
10778 VALUE line;
10779
10780 if (!next_argv()) rb_eof_error();
10781 ARGF_FORWARD(argc, argv);
10782 line = argf_gets(argc, argv, argf);
10783 if (NIL_P(line)) {
10784 rb_eof_error();
10785 }
10786
10787 return line;
10788}
10789
10790static VALUE argf_readlines(int, VALUE *, VALUE);
10791
10792/*
10793 * call-seq:
10794 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10795 * readlines(limit, chomp: false, **enc_opts) -> array
10796 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10797 *
10798 * Returns an array containing the lines returned by calling
10799 * Kernel#gets until the end-of-stream is reached;
10800 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10801 *
10802 * With only string argument +sep+ given,
10803 * returns the remaining lines as determined by line separator +sep+,
10804 * or +nil+ if none;
10805 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10806 *
10807 * # Default separator.
10808 * $ cat t.txt | ruby -e "p readlines"
10809 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10810 *
10811 * # Specified separator.
10812 * $ cat t.txt | ruby -e "p readlines 'li'"
10813 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10814 *
10815 * # Get-all separator.
10816 * $ cat t.txt | ruby -e "p readlines nil"
10817 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10818 *
10819 * # Get-paragraph separator.
10820 * $ cat t.txt | ruby -e "p readlines ''"
10821 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10822 *
10823 * With only integer argument +limit+ given,
10824 * limits the number of bytes in the line;
10825 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10826 *
10827 * $cat t.txt | ruby -e "p readlines 10"
10828 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10829 *
10830 * $cat t.txt | ruby -e "p readlines 11"
10831 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10832 *
10833 * $cat t.txt | ruby -e "p readlines 12"
10834 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10835 *
10836 * With arguments +sep+ and +limit+ given,
10837 * combines the two behaviors
10838 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10839 *
10840 * Optional keyword argument +chomp+ specifies whether line separators
10841 * are to be omitted:
10842 *
10843 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10844 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10845 *
10846 * Optional keyword arguments +enc_opts+ specify encoding options;
10847 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10848 *
10849 */
10850
10851static VALUE
10852rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10853{
10854 if (recv == argf) {
10855 return argf_readlines(argc, argv, argf);
10856 }
10857 return forward(argf, rb_intern("readlines"), argc, argv);
10858}
10859
10860/*
10861 * call-seq:
10862 * ARGF.readlines(sep = $/, chomp: false) -> array
10863 * ARGF.readlines(limit, chomp: false) -> array
10864 * ARGF.readlines(sep, limit, chomp: false) -> array
10865 *
10866 * ARGF.to_a(sep = $/, chomp: false) -> array
10867 * ARGF.to_a(limit, chomp: false) -> array
10868 * ARGF.to_a(sep, limit, chomp: false) -> array
10869 *
10870 * Reads each file in ARGF in its entirety, returning an Array containing
10871 * lines from the files. Lines are assumed to be separated by _sep_.
10872 *
10873 * lines = ARGF.readlines
10874 * lines[0] #=> "This is line one\n"
10875 *
10876 * See +IO.readlines+ for a full description of all options.
10877 */
10878static VALUE
10879argf_readlines(int argc, VALUE *argv, VALUE argf)
10880{
10881 long lineno = ARGF.lineno;
10882 VALUE lines, ary;
10883
10884 ary = rb_ary_new();
10885 while (next_argv()) {
10886 if (ARGF_GENERIC_INPUT_P()) {
10887 lines = forward_current(rb_intern("readlines"), argc, argv);
10888 }
10889 else {
10890 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10891 argf_close(argf);
10892 }
10893 ARGF.next_p = 1;
10894 rb_ary_concat(ary, lines);
10895 ARGF.lineno = lineno + RARRAY_LEN(ary);
10896 ARGF.last_lineno = ARGF.lineno;
10897 }
10898 ARGF.init_p = 0;
10899 return ary;
10900}
10901
10902/*
10903 * call-seq:
10904 * `command` -> string
10905 *
10906 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10907 * sets global variable <tt>$?</tt> to the process status.
10908 *
10909 * This method has potential security vulnerabilities if called with untrusted input;
10910 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
10911 *
10912 * Examples:
10913 *
10914 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10915 * $ `echo oops && exit 99` # => "oops\n"
10916 * $ $? # => #<Process::Status: pid 17088 exit 99>
10917 * $ $?.exitstatus # => 99
10918 *
10919 * The built-in syntax <tt>%x{...}</tt> uses this method.
10920 *
10921 */
10922
10923static VALUE
10924rb_f_backquote(VALUE obj, VALUE str)
10925{
10926 VALUE port;
10927 VALUE result;
10928 rb_io_t *fptr;
10929
10930 StringValue(str);
10931 rb_last_status_clear();
10932 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10933 if (NIL_P(port)) return rb_str_new(0,0);
10934
10935 GetOpenFile(port, fptr);
10936 result = read_all(fptr, remain_size(fptr), Qnil);
10937 rb_io_close(port);
10938 rb_io_fptr_cleanup_all(fptr);
10939 RB_GC_GUARD(port);
10940
10941 return result;
10942}
10943
10944#ifdef HAVE_SYS_SELECT_H
10945#include <sys/select.h>
10946#endif
10947
10948static VALUE
10949select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10950{
10951 VALUE res, list;
10952 rb_fdset_t *rp, *wp, *ep;
10953 rb_io_t *fptr;
10954 long i;
10955 int max = 0, n;
10956 int pending = 0;
10957 struct timeval timerec;
10958
10959 if (!NIL_P(read)) {
10960 Check_Type(read, T_ARRAY);
10961 for (i=0; i<RARRAY_LEN(read); i++) {
10962 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10963 rb_fd_set(fptr->fd, &fds[0]);
10964 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10965 pending++;
10966 rb_fd_set(fptr->fd, &fds[3]);
10967 }
10968 if (max < fptr->fd) max = fptr->fd;
10969 }
10970 if (pending) { /* no blocking if there's buffered data */
10971 timerec.tv_sec = timerec.tv_usec = 0;
10972 tp = &timerec;
10973 }
10974 rp = &fds[0];
10975 }
10976 else
10977 rp = 0;
10978
10979 if (!NIL_P(write)) {
10980 Check_Type(write, T_ARRAY);
10981 for (i=0; i<RARRAY_LEN(write); i++) {
10982 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10983 GetOpenFile(write_io, fptr);
10984 rb_fd_set(fptr->fd, &fds[1]);
10985 if (max < fptr->fd) max = fptr->fd;
10986 }
10987 wp = &fds[1];
10988 }
10989 else
10990 wp = 0;
10991
10992 if (!NIL_P(except)) {
10993 Check_Type(except, T_ARRAY);
10994 for (i=0; i<RARRAY_LEN(except); i++) {
10995 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10996 VALUE write_io = GetWriteIO(io);
10997 GetOpenFile(io, fptr);
10998 rb_fd_set(fptr->fd, &fds[2]);
10999 if (max < fptr->fd) max = fptr->fd;
11000 if (io != write_io) {
11001 GetOpenFile(write_io, fptr);
11002 rb_fd_set(fptr->fd, &fds[2]);
11003 if (max < fptr->fd) max = fptr->fd;
11004 }
11005 }
11006 ep = &fds[2];
11007 }
11008 else {
11009 ep = 0;
11010 }
11011
11012 max++;
11013
11014 n = rb_thread_fd_select(max, rp, wp, ep, tp);
11015 if (n < 0) {
11016 rb_sys_fail(0);
11017 }
11018 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
11019
11020 res = rb_ary_new2(3);
11021 rb_ary_push(res, rp ? rb_ary_new_capa(RARRAY_LEN(read)) : rb_ary_new());
11022 rb_ary_push(res, wp ? rb_ary_new_capa(RARRAY_LEN(write)) : rb_ary_new());
11023 rb_ary_push(res, ep ? rb_ary_new_capa(RARRAY_LEN(except)) : rb_ary_new());
11024
11025 if (rp) {
11026 list = RARRAY_AREF(res, 0);
11027 for (i=0; i< RARRAY_LEN(read); i++) {
11028 VALUE obj = rb_ary_entry(read, i);
11029 VALUE io = rb_io_get_io(obj);
11030 GetOpenFile(io, fptr);
11031 if (rb_fd_isset(fptr->fd, &fds[0]) ||
11032 rb_fd_isset(fptr->fd, &fds[3])) {
11033 rb_ary_push(list, obj);
11034 }
11035 }
11036 }
11037
11038 if (wp) {
11039 list = RARRAY_AREF(res, 1);
11040 for (i=0; i< RARRAY_LEN(write); i++) {
11041 VALUE obj = rb_ary_entry(write, i);
11042 VALUE io = rb_io_get_io(obj);
11043 VALUE write_io = GetWriteIO(io);
11044 GetOpenFile(write_io, fptr);
11045 if (rb_fd_isset(fptr->fd, &fds[1])) {
11046 rb_ary_push(list, obj);
11047 }
11048 }
11049 }
11050
11051 if (ep) {
11052 list = RARRAY_AREF(res, 2);
11053 for (i=0; i< RARRAY_LEN(except); i++) {
11054 VALUE obj = rb_ary_entry(except, i);
11055 VALUE io = rb_io_get_io(obj);
11056 VALUE write_io = GetWriteIO(io);
11057 GetOpenFile(io, fptr);
11058 if (rb_fd_isset(fptr->fd, &fds[2])) {
11059 rb_ary_push(list, obj);
11060 }
11061 else if (io != write_io) {
11062 GetOpenFile(write_io, fptr);
11063 if (rb_fd_isset(fptr->fd, &fds[2])) {
11064 rb_ary_push(list, obj);
11065 }
11066 }
11067 }
11068 }
11069
11070 return res; /* returns an empty array on interrupt */
11071}
11072
11074 VALUE read, write, except;
11075 struct timeval *timeout;
11076 rb_fdset_t fdsets[4];
11077};
11078
11079static VALUE
11080select_call(VALUE arg)
11081{
11082 struct select_args *p = (struct select_args *)arg;
11083
11084 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
11085}
11086
11087static VALUE
11088select_end(VALUE arg)
11089{
11090 struct select_args *p = (struct select_args *)arg;
11091 int i;
11092
11093 for (i = 0; i < numberof(p->fdsets); ++i)
11094 rb_fd_term(&p->fdsets[i]);
11095 return Qnil;
11096}
11097
11098static VALUE sym_normal, sym_sequential, sym_random,
11099 sym_willneed, sym_dontneed, sym_noreuse;
11100
11101#ifdef HAVE_POSIX_FADVISE
11102struct io_advise_struct {
11103 int fd;
11104 int advice;
11105 rb_off_t offset;
11106 rb_off_t len;
11107};
11108
11109static VALUE
11110io_advise_internal(void *arg)
11111{
11112 struct io_advise_struct *ptr = arg;
11113 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
11114}
11115
11116static VALUE
11117io_advise_sym_to_const(VALUE sym)
11118{
11119#ifdef POSIX_FADV_NORMAL
11120 if (sym == sym_normal)
11121 return INT2NUM(POSIX_FADV_NORMAL);
11122#endif
11123
11124#ifdef POSIX_FADV_RANDOM
11125 if (sym == sym_random)
11126 return INT2NUM(POSIX_FADV_RANDOM);
11127#endif
11128
11129#ifdef POSIX_FADV_SEQUENTIAL
11130 if (sym == sym_sequential)
11131 return INT2NUM(POSIX_FADV_SEQUENTIAL);
11132#endif
11133
11134#ifdef POSIX_FADV_WILLNEED
11135 if (sym == sym_willneed)
11136 return INT2NUM(POSIX_FADV_WILLNEED);
11137#endif
11138
11139#ifdef POSIX_FADV_DONTNEED
11140 if (sym == sym_dontneed)
11141 return INT2NUM(POSIX_FADV_DONTNEED);
11142#endif
11143
11144#ifdef POSIX_FADV_NOREUSE
11145 if (sym == sym_noreuse)
11146 return INT2NUM(POSIX_FADV_NOREUSE);
11147#endif
11148
11149 return Qnil;
11150}
11151
11152static VALUE
11153do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
11154{
11155 int rv;
11156 struct io_advise_struct ias;
11157 VALUE num_adv;
11158
11159 num_adv = io_advise_sym_to_const(advice);
11160
11161 /*
11162 * The platform doesn't support this hint. We don't raise exception, instead
11163 * silently ignore it. Because IO::advise is only hint.
11164 */
11165 if (NIL_P(num_adv))
11166 return Qnil;
11167
11168 ias.fd = fptr->fd;
11169 ias.advice = NUM2INT(num_adv);
11170 ias.offset = offset;
11171 ias.len = len;
11172
11173 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
11174 if (rv && rv != ENOSYS) {
11175 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
11176 it returns the error code. */
11177 VALUE message = rb_sprintf("%"PRIsVALUE" "
11178 "(%"PRI_OFFT_PREFIX"d, "
11179 "%"PRI_OFFT_PREFIX"d, "
11180 "%"PRIsVALUE")",
11181 fptr->pathv, offset, len, advice);
11182 rb_syserr_fail_str(rv, message);
11183 }
11184
11185 return Qnil;
11186}
11187
11188#endif /* HAVE_POSIX_FADVISE */
11189
11190static void
11191advice_arg_check(VALUE advice)
11192{
11193 if (!SYMBOL_P(advice))
11194 rb_raise(rb_eTypeError, "advice must be a Symbol");
11195
11196 if (advice != sym_normal &&
11197 advice != sym_sequential &&
11198 advice != sym_random &&
11199 advice != sym_willneed &&
11200 advice != sym_dontneed &&
11201 advice != sym_noreuse) {
11202 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
11203 }
11204}
11205
11206/*
11207 * call-seq:
11208 * advise(advice, offset = 0, len = 0) -> nil
11209 *
11210 * Invokes Posix system call
11211 * {posix_fadvise(2)}[https://man7.org/linux/man-pages/man2/posix_fadvise.2.html],
11212 * which announces an intention to access data from the current file
11213 * in a particular manner.
11214 *
11215 * The arguments and results are platform-dependent.
11216 *
11217 * The relevant data is specified by:
11218 *
11219 * - +offset+: The offset of the first byte of data.
11220 * - +len+: The number of bytes to be accessed;
11221 * if +len+ is zero, or is larger than the number of bytes remaining,
11222 * all remaining bytes will be accessed.
11223 *
11224 * Argument +advice+ is one of the following symbols:
11225 *
11226 * - +:normal+: The application has no advice to give
11227 * about its access pattern for the specified data.
11228 * If no advice is given for an open file, this is the default assumption.
11229 * - +:sequential+: The application expects to access the specified data sequentially
11230 * (with lower offsets read before higher ones).
11231 * - +:random+: The specified data will be accessed in random order.
11232 * - +:noreuse+: The specified data will be accessed only once.
11233 * - +:willneed+: The specified data will be accessed in the near future.
11234 * - +:dontneed+: The specified data will not be accessed in the near future.
11235 *
11236 * Not implemented on all platforms.
11237 *
11238 */
11239static VALUE
11240rb_io_advise(int argc, VALUE *argv, VALUE io)
11241{
11242 VALUE advice, offset, len;
11243 rb_off_t off, l;
11244 rb_io_t *fptr;
11245
11246 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
11247 advice_arg_check(advice);
11248
11249 io = GetWriteIO(io);
11250 GetOpenFile(io, fptr);
11251
11252 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
11253 l = NIL_P(len) ? 0 : NUM2OFFT(len);
11254
11255#ifdef HAVE_POSIX_FADVISE
11256 return do_io_advise(fptr, advice, off, l);
11257#else
11258 ((void)off, (void)l); /* Ignore all hint */
11259 return Qnil;
11260#endif
11261}
11262
11263static int
11264is_pos_inf(VALUE x)
11265{
11266 double f;
11267 if (!RB_FLOAT_TYPE_P(x))
11268 return 0;
11269 f = RFLOAT_VALUE(x);
11270 return isinf(f) && 0 < f;
11271}
11272
11273/*
11274 * call-seq:
11275 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11276 *
11277 * Invokes system call {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html],
11278 * which monitors multiple file descriptors,
11279 * waiting until one or more of the file descriptors
11280 * becomes ready for some class of I/O operation.
11281 *
11282 * Not implemented on all platforms.
11283 *
11284 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11285 * is an array of IO objects.
11286 *
11287 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11288 * interval in seconds.
11289 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11290 * +nil+ and +Float::INFINITY+ means no timeout.
11291 *
11292 * The method monitors the \IO objects given in all three arrays,
11293 * waiting for some to be ready;
11294 * returns a 3-element array whose elements are:
11295 *
11296 * - An array of the objects in +read_ios+ that are ready for reading.
11297 * - An array of the objects in +write_ios+ that are ready for writing.
11298 * - An array of the objects in +error_ios+ have pending exceptions.
11299 *
11300 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11301 *
11302 * \IO.select peeks the buffer of \IO objects for testing readability.
11303 * If the \IO buffer is not empty, \IO.select immediately notifies
11304 * readability. This "peek" only happens for \IO objects. It does not
11305 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11306 *
11307 * The best way to use \IO.select is invoking it after non-blocking
11308 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11309 * raise an exception which is extended by IO::WaitReadable or
11310 * IO::WaitWritable. The modules notify how the caller should wait
11311 * with \IO.select. If IO::WaitReadable is raised, the caller should
11312 * wait for reading. If IO::WaitWritable is raised, the caller should
11313 * wait for writing.
11314 *
11315 * So, blocking read (#readpartial) can be emulated using
11316 * #read_nonblock and \IO.select as follows:
11317 *
11318 * begin
11319 * result = io_like.read_nonblock(maxlen)
11320 * rescue IO::WaitReadable
11321 * IO.select([io_like])
11322 * retry
11323 * rescue IO::WaitWritable
11324 * IO.select(nil, [io_like])
11325 * retry
11326 * end
11327 *
11328 * Especially, the combination of non-blocking methods and \IO.select is
11329 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11330 * has #to_io method to return underlying IO object. IO.select calls
11331 * #to_io to obtain the file descriptor to wait.
11332 *
11333 * This means that readability notified by \IO.select doesn't mean
11334 * readability from OpenSSL::SSL::SSLSocket object.
11335 *
11336 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11337 * some data. \IO.select doesn't see the buffer. So \IO.select can
11338 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11339 *
11340 * However, several more complicated situations exist.
11341 *
11342 * SSL is a protocol which is sequence of records.
11343 * The record consists of multiple bytes.
11344 * So, the remote side of SSL sends a partial record, IO.select
11345 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11346 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11347 *
11348 * Also, the remote side can request SSL renegotiation which forces
11349 * the local SSL engine to write some data.
11350 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11351 * system call and it can block.
11352 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11353 * IO::WaitWritable instead of blocking.
11354 * So, the caller should wait for ready for writability as above
11355 * example.
11356 *
11357 * The combination of non-blocking methods and \IO.select is also useful
11358 * for streams such as tty, pipe socket socket when multiple processes
11359 * read from a stream.
11360 *
11361 * Finally, Linux kernel developers don't guarantee that
11362 * readability of select(2) means readability of following read(2) even
11363 * for a single process;
11364 * see {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html]
11365 *
11366 * Invoking \IO.select before IO#readpartial works well as usual.
11367 * However it is not the best way to use \IO.select.
11368 *
11369 * The writability notified by select(2) doesn't show
11370 * how many bytes are writable.
11371 * IO#write method blocks until given whole string is written.
11372 * So, <tt>IO#write(two or more bytes)</tt> can block after
11373 * writability is notified by \IO.select. IO#write_nonblock is required
11374 * to avoid the blocking.
11375 *
11376 * Blocking write (#write) can be emulated using #write_nonblock and
11377 * IO.select as follows: IO::WaitReadable should also be rescued for
11378 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11379 *
11380 * while 0 < string.bytesize
11381 * begin
11382 * written = io_like.write_nonblock(string)
11383 * rescue IO::WaitReadable
11384 * IO.select([io_like])
11385 * retry
11386 * rescue IO::WaitWritable
11387 * IO.select(nil, [io_like])
11388 * retry
11389 * end
11390 * string = string.byteslice(written..-1)
11391 * end
11392 *
11393 * Example:
11394 *
11395 * rp, wp = IO.pipe
11396 * mesg = "ping "
11397 * 100.times {
11398 * # IO.select follows IO#read. Not the best way to use IO.select.
11399 * rs, ws, = IO.select([rp], [wp])
11400 * if r = rs[0]
11401 * ret = r.read(5)
11402 * print ret
11403 * case ret
11404 * when /ping/
11405 * mesg = "pong\n"
11406 * when /pong/
11407 * mesg = "ping "
11408 * end
11409 * end
11410 * if w = ws[0]
11411 * w.write(mesg)
11412 * end
11413 * }
11414 *
11415 * Output:
11416 *
11417 * ping pong
11418 * ping pong
11419 * ping pong
11420 * (snipped)
11421 * ping
11422 *
11423 */
11424
11425static VALUE
11426rb_f_select(int argc, VALUE *argv, VALUE obj)
11427{
11428 VALUE scheduler = rb_fiber_scheduler_current();
11429 if (scheduler != Qnil) {
11430 // It's optionally supported.
11431 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11432 if (!UNDEF_P(result)) return result;
11433 }
11434
11435 VALUE timeout;
11436 struct select_args args;
11437 struct timeval timerec;
11438 int i;
11439
11440 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11441 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11442 args.timeout = 0;
11443 }
11444 else {
11445 timerec = rb_time_interval(timeout);
11446 args.timeout = &timerec;
11447 }
11448
11449 for (i = 0; i < numberof(args.fdsets); ++i)
11450 rb_fd_init(&args.fdsets[i]);
11451
11452 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11453}
11454
11455#ifdef IOCTL_REQ_TYPE
11456 typedef IOCTL_REQ_TYPE ioctl_req_t;
11457#else
11458 typedef int ioctl_req_t;
11459# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11460#endif
11461
11462#ifdef HAVE_IOCTL
11463struct ioctl_arg {
11464 int fd;
11465 ioctl_req_t cmd;
11466 long narg;
11467};
11468
11469static VALUE
11470nogvl_ioctl(void *ptr)
11471{
11472 struct ioctl_arg *arg = ptr;
11473
11474 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11475}
11476
11477static int
11478do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11479{
11480 int retval;
11481 struct ioctl_arg arg;
11482
11483 arg.fd = io->fd;
11484 arg.cmd = cmd;
11485 arg.narg = narg;
11486
11487 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11488
11489 return retval;
11490}
11491#endif
11492
11493#define DEFAULT_IOCTL_NARG_LEN (256)
11494
11495#if defined(__linux__) && defined(_IOC_SIZE)
11496static long
11497linux_iocparm_len(ioctl_req_t cmd)
11498{
11499 long len;
11500
11501 if ((cmd & 0xFFFF0000) == 0) {
11502 /* legacy and unstructured ioctl number. */
11503 return DEFAULT_IOCTL_NARG_LEN;
11504 }
11505
11506 len = _IOC_SIZE(cmd);
11507
11508 /* paranoia check for silly drivers which don't keep ioctl convention */
11509 if (len < DEFAULT_IOCTL_NARG_LEN)
11510 len = DEFAULT_IOCTL_NARG_LEN;
11511
11512 return len;
11513}
11514#endif
11515
11516#ifdef HAVE_IOCTL
11517static long
11518ioctl_narg_len(ioctl_req_t cmd)
11519{
11520 long len;
11521
11522#ifdef IOCPARM_MASK
11523#ifndef IOCPARM_LEN
11524#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11525#endif
11526#endif
11527#ifdef IOCPARM_LEN
11528 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11529#elif defined(__linux__) && defined(_IOC_SIZE)
11530 len = linux_iocparm_len(cmd);
11531#else
11532 /* otherwise guess at what's safe */
11533 len = DEFAULT_IOCTL_NARG_LEN;
11534#endif
11535
11536 return len;
11537}
11538#endif
11539
11540#ifdef HAVE_FCNTL
11541#ifdef __linux__
11542typedef long fcntl_arg_t;
11543#else
11544/* posix */
11545typedef int fcntl_arg_t;
11546#endif
11547
11548static long
11549fcntl_narg_len(ioctl_req_t cmd)
11550{
11551 long len;
11552
11553 switch (cmd) {
11554#ifdef F_DUPFD
11555 case F_DUPFD:
11556 len = sizeof(fcntl_arg_t);
11557 break;
11558#endif
11559#ifdef F_DUP2FD /* bsd specific */
11560 case F_DUP2FD:
11561 len = sizeof(int);
11562 break;
11563#endif
11564#ifdef F_DUPFD_CLOEXEC /* linux specific */
11565 case F_DUPFD_CLOEXEC:
11566 len = sizeof(fcntl_arg_t);
11567 break;
11568#endif
11569#ifdef F_GETFD
11570 case F_GETFD:
11571 len = 1;
11572 break;
11573#endif
11574#ifdef F_SETFD
11575 case F_SETFD:
11576 len = sizeof(fcntl_arg_t);
11577 break;
11578#endif
11579#ifdef F_GETFL
11580 case F_GETFL:
11581 len = 1;
11582 break;
11583#endif
11584#ifdef F_SETFL
11585 case F_SETFL:
11586 len = sizeof(fcntl_arg_t);
11587 break;
11588#endif
11589#ifdef F_GETOWN
11590 case F_GETOWN:
11591 len = 1;
11592 break;
11593#endif
11594#ifdef F_SETOWN
11595 case F_SETOWN:
11596 len = sizeof(fcntl_arg_t);
11597 break;
11598#endif
11599#ifdef F_GETOWN_EX /* linux specific */
11600 case F_GETOWN_EX:
11601 len = sizeof(struct f_owner_ex);
11602 break;
11603#endif
11604#ifdef F_SETOWN_EX /* linux specific */
11605 case F_SETOWN_EX:
11606 len = sizeof(struct f_owner_ex);
11607 break;
11608#endif
11609#ifdef F_GETLK
11610 case F_GETLK:
11611 len = sizeof(struct flock);
11612 break;
11613#endif
11614#ifdef F_SETLK
11615 case F_SETLK:
11616 len = sizeof(struct flock);
11617 break;
11618#endif
11619#ifdef F_SETLKW
11620 case F_SETLKW:
11621 len = sizeof(struct flock);
11622 break;
11623#endif
11624#ifdef F_READAHEAD /* bsd specific */
11625 case F_READAHEAD:
11626 len = sizeof(int);
11627 break;
11628#endif
11629#ifdef F_RDAHEAD /* Darwin specific */
11630 case F_RDAHEAD:
11631 len = sizeof(int);
11632 break;
11633#endif
11634#ifdef F_GETSIG /* linux specific */
11635 case F_GETSIG:
11636 len = 1;
11637 break;
11638#endif
11639#ifdef F_SETSIG /* linux specific */
11640 case F_SETSIG:
11641 len = sizeof(fcntl_arg_t);
11642 break;
11643#endif
11644#ifdef F_GETLEASE /* linux specific */
11645 case F_GETLEASE:
11646 len = 1;
11647 break;
11648#endif
11649#ifdef F_SETLEASE /* linux specific */
11650 case F_SETLEASE:
11651 len = sizeof(fcntl_arg_t);
11652 break;
11653#endif
11654#ifdef F_NOTIFY /* linux specific */
11655 case F_NOTIFY:
11656 len = sizeof(fcntl_arg_t);
11657 break;
11658#endif
11659
11660 default:
11661 len = 256;
11662 break;
11663 }
11664
11665 return len;
11666}
11667#else /* HAVE_FCNTL */
11668static long
11669fcntl_narg_len(ioctl_req_t cmd)
11670{
11671 return 0;
11672}
11673#endif /* HAVE_FCNTL */
11674
11675#define NARG_SENTINEL 17
11676
11677static long
11678setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11679{
11680 long narg = 0;
11681 VALUE arg = *argp;
11682
11683 if (!RTEST(arg)) {
11684 narg = 0;
11685 }
11686 else if (FIXNUM_P(arg)) {
11687 narg = FIX2LONG(arg);
11688 }
11689 else if (arg == Qtrue) {
11690 narg = 1;
11691 }
11692 else {
11693 VALUE tmp = rb_check_string_type(arg);
11694
11695 if (NIL_P(tmp)) {
11696 narg = NUM2LONG(arg);
11697 }
11698 else {
11699 char *ptr;
11700 long len, slen;
11701
11702 *argp = arg = tmp;
11703 len = narg_len(cmd);
11704 rb_str_modify(arg);
11705
11706 slen = RSTRING_LEN(arg);
11707 /* expand for data + sentinel. */
11708 if (slen < len+1) {
11709 rb_str_resize(arg, len+1);
11710 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11711 slen = len+1;
11712 }
11713 /* a little sanity check here */
11714 ptr = RSTRING_PTR(arg);
11715 ptr[slen - 1] = NARG_SENTINEL;
11716 narg = (long)(SIGNED_VALUE)ptr;
11717 }
11718 }
11719
11720 return narg;
11721}
11722
11723static VALUE
11724finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11725{
11726 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11727 if (RB_TYPE_P(arg, T_STRING)) {
11728 char *ptr;
11729 long slen;
11730 RSTRING_GETMEM(arg, ptr, slen);
11731 if (ptr[slen-1] != NARG_SENTINEL)
11732 rb_raise(rb_eArgError, "return value overflowed string");
11733 ptr[slen-1] = '\0';
11734 }
11735
11736 return INT2NUM(retval);
11737}
11738
11739#ifdef HAVE_IOCTL
11740static VALUE
11741rb_ioctl(VALUE io, VALUE req, VALUE arg)
11742{
11743 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11744 rb_io_t *fptr;
11745 long narg;
11746 int retval;
11747
11748 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11749 GetOpenFile(io, fptr);
11750 retval = do_ioctl(fptr, cmd, narg);
11751 return finish_narg(retval, arg, fptr);
11752}
11753
11754/*
11755 * call-seq:
11756 * ioctl(integer_cmd, argument) -> integer
11757 *
11758 * Invokes Posix system call {ioctl(2)}[https://man7.org/linux/man-pages/man2/ioctl.2.html],
11759 * which issues a low-level command to an I/O device.
11760 *
11761 * Issues a low-level command to an I/O device.
11762 * The arguments and returned value are platform-dependent.
11763 * The effect of the call is platform-dependent.
11764 *
11765 * If argument +argument+ is an integer, it is passed directly;
11766 * if it is a string, it is interpreted as a binary sequence of bytes.
11767 *
11768 * Not implemented on all platforms.
11769 *
11770 */
11771
11772static VALUE
11773rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11774{
11775 VALUE req, arg;
11776
11777 rb_scan_args(argc, argv, "11", &req, &arg);
11778 return rb_ioctl(io, req, arg);
11779}
11780#else
11781#define rb_io_ioctl rb_f_notimplement
11782#endif
11783
11784#ifdef HAVE_FCNTL
11785struct fcntl_arg {
11786 int fd;
11787 int cmd;
11788 long narg;
11789};
11790
11791static VALUE
11792nogvl_fcntl(void *ptr)
11793{
11794 struct fcntl_arg *arg = ptr;
11795
11796#if defined(F_DUPFD)
11797 if (arg->cmd == F_DUPFD)
11798 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11799#endif
11800 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11801}
11802
11803static int
11804do_fcntl(struct rb_io *io, int cmd, long narg)
11805{
11806 int retval;
11807 struct fcntl_arg arg;
11808
11809 arg.fd = io->fd;
11810 arg.cmd = cmd;
11811 arg.narg = narg;
11812
11813 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11814 if (retval != -1) {
11815 switch (cmd) {
11816#if defined(F_DUPFD)
11817 case F_DUPFD:
11818#endif
11819#if defined(F_DUPFD_CLOEXEC)
11820 case F_DUPFD_CLOEXEC:
11821#endif
11822 rb_update_max_fd(retval);
11823 }
11824 }
11825
11826 return retval;
11827}
11828
11829static VALUE
11830rb_fcntl(VALUE io, VALUE req, VALUE arg)
11831{
11832 int cmd = NUM2INT(req);
11833 rb_io_t *fptr;
11834 long narg;
11835 int retval;
11836
11837 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11838 GetOpenFile(io, fptr);
11839 retval = do_fcntl(fptr, cmd, narg);
11840 return finish_narg(retval, arg, fptr);
11841}
11842
11843/*
11844 * call-seq:
11845 * fcntl(integer_cmd, argument) -> integer
11846 *
11847 * Invokes Posix system call {fcntl(2)}[https://man7.org/linux/man-pages/man2/fcntl.2.html],
11848 * which provides a mechanism for issuing low-level commands to control or query
11849 * a file-oriented I/O stream. Arguments and results are platform
11850 * dependent.
11851 *
11852 * If +argument+ is a number, its value is passed directly;
11853 * if it is a string, it is interpreted as a binary sequence of bytes.
11854 * (Array#pack might be a useful way to build this string.)
11855 *
11856 * Not implemented on all platforms.
11857 *
11858 */
11859
11860static VALUE
11861rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11862{
11863 VALUE req, arg;
11864
11865 rb_scan_args(argc, argv, "11", &req, &arg);
11866 return rb_fcntl(io, req, arg);
11867}
11868#else
11869#define rb_io_fcntl rb_f_notimplement
11870#endif
11871
11872#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11873/*
11874 * call-seq:
11875 * syscall(integer_callno, *arguments) -> integer
11876 *
11877 * Invokes Posix system call {syscall(2)}[https://man7.org/linux/man-pages/man2/syscall.2.html],
11878 * which calls a specified function.
11879 *
11880 * Calls the operating system function identified by +integer_callno+;
11881 * returns the result of the function or raises SystemCallError if it failed.
11882 * The effect of the call is platform-dependent.
11883 * The arguments and returned value are platform-dependent.
11884 *
11885 * For each of +arguments+: if it is an integer, it is passed directly;
11886 * if it is a string, it is interpreted as a binary sequence of bytes.
11887 * There may be as many as nine such arguments.
11888 *
11889 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11890 * are platform-dependent.
11891 *
11892 * Note: Method +syscall+ is essentially unsafe and unportable.
11893 * The DL (Fiddle) library is preferred for safer and a bit
11894 * more portable programming.
11895 *
11896 * Not implemented on all platforms.
11897 *
11898 */
11899
11900static VALUE
11901rb_f_syscall(int argc, VALUE *argv, VALUE _)
11902{
11903 VALUE arg[8];
11904#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11905# define SYSCALL __syscall
11906# define NUM2SYSCALLID(x) NUM2LONG(x)
11907# define RETVAL2NUM(x) LONG2NUM(x)
11908# if SIZEOF_LONG == 8
11909 long num, retval = -1;
11910# elif SIZEOF_LONG_LONG == 8
11911 long long num, retval = -1;
11912# else
11913# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11914# endif
11915#elif defined(__linux__)
11916# define SYSCALL syscall
11917# define NUM2SYSCALLID(x) NUM2LONG(x)
11918# define RETVAL2NUM(x) LONG2NUM(x)
11919 /*
11920 * Linux man page says, syscall(2) function prototype is below.
11921 *
11922 * int syscall(int number, ...);
11923 *
11924 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11925 */
11926 long num, retval = -1;
11927#else
11928# define SYSCALL syscall
11929# define NUM2SYSCALLID(x) NUM2INT(x)
11930# define RETVAL2NUM(x) INT2NUM(x)
11931 int num, retval = -1;
11932#endif
11933 int i;
11934
11935 if (RTEST(ruby_verbose)) {
11937 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11938 }
11939
11940 if (argc == 0)
11941 rb_raise(rb_eArgError, "too few arguments for syscall");
11942 if (argc > numberof(arg))
11943 rb_raise(rb_eArgError, "too many arguments for syscall");
11944 num = NUM2SYSCALLID(argv[0]); ++argv;
11945 for (i = argc - 1; i--; ) {
11946 VALUE v = rb_check_string_type(argv[i]);
11947
11948 if (!NIL_P(v)) {
11949 StringValue(v);
11950 rb_str_modify(v);
11951 arg[i] = (VALUE)StringValueCStr(v);
11952 }
11953 else {
11954 arg[i] = (VALUE)NUM2LONG(argv[i]);
11955 }
11956 }
11957
11958 switch (argc) {
11959 case 1:
11960 retval = SYSCALL(num);
11961 break;
11962 case 2:
11963 retval = SYSCALL(num, arg[0]);
11964 break;
11965 case 3:
11966 retval = SYSCALL(num, arg[0],arg[1]);
11967 break;
11968 case 4:
11969 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11970 break;
11971 case 5:
11972 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11973 break;
11974 case 6:
11975 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11976 break;
11977 case 7:
11978 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11979 break;
11980 case 8:
11981 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11982 break;
11983 }
11984
11985 if (retval == -1)
11986 rb_sys_fail(0);
11987 return RETVAL2NUM(retval);
11988#undef SYSCALL
11989#undef NUM2SYSCALLID
11990#undef RETVAL2NUM
11991}
11992#else
11993#define rb_f_syscall rb_f_notimplement
11994#endif
11995
11996static VALUE
11997io_new_instance(VALUE args)
11998{
11999 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
12000}
12001
12002static rb_encoding *
12003find_encoding(VALUE v)
12004{
12005 rb_encoding *enc = rb_find_encoding(v);
12006 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
12007 return enc;
12008}
12009
12010static void
12011io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
12012{
12013 rb_encoding *enc, *enc2;
12014 int ecflags = fptr->encs.ecflags;
12015 VALUE ecopts, tmp;
12016
12017 if (!NIL_P(v2)) {
12018 enc2 = find_encoding(v1);
12019 tmp = rb_check_string_type(v2);
12020 if (!NIL_P(tmp)) {
12021 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
12022 /* Special case - "-" => no transcoding */
12023 enc = enc2;
12024 enc2 = NULL;
12025 }
12026 else
12027 enc = find_encoding(v2);
12028 if (enc == enc2) {
12029 /* Special case - "-" => no transcoding */
12030 enc2 = NULL;
12031 }
12032 }
12033 else {
12034 enc = find_encoding(v2);
12035 if (enc == enc2) {
12036 /* Special case - "-" => no transcoding */
12037 enc2 = NULL;
12038 }
12039 }
12040 if (enc2 == rb_ascii8bit_encoding()) {
12041 /* If external is ASCII-8BIT, no transcoding */
12042 enc = enc2;
12043 enc2 = NULL;
12044 }
12045 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12046 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
12047 }
12048 else {
12049 if (NIL_P(v1)) {
12050 /* Set to default encodings */
12051 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
12052 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12053 ecopts = Qnil;
12054 }
12055 else {
12056 tmp = rb_check_string_type(v1);
12057 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
12058 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
12059 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12060 }
12061 else {
12062 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
12063 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12064 }
12065 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
12066 }
12067 }
12068 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
12069 fptr->encs.enc = enc;
12070 fptr->encs.enc2 = enc2;
12071 fptr->encs.ecflags = ecflags;
12072 fptr->encs.ecopts = ecopts;
12073 clear_codeconv(fptr);
12074
12075}
12076
12078 rb_io_t *fptr;
12079 VALUE v1;
12080 VALUE v2;
12081 VALUE opt;
12082};
12083
12084static VALUE
12085io_encoding_set_v(VALUE v)
12086{
12087 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
12088 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
12089 return Qnil;
12090}
12091
12092static VALUE
12093pipe_pair_close(VALUE rw)
12094{
12095 VALUE *rwp = (VALUE *)rw;
12096 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
12097}
12098
12099/*
12100 * call-seq:
12101 * IO.pipe(**opts) -> [read_io, write_io]
12102 * IO.pipe(enc, **opts) -> [read_io, write_io]
12103 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
12104 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
12105 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
12106 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
12107 *
12108 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
12109 * connected to each other.
12110 *
12111 * If argument +enc_string+ is given, it must be a string containing one of:
12112 *
12113 * - The name of the encoding to be used as the external encoding.
12114 * - The colon-separated names of two encodings to be used as the external
12115 * and internal encodings.
12116 *
12117 * If argument +int_enc+ is given, it must be an Encoding object
12118 * or encoding name string that specifies the internal encoding to be used;
12119 * if argument +ext_enc+ is also given, it must be an Encoding object
12120 * or encoding name string that specifies the external encoding to be used.
12121 *
12122 * The string read from +read_io+ is tagged with the external encoding;
12123 * if an internal encoding is also specified, the string is converted
12124 * to, and tagged with, that encoding.
12125 *
12126 * If any encoding is specified,
12127 * optional hash arguments specify the conversion option.
12128 *
12129 * Optional keyword arguments +opts+ specify:
12130 *
12131 * - {Open Options}[rdoc-ref:IO@Open+Options].
12132 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12133 *
12134 * With no block given, returns the two endpoints in an array:
12135 *
12136 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
12137 *
12138 * With a block given, calls the block with the two endpoints;
12139 * closes both endpoints and returns the value of the block:
12140 *
12141 * IO.pipe {|read_io, write_io| p read_io; p write_io }
12142 *
12143 * Output:
12144 *
12145 * #<IO:fd 6>
12146 * #<IO:fd 7>
12147 *
12148 * Not available on all platforms.
12149 *
12150 * In the example below, the two processes close the ends of the pipe
12151 * that they are not using. This is not just a cosmetic nicety. The
12152 * read end of a pipe will not generate an end of file condition if
12153 * there are any writers with the pipe still open. In the case of the
12154 * parent process, the <tt>rd.read</tt> will never return if it
12155 * does not first issue a <tt>wr.close</tt>:
12156 *
12157 * rd, wr = IO.pipe
12158 *
12159 * if fork
12160 * wr.close
12161 * puts "Parent got: <#{rd.read}>"
12162 * rd.close
12163 * Process.wait
12164 * else
12165 * rd.close
12166 * puts 'Sending message to parent'
12167 * wr.write "Hi Dad"
12168 * wr.close
12169 * end
12170 *
12171 * <em>produces:</em>
12172 *
12173 * Sending message to parent
12174 * Parent got: <Hi Dad>
12175 *
12176 */
12177
12178static VALUE
12179rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
12180{
12181 int pipes[2], state;
12182 VALUE r, w, args[3], v1, v2;
12183 VALUE opt;
12184 rb_io_t *fptr, *fptr2;
12185 struct io_encoding_set_args ies_args;
12186 enum rb_io_mode fmode = 0;
12187 VALUE ret;
12188
12189 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
12190 if (rb_pipe(pipes) < 0)
12191 rb_sys_fail(0);
12192
12193 args[0] = klass;
12194 args[1] = INT2NUM(pipes[0]);
12195 args[2] = INT2FIX(O_RDONLY);
12196 r = rb_protect(io_new_instance, (VALUE)args, &state);
12197 if (state) {
12198 close(pipes[0]);
12199 close(pipes[1]);
12200 rb_jump_tag(state);
12201 }
12202 GetOpenFile(r, fptr);
12203
12204 ies_args.fptr = fptr;
12205 ies_args.v1 = v1;
12206 ies_args.v2 = v2;
12207 ies_args.opt = opt;
12208 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
12209 if (state) {
12210 close(pipes[1]);
12211 io_close(r);
12212 rb_jump_tag(state);
12213 }
12214
12215 args[1] = INT2NUM(pipes[1]);
12216 args[2] = INT2FIX(O_WRONLY);
12217 w = rb_protect(io_new_instance, (VALUE)args, &state);
12218 if (state) {
12219 close(pipes[1]);
12220 if (!NIL_P(r)) rb_io_close(r);
12221 rb_jump_tag(state);
12222 }
12223 GetOpenFile(w, fptr2);
12224 rb_io_synchronized(fptr2);
12225
12226 extract_binmode(opt, &fmode);
12227
12228 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
12231 }
12232
12233#if DEFAULT_TEXTMODE
12234 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12235 fptr->mode &= ~FMODE_TEXTMODE;
12236 setmode(fptr->fd, O_BINARY);
12237 }
12238#if RUBY_CRLF_ENVIRONMENT
12241 }
12242#endif
12243#endif
12244 fptr->mode |= fmode;
12245#if DEFAULT_TEXTMODE
12246 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12247 fptr2->mode &= ~FMODE_TEXTMODE;
12248 setmode(fptr2->fd, O_BINARY);
12249 }
12250#endif
12251 fptr2->mode |= fmode;
12252
12253 ret = rb_assoc_new(r, w);
12254 if (rb_block_given_p()) {
12255 VALUE rw[2];
12256 rw[0] = r;
12257 rw[1] = w;
12258 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12259 }
12260 return ret;
12261}
12262
12264 int argc;
12265 VALUE *argv;
12266 VALUE io;
12267};
12268
12269static void
12270open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12271{
12272 VALUE path, v;
12273 VALUE vmode = Qnil, vperm = Qnil;
12274
12275 path = *argv++;
12276 argc--;
12277 FilePathValue(path);
12278 arg->io = 0;
12279 arg->argc = argc;
12280 arg->argv = argv;
12281 if (NIL_P(opt)) {
12282 vmode = INT2NUM(O_RDONLY);
12283 vperm = INT2FIX(0666);
12284 }
12285 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12286 int n;
12287
12288 v = rb_to_array_type(v);
12289 n = RARRAY_LENINT(v);
12290 rb_check_arity(n, 0, 3); /* rb_io_open */
12291 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12292 }
12293 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12294}
12295
12296static VALUE
12297io_s_foreach(VALUE v)
12298{
12299 struct getline_arg *arg = (void *)v;
12300 VALUE str;
12301
12302 if (arg->limit == 0)
12303 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12304 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12305 rb_lastline_set(str);
12306 rb_yield(str);
12307 }
12309 return Qnil;
12310}
12311
12312/*
12313 * call-seq:
12314 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12315 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12316 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12317 * IO.foreach(...) -> an_enumerator
12318 *
12319 * Calls the block with each successive line read from the stream.
12320 *
12321 * The first argument must be a string that is the path to a file.
12322 *
12323 * With only argument +path+ given, parses lines from the file at the given +path+,
12324 * as determined by the default line separator,
12325 * and calls the block with each successive line:
12326 *
12327 * File.foreach('t.txt') {|line| p line }
12328 *
12329 * Output: the same as above.
12330 *
12331 * For both forms, command and path, the remaining arguments are the same.
12332 *
12333 * With argument +sep+ given, parses lines as determined by that line separator
12334 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12335 *
12336 * File.foreach('t.txt', 'li') {|line| p line }
12337 *
12338 * Output:
12339 *
12340 * "First li"
12341 * "ne\nSecond li"
12342 * "ne\n\nThird li"
12343 * "ne\nFourth li"
12344 * "ne\n"
12345 *
12346 * Each paragraph:
12347 *
12348 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12349 *
12350 * Output:
12351 *
12352 * "First line\nSecond line\n\n"
12353 * "Third line\nFourth line\n"
12354 *
12355 * With argument +limit+ given, parses lines as determined by the default
12356 * line separator and the given line-length limit
12357 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12358 *
12359 * File.foreach('t.txt', 7) {|line| p line }
12360 *
12361 * Output:
12362 *
12363 * "First l"
12364 * "ine\n"
12365 * "Second "
12366 * "line\n"
12367 * "\n"
12368 * "Third l"
12369 * "ine\n"
12370 * "Fourth l"
12371 * "line\n"
12372 *
12373 * With arguments +sep+ and +limit+ given,
12374 * combines the two behaviors
12375 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12376 *
12377 * Optional keyword arguments +opts+ specify:
12378 *
12379 * - {Open Options}[rdoc-ref:IO@Open+Options].
12380 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12381 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12382 *
12383 * Returns an Enumerator if no block is given.
12384 *
12385 */
12386
12387static VALUE
12388rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12389{
12390 VALUE opt;
12391 int orig_argc = argc;
12392 struct foreach_arg arg;
12393 struct getline_arg garg;
12394
12395 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12396 RETURN_ENUMERATOR(self, orig_argc, argv);
12397 extract_getline_args(argc-1, argv+1, &garg);
12398 open_key_args(self, argc, argv, opt, &arg);
12399 if (NIL_P(arg.io)) return Qnil;
12400 extract_getline_opts(opt, &garg);
12401 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12402 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12403}
12404
12405static VALUE
12406io_s_readlines(VALUE v)
12407{
12408 struct getline_arg *arg = (void *)v;
12409 return io_readlines(arg, arg->io);
12410}
12411
12412/*
12413 * call-seq:
12414 * IO.readlines(path, sep = $/, **opts) -> array
12415 * IO.readlines(path, limit, **opts) -> array
12416 * IO.readlines(path, sep, limit, **opts) -> array
12417 *
12418 * Returns an array of all lines read from the stream.
12419 *
12420 * The first argument must be a string that is the path to a file.
12421 *
12422 * With only argument +path+ given, parses lines from the file at the given +path+,
12423 * as determined by the default line separator,
12424 * and returns those lines in an array:
12425 *
12426 * IO.readlines('t.txt')
12427 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12428 *
12429 * With argument +sep+ given, parses lines as determined by that line separator
12430 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12431 *
12432 * # Ordinary separator.
12433 * IO.readlines('t.txt', 'li')
12434 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12435 * # Get-paragraphs separator.
12436 * IO.readlines('t.txt', '')
12437 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12438 * # Get-all separator.
12439 * IO.readlines('t.txt', nil)
12440 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12441 *
12442 * With argument +limit+ given, parses lines as determined by the default
12443 * line separator and the given line-length limit
12444 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12445 *
12446 * IO.readlines('t.txt', 7)
12447 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12448 *
12449 * With arguments +sep+ and +limit+ given,
12450 * combines the two behaviors
12451 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12452 *
12453 * Optional keyword arguments +opts+ specify:
12454 *
12455 * - {Open Options}[rdoc-ref:IO@Open+Options].
12456 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12457 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12458 *
12459 */
12460
12461static VALUE
12462rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12463{
12464 VALUE opt;
12465 struct foreach_arg arg;
12466 struct getline_arg garg;
12467
12468 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12469 extract_getline_args(argc-1, argv+1, &garg);
12470 open_key_args(io, argc, argv, opt, &arg);
12471 if (NIL_P(arg.io)) return Qnil;
12472 extract_getline_opts(opt, &garg);
12473 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12474 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12475}
12476
12477static VALUE
12478io_s_read(VALUE v)
12479{
12480 struct foreach_arg *arg = (void *)v;
12481 return io_read(arg->argc, arg->argv, arg->io);
12482}
12483
12484struct seek_arg {
12485 VALUE io;
12486 VALUE offset;
12487 int mode;
12488};
12489
12490static VALUE
12491seek_before_access(VALUE argp)
12492{
12493 struct seek_arg *arg = (struct seek_arg *)argp;
12494 rb_io_binmode(arg->io);
12495 return rb_io_seek(arg->io, arg->offset, arg->mode);
12496}
12497
12498/*
12499 * call-seq:
12500 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12501 *
12502 * Opens the stream, reads and returns some or all of its content,
12503 * and closes the stream; returns +nil+ if no bytes were read.
12504 *
12505 * The first argument must be a string that is the path to a file.
12506 *
12507 * With only argument +path+ given, reads in text mode and returns the entire content
12508 * of the file at the given path:
12509 *
12510 * File.read('t.txt')
12511 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
12512 * File.read('t.ja')
12513 * # => "こんにちは"
12514 * File.read('t.dat')
12515 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12516 *
12517 * On Windows, text mode can terminate reading and leave bytes in the file
12518 * unread when encountering certain special bytes. Consider using
12519 * IO.binread if all bytes in the file should be read.
12520 *
12521 * With argument +length+, returns +length+ bytes if available:
12522 *
12523 * File.read('t.txt', 7)
12524 * # => "First l"
12525 * File.read('t.ja', 7)
12526 * # => "\xE3\x81\x93\xE3\x82\x93\xE3"
12527 * File.read('t.dat', 7)
12528 * # => "\xFE\xFF\x99\x90\x99\x91\x99"
12529 *
12530 * Returns all bytes if +length+ is larger than the files size:
12531 *
12532 * File.read('t.txt', 700)
12533 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12534 * File.read('t.ja', 700)
12535 * # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
12536 * File.read('t.dat', 700)
12537 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12538 *
12539 * With arguments +length+ and +offset+, returns +length+ bytes
12540 * if available, beginning at the given +offset+:
12541 *
12542 * File.read('t.txt', 10, 2)
12543 * # => "rst line\r\n"
12544 * File.read('t.ja', 10, 2)
12545 * # => "\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1"
12546 * File.read('t.dat', 10, 2)
12547 * # => "\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12548 *
12549 * Returns +nil+ if +offset+ is past the end of the stream:
12550 *
12551 * File.read('t.txt', 10, 200)
12552 * # => nil
12553 *
12554 * Optional keyword arguments +opts+ specify:
12555 *
12556 * - {Open Options}[rdoc-ref:IO@Open+Options].
12557 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12558 *
12559 */
12560
12561static VALUE
12562rb_io_s_read(int argc, VALUE *argv, VALUE io)
12563{
12564 VALUE opt, offset;
12565 long off;
12566 struct foreach_arg arg;
12567
12568 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12569 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12570 rb_raise(rb_eArgError, "negative offset %ld given", off);
12571 }
12572 open_key_args(io, argc, argv, opt, &arg);
12573 if (NIL_P(arg.io)) return Qnil;
12574 if (!NIL_P(offset)) {
12575 struct seek_arg sarg;
12576 int state = 0;
12577 sarg.io = arg.io;
12578 sarg.offset = offset;
12579 sarg.mode = SEEK_SET;
12580 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12581 if (state) {
12582 rb_io_close(arg.io);
12583 rb_jump_tag(state);
12584 }
12585 if (arg.argc == 2) arg.argc = 1;
12586 }
12587 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12588}
12589
12590/*
12591 * call-seq:
12592 * IO.binread(path, length = nil, offset = 0) -> string or nil
12593 *
12594 * Behaves like IO.read, except that the stream is opened in binary mode
12595 * with ASCII-8BIT encoding.
12596 *
12597 */
12598
12599static VALUE
12600rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12601{
12602 VALUE offset;
12603 struct foreach_arg arg;
12604 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12605 enum {
12606 oflags = O_RDONLY
12607#ifdef O_BINARY
12608 |O_BINARY
12609#endif
12610 };
12611 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12612
12613 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12614 FilePathValue(argv[0]);
12615 convconfig.enc = rb_ascii8bit_encoding();
12616 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12617 if (NIL_P(arg.io)) return Qnil;
12618 arg.argv = argv+1;
12619 arg.argc = (argc > 1) ? 1 : 0;
12620 if (!NIL_P(offset)) {
12621 struct seek_arg sarg;
12622 int state = 0;
12623 sarg.io = arg.io;
12624 sarg.offset = offset;
12625 sarg.mode = SEEK_SET;
12626 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12627 if (state) {
12628 rb_io_close(arg.io);
12629 rb_jump_tag(state);
12630 }
12631 }
12632 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12633}
12634
12635static VALUE
12636io_s_write0(VALUE v)
12637{
12638 struct write_arg *arg = (void *)v;
12639 return io_write(arg->io,arg->str,arg->nosync);
12640}
12641
12642static VALUE
12643io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12644{
12645 VALUE string, offset, opt;
12646 struct foreach_arg arg;
12647 struct write_arg warg;
12648
12649 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12650
12651 if (NIL_P(opt)) opt = rb_hash_new();
12652 else opt = rb_hash_dup(opt);
12653
12654
12655 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12656 int mode = O_WRONLY|O_CREAT;
12657#ifdef O_BINARY
12658 if (binary) mode |= O_BINARY;
12659#endif
12660 if (NIL_P(offset)) mode |= O_TRUNC;
12661 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12662 }
12663 open_key_args(klass, argc, argv, opt, &arg);
12664
12665#ifndef O_BINARY
12666 if (binary) rb_io_binmode_m(arg.io);
12667#endif
12668
12669 if (NIL_P(arg.io)) return Qnil;
12670 if (!NIL_P(offset)) {
12671 struct seek_arg sarg;
12672 int state = 0;
12673 sarg.io = arg.io;
12674 sarg.offset = offset;
12675 sarg.mode = SEEK_SET;
12676 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12677 if (state) {
12678 rb_io_close(arg.io);
12679 rb_jump_tag(state);
12680 }
12681 }
12682
12683 warg.io = arg.io;
12684 warg.str = string;
12685 warg.nosync = 0;
12686
12687 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12688}
12689
12690/*
12691 * call-seq:
12692 * IO.write(path, data, offset = 0, **opts) -> nonnegative_integer
12693 *
12694 * Opens the stream, writes the given +data+ to it,
12695 * and closes the stream; returns the number of bytes written.
12696 *
12697 * The first argument must be a string that is the path to a file.
12698 *
12699 * With only arguments +path+ and +data+ given,
12700 * writes the given data to the file at that path:
12701 *
12702 * path = 't.tmp'
12703 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n") # => 47
12704 * File.write(path, 'こんにちは') # => 15
12705 * File.write(path, "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94") # => 12
12706 *
12707 * When +offset+ is zero (the default), the entire file content is overwritten:
12708 *
12709 * File.read(path) # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12710 * File.write(path, 'foo')
12711 * File.read(path) # => "foo"
12712 *
12713 * When +offset+ in within the file content, the file content is partly overwritten,
12714 * beginning at byte +offset+:
12715 *
12716 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12717 * File.write(path, 'LINE', 6)
12718 * File.read(path) # => "First LINE\nSecond line\n\nFourth line\nFifth line\n"
12719 *
12720 * When the file contains multi-byte characters,
12721 * the effect of writing may disturb some characters:
12722 *
12723 * File.write(path, "こんにちは")
12724 * File.write(path, 'FOO', 3) # Replace one 3-byte character.
12725 * File.read(path) # => "こFOOにちは"
12726 * File.write(path, 'BAR', 7) # Replace bytes in two different 3-byte characters.
12727 * File.read(path) # => "こFOO\xE3BAR\x81\xA1は"
12728 *
12729 * If +offset+ is outside the file content,
12730 * the file is padded with null characters <tt>"\u0000"</tt>:
12731 *
12732 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12733 * File.write(path, 'FOO', 55)
12734 * File.read(path)
12735 * # => "First line\nSecond line\n\nFourth line\nFifth line\n\u0000\u0000\u0000FOO"
12736 *
12737 * Optional keyword arguments +opts+ specify:
12738 *
12739 * - {Open Options}[rdoc-ref:IO@Open+Options].
12740 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12741 *
12742 */
12743
12744static VALUE
12745rb_io_s_write(int argc, VALUE *argv, VALUE io)
12746{
12747 return io_s_write(argc, argv, io, 0);
12748}
12749
12750/*
12751 * call-seq:
12752 * IO.binwrite(path, string, offset = 0, **opts) -> integer
12753 *
12754 * Behaves like IO.write, except that the stream is opened in binary mode
12755 * with ASCII-8BIT encoding.
12756 *
12757 */
12758
12759static VALUE
12760rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12761{
12762 return io_s_write(argc, argv, io, 1);
12763}
12764
12766 VALUE src;
12767 VALUE dst;
12768 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12769 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12770
12771 rb_io_t *src_fptr;
12772 rb_io_t *dst_fptr;
12773 unsigned close_src : 1;
12774 unsigned close_dst : 1;
12775 int error_no;
12776 rb_off_t total;
12777 const char *syserr;
12778 const char *notimp;
12779 VALUE th;
12780 struct stat src_stat;
12781 struct stat dst_stat;
12782#ifdef HAVE_FCOPYFILE
12783 copyfile_state_t copyfile_state;
12784#endif
12785};
12786
12787static void *
12788exec_interrupts(void *arg)
12789{
12790 VALUE th = (VALUE)arg;
12791 rb_thread_execute_interrupts(th);
12792 return NULL;
12793}
12794
12795/*
12796 * returns TRUE if the preceding system call was interrupted
12797 * so we can continue. If the thread was interrupted, we
12798 * reacquire the GVL to execute interrupts before continuing.
12799 */
12800static int
12801maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12802{
12803 switch (errno) {
12804 case EINTR:
12805#if defined(ERESTART)
12806 case ERESTART:
12807#endif
12808 if (rb_thread_interrupted(stp->th)) {
12809 if (has_gvl)
12810 rb_thread_execute_interrupts(stp->th);
12811 else
12812 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12813 }
12814 return TRUE;
12815 }
12816 return FALSE;
12817}
12818
12820 VALUE scheduler;
12821
12822 rb_io_t *fptr;
12823 short events;
12824
12825 VALUE result;
12826};
12827
12828static void *
12829fiber_scheduler_wait_for(void * _arguments)
12830{
12831 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12832
12833 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12834
12835 return NULL;
12836}
12837
12838#if USE_POLL
12839# define IOWAIT_SYSCALL "poll"
12840STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12841STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12842static int
12843nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12844{
12846 if (scheduler != Qnil) {
12847 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12848 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12849 return RTEST(args.result);
12850 }
12851
12852 int fd = fptr->fd;
12853 if (fd == -1) return 0;
12854
12855 struct pollfd fds;
12856
12857 fds.fd = fd;
12858 fds.events = events;
12859
12860 int timeout_milliseconds = -1;
12861
12862 if (timeout) {
12863 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12864 }
12865
12866 return poll(&fds, 1, timeout_milliseconds);
12867}
12868#else /* !USE_POLL */
12869# define IOWAIT_SYSCALL "select"
12870static int
12871nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12872{
12874 if (scheduler != Qnil) {
12875 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12876 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12877 return RTEST(args.result);
12878 }
12879
12880 int fd = fptr->fd;
12881
12882 if (fd == -1) {
12883 errno = EBADF;
12884 return -1;
12885 }
12886
12887 rb_fdset_t fds;
12888 int ret;
12889
12890 rb_fd_init(&fds);
12891 rb_fd_set(fd, &fds);
12892
12893 switch (events) {
12894 case RB_WAITFD_IN:
12895 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12896 break;
12897 case RB_WAITFD_OUT:
12898 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12899 break;
12900 default:
12901 VM_UNREACHABLE(nogvl_wait_for);
12902 }
12903
12904 rb_fd_term(&fds);
12905
12906 // On timeout, this returns 0.
12907 return ret;
12908}
12909#endif /* !USE_POLL */
12910
12911static int
12912maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12913{
12914 int ret;
12915
12916 do {
12917 if (has_gvl) {
12919 }
12920 else {
12921 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12922 }
12923 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12924
12925 if (ret < 0) {
12926 stp->syserr = IOWAIT_SYSCALL;
12927 stp->error_no = errno;
12928 return ret;
12929 }
12930 return 0;
12931}
12932
12933static int
12934nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12935{
12936 int ret;
12937
12938 do {
12939 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12940 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12941
12942 if (ret < 0) {
12943 stp->syserr = IOWAIT_SYSCALL;
12944 stp->error_no = errno;
12945 return ret;
12946 }
12947 return 0;
12948}
12949
12950#ifdef USE_COPY_FILE_RANGE
12951
12952static ssize_t
12953simple_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)
12954{
12955#ifdef HAVE_COPY_FILE_RANGE
12956 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12957#else
12958 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12959#endif
12960}
12961
12962static int
12963nogvl_copy_file_range(struct copy_stream_struct *stp)
12964{
12965 ssize_t ss;
12966 rb_off_t src_size;
12967 rb_off_t copy_length, src_offset, *src_offset_ptr;
12968
12969 if (!S_ISREG(stp->src_stat.st_mode))
12970 return 0;
12971
12972 src_size = stp->src_stat.st_size;
12973 src_offset = stp->src_offset;
12974 if (src_offset >= (rb_off_t)0) {
12975 src_offset_ptr = &src_offset;
12976 }
12977 else {
12978 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12979 }
12980
12981 copy_length = stp->copy_length;
12982 if (copy_length < (rb_off_t)0) {
12983 if (src_offset < (rb_off_t)0) {
12984 rb_off_t current_offset;
12985 errno = 0;
12986 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12987 if (current_offset < (rb_off_t)0 && errno) {
12988 stp->syserr = "lseek";
12989 stp->error_no = errno;
12990 return (int)current_offset;
12991 }
12992 copy_length = src_size - current_offset;
12993 }
12994 else {
12995 copy_length = src_size - src_offset;
12996 }
12997 }
12998
12999 retry_copy_file_range:
13000# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13001 /* we are limited by the 32-bit ssize_t return value on 32-bit */
13002 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13003# else
13004 ss = (ssize_t)copy_length;
13005# endif
13006 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
13007 if (0 < ss) {
13008 stp->total += ss;
13009 copy_length -= ss;
13010 if (0 < copy_length) {
13011 goto retry_copy_file_range;
13012 }
13013 }
13014 if (ss < 0) {
13015 if (maygvl_copy_stream_continue_p(0, stp)) {
13016 goto retry_copy_file_range;
13017 }
13018 switch (errno) {
13019 case EINVAL:
13020 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
13021 docker container) */
13022#ifdef ENOSYS
13023 case ENOSYS:
13024#endif
13025#ifdef EXDEV
13026 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
13027#endif
13028 return 0;
13029 case EAGAIN:
13030#if EWOULDBLOCK != EAGAIN
13031 case EWOULDBLOCK:
13032#endif
13033 {
13034 int ret = nogvl_copy_stream_wait_write(stp);
13035 if (ret < 0) return ret;
13036 }
13037 goto retry_copy_file_range;
13038 case EBADF:
13039 {
13040 int e = errno;
13041 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
13042
13043 if (flags != -1 && flags & O_APPEND) {
13044 return 0;
13045 }
13046 errno = e;
13047 }
13048 }
13049 stp->syserr = "copy_file_range";
13050 stp->error_no = errno;
13051 return (int)ss;
13052 }
13053 return 1;
13054}
13055#endif
13056
13057#ifdef HAVE_FCOPYFILE
13058static int
13059nogvl_fcopyfile(struct copy_stream_struct *stp)
13060{
13061 rb_off_t cur, ss = 0;
13062 const rb_off_t src_offset = stp->src_offset;
13063 int ret;
13064
13065 if (stp->copy_length >= (rb_off_t)0) {
13066 /* copy_length can't be specified in fcopyfile(3) */
13067 return 0;
13068 }
13069
13070 if (!S_ISREG(stp->src_stat.st_mode))
13071 return 0;
13072
13073 if (!S_ISREG(stp->dst_stat.st_mode))
13074 return 0;
13075 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
13076 return 0;
13077 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
13078 /* fcopyfile(3) appends src IO to dst IO and then truncates
13079 * dst IO to src IO's original size. */
13080 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
13081 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
13082 if (end > (rb_off_t)0) return 0;
13083 }
13084
13085 if (src_offset > (rb_off_t)0) {
13086 rb_off_t r;
13087
13088 /* get current offset */
13089 errno = 0;
13090 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13091 if (cur < (rb_off_t)0 && errno) {
13092 stp->error_no = errno;
13093 return 1;
13094 }
13095
13096 errno = 0;
13097 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13098 if (r < (rb_off_t)0 && errno) {
13099 stp->error_no = errno;
13100 return 1;
13101 }
13102 }
13103
13104 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
13105 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
13106 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
13107
13108 if (ret == 0) { /* success */
13109 stp->total = ss;
13110 if (src_offset > (rb_off_t)0) {
13111 rb_off_t r;
13112 errno = 0;
13113 /* reset offset */
13114 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
13115 if (r < (rb_off_t)0 && errno) {
13116 stp->error_no = errno;
13117 return 1;
13118 }
13119 }
13120 }
13121 else {
13122 switch (errno) {
13123 case ENOTSUP:
13124 case EPERM:
13125 case EINVAL:
13126 return 0;
13127 }
13128 stp->syserr = "fcopyfile";
13129 stp->error_no = errno;
13130 return (int)ret;
13131 }
13132 return 1;
13133}
13134#endif
13135
13136#ifdef HAVE_SENDFILE
13137
13138# ifdef __linux__
13139# define USE_SENDFILE
13140
13141# ifdef HAVE_SYS_SENDFILE_H
13142# include <sys/sendfile.h>
13143# endif
13144
13145static ssize_t
13146simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13147{
13148 return sendfile(out_fd, in_fd, offset, (size_t)count);
13149}
13150
13151# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
13152/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
13153 * without cpuset -l 0.
13154 */
13155# define USE_SENDFILE
13156
13157static ssize_t
13158simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13159{
13160 int r;
13161 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
13162 rb_off_t sbytes;
13163# ifdef __APPLE__
13164 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
13165 sbytes = count;
13166# else
13167 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
13168# endif
13169 if (r != 0 && sbytes == 0) return r;
13170 if (offset) {
13171 *offset += sbytes;
13172 }
13173 else {
13174 lseek(in_fd, sbytes, SEEK_CUR);
13175 }
13176 return (ssize_t)sbytes;
13177}
13178
13179# endif
13180
13181#endif
13182
13183#ifdef USE_SENDFILE
13184static int
13185nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
13186{
13187 ssize_t ss;
13188 rb_off_t src_size;
13189 rb_off_t copy_length;
13190 rb_off_t src_offset;
13191 int use_pread;
13192
13193 if (!S_ISREG(stp->src_stat.st_mode))
13194 return 0;
13195
13196 src_size = stp->src_stat.st_size;
13197#ifndef __linux__
13198 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
13199 return 0;
13200#endif
13201
13202 src_offset = stp->src_offset;
13203 use_pread = src_offset >= (rb_off_t)0;
13204
13205 copy_length = stp->copy_length;
13206 if (copy_length < (rb_off_t)0) {
13207 if (use_pread)
13208 copy_length = src_size - src_offset;
13209 else {
13210 rb_off_t cur;
13211 errno = 0;
13212 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13213 if (cur < (rb_off_t)0 && errno) {
13214 stp->syserr = "lseek";
13215 stp->error_no = errno;
13216 return (int)cur;
13217 }
13218 copy_length = src_size - cur;
13219 }
13220 }
13221
13222 retry_sendfile:
13223# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13224 /* we are limited by the 32-bit ssize_t return value on 32-bit */
13225 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13226# else
13227 ss = (ssize_t)copy_length;
13228# endif
13229 if (use_pread) {
13230 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
13231 }
13232 else {
13233 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
13234 }
13235 if (0 < ss) {
13236 stp->total += ss;
13237 copy_length -= ss;
13238 if (0 < copy_length) {
13239 goto retry_sendfile;
13240 }
13241 }
13242 if (ss < 0) {
13243 if (maygvl_copy_stream_continue_p(0, stp))
13244 goto retry_sendfile;
13245 switch (errno) {
13246 case EINVAL:
13247#ifdef ENOSYS
13248 case ENOSYS:
13249#endif
13250#ifdef EOPNOTSUP
13251 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
13252 see also: [Feature #16965] */
13253 case EOPNOTSUP:
13254#endif
13255 return 0;
13256 case EAGAIN:
13257#if EWOULDBLOCK != EAGAIN
13258 case EWOULDBLOCK:
13259#endif
13260 {
13261 int ret;
13262#ifndef __linux__
13263 /*
13264 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
13265 * select() reports regular files to always be "ready", so
13266 * there is no need to select() on it.
13267 * Other OSes may have the same limitation for sendfile() which
13268 * allow us to bypass maygvl_copy_stream_wait_read()...
13269 */
13270 ret = maygvl_copy_stream_wait_read(0, stp);
13271 if (ret < 0) return ret;
13272#endif
13273 ret = nogvl_copy_stream_wait_write(stp);
13274 if (ret < 0) return ret;
13275 }
13276 goto retry_sendfile;
13277 }
13278 stp->syserr = "sendfile";
13279 stp->error_no = errno;
13280 return (int)ss;
13281 }
13282 return 1;
13283}
13284#endif
13285
13286static ssize_t
13287maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13288{
13289 if (has_gvl)
13290 return rb_io_read_memory(fptr, buf, count);
13291 else
13292 return read(fptr->fd, buf, count);
13293}
13294
13295static ssize_t
13296maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13297{
13298 ssize_t ss;
13299 retry_read:
13300 if (offset < (rb_off_t)0) {
13301 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13302 }
13303 else {
13304 ss = pread(stp->src_fptr->fd, buf, len, offset);
13305 }
13306 if (ss == 0) {
13307 return 0;
13308 }
13309 if (ss < 0) {
13310 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13311 goto retry_read;
13312 switch (errno) {
13313 case EAGAIN:
13314#if EWOULDBLOCK != EAGAIN
13315 case EWOULDBLOCK:
13316#endif
13317 {
13318 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13319 if (ret < 0) return ret;
13320 }
13321 goto retry_read;
13322#ifdef ENOSYS
13323 case ENOSYS:
13324 stp->notimp = "pread";
13325 return ss;
13326#endif
13327 }
13328 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13329 stp->error_no = errno;
13330 }
13331 return ss;
13332}
13333
13334static int
13335nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13336{
13337 ssize_t ss;
13338 int off = 0;
13339 while (len) {
13340 ss = write(stp->dst_fptr->fd, buf+off, len);
13341 if (ss < 0) {
13342 if (maygvl_copy_stream_continue_p(0, stp))
13343 continue;
13344 if (io_again_p(errno)) {
13345 int ret = nogvl_copy_stream_wait_write(stp);
13346 if (ret < 0) return ret;
13347 continue;
13348 }
13349 stp->syserr = "write";
13350 stp->error_no = errno;
13351 return (int)ss;
13352 }
13353 off += (int)ss;
13354 len -= (int)ss;
13355 stp->total += ss;
13356 }
13357 return 0;
13358}
13359
13360static void
13361nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13362{
13363 char buf[1024*16];
13364 size_t len;
13365 ssize_t ss;
13366 int ret;
13367 rb_off_t copy_length;
13368 rb_off_t src_offset;
13369 int use_eof;
13370 int use_pread;
13371
13372 copy_length = stp->copy_length;
13373 use_eof = copy_length < (rb_off_t)0;
13374 src_offset = stp->src_offset;
13375 use_pread = src_offset >= (rb_off_t)0;
13376
13377 if (use_pread && stp->close_src) {
13378 rb_off_t r;
13379 errno = 0;
13380 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13381 if (r < (rb_off_t)0 && errno) {
13382 stp->syserr = "lseek";
13383 stp->error_no = errno;
13384 return;
13385 }
13386 src_offset = (rb_off_t)-1;
13387 use_pread = 0;
13388 }
13389
13390 while (use_eof || 0 < copy_length) {
13391 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13392 len = (size_t)copy_length;
13393 }
13394 else {
13395 len = sizeof(buf);
13396 }
13397 if (use_pread) {
13398 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13399 if (0 < ss)
13400 src_offset += ss;
13401 }
13402 else {
13403 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13404 }
13405 if (ss <= 0) /* EOF or error */
13406 return;
13407
13408 ret = nogvl_copy_stream_write(stp, buf, ss);
13409 if (ret < 0)
13410 return;
13411
13412 if (!use_eof)
13413 copy_length -= ss;
13414 }
13415}
13416
13417static void *
13418nogvl_copy_stream_func(void *arg)
13419{
13420 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13421#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13422 int ret;
13423#endif
13424
13425#ifdef USE_COPY_FILE_RANGE
13426 ret = nogvl_copy_file_range(stp);
13427 if (ret != 0)
13428 goto finish; /* error or success */
13429#endif
13430
13431#ifdef HAVE_FCOPYFILE
13432 ret = nogvl_fcopyfile(stp);
13433 if (ret != 0)
13434 goto finish; /* error or success */
13435#endif
13436
13437#ifdef USE_SENDFILE
13438 ret = nogvl_copy_stream_sendfile(stp);
13439 if (ret != 0)
13440 goto finish; /* error or success */
13441#endif
13442
13443 nogvl_copy_stream_read_write(stp);
13444
13445#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13446 finish:
13447#endif
13448 return 0;
13449}
13450
13451static VALUE
13452copy_stream_fallback_body(VALUE arg)
13453{
13454 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13455 const int buflen = 16*1024;
13456 VALUE n;
13457 VALUE buf = rb_str_buf_new(buflen);
13458 rb_off_t rest = stp->copy_length;
13459 rb_off_t off = stp->src_offset;
13460 ID read_method = id_readpartial;
13461
13462 if (!stp->src_fptr) {
13463 if (!rb_respond_to(stp->src, read_method)) {
13464 read_method = id_read;
13465 }
13466 }
13467
13468 while (1) {
13469 long numwrote;
13470 long l;
13471 rb_str_make_independent(buf);
13472 if (stp->copy_length < (rb_off_t)0) {
13473 l = buflen;
13474 }
13475 else {
13476 if (rest == 0) {
13477 rb_str_resize(buf, 0);
13478 break;
13479 }
13480 l = buflen < rest ? buflen : (long)rest;
13481 }
13482 if (!stp->src_fptr) {
13483 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13484
13485 if (read_method == id_read && NIL_P(rc))
13486 break;
13487 }
13488 else {
13489 ssize_t ss;
13490 rb_str_resize(buf, buflen);
13491 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13492 rb_str_resize(buf, ss > 0 ? ss : 0);
13493 if (ss < 0)
13494 return Qnil;
13495 if (ss == 0)
13496 rb_eof_error();
13497 if (off >= (rb_off_t)0)
13498 off += ss;
13499 }
13500 n = rb_io_write(stp->dst, buf);
13501 numwrote = NUM2LONG(n);
13502 stp->total += numwrote;
13503 rest -= numwrote;
13504 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13505 break;
13506 }
13507 }
13508
13509 return Qnil;
13510}
13511
13512static VALUE
13513copy_stream_fallback(struct copy_stream_struct *stp)
13514{
13515 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13516 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13517 }
13518 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13519 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13520 rb_eEOFError, (VALUE)0);
13521 return Qnil;
13522}
13523
13524static VALUE
13525copy_stream_body(VALUE arg)
13526{
13527 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13528 VALUE src_io = stp->src, dst_io = stp->dst;
13529 const int common_oflags = 0
13530#ifdef O_NOCTTY
13531 | O_NOCTTY
13532#endif
13533 ;
13534
13535 stp->th = rb_thread_current();
13536
13537 stp->total = 0;
13538
13539 if (src_io == argf ||
13540 !(RB_TYPE_P(src_io, T_FILE) ||
13541 RB_TYPE_P(src_io, T_STRING) ||
13542 rb_respond_to(src_io, rb_intern("to_path")))) {
13543 stp->src_fptr = NULL;
13544 }
13545 else {
13546 int stat_ret;
13547 VALUE tmp_io = rb_io_check_io(src_io);
13548 if (!NIL_P(tmp_io)) {
13549 src_io = tmp_io;
13550 }
13551 else if (!RB_TYPE_P(src_io, T_FILE)) {
13552 VALUE args[2];
13553 FilePathValue(src_io);
13554 args[0] = src_io;
13555 args[1] = INT2NUM(O_RDONLY|common_oflags);
13556 src_io = rb_class_new_instance(2, args, rb_cFile);
13557 stp->src = src_io;
13558 stp->close_src = 1;
13559 }
13560 RB_IO_POINTER(src_io, stp->src_fptr);
13561 rb_io_check_byte_readable(stp->src_fptr);
13562
13563 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13564 if (stat_ret < 0) {
13565 stp->syserr = "fstat";
13566 stp->error_no = errno;
13567 return Qnil;
13568 }
13569 }
13570
13571 if (dst_io == argf ||
13572 !(RB_TYPE_P(dst_io, T_FILE) ||
13573 RB_TYPE_P(dst_io, T_STRING) ||
13574 rb_respond_to(dst_io, rb_intern("to_path")))) {
13575 stp->dst_fptr = NULL;
13576 }
13577 else {
13578 int stat_ret;
13579 VALUE tmp_io = rb_io_check_io(dst_io);
13580 if (!NIL_P(tmp_io)) {
13581 dst_io = GetWriteIO(tmp_io);
13582 }
13583 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13584 VALUE args[3];
13585 FilePathValue(dst_io);
13586 args[0] = dst_io;
13587 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13588 args[2] = INT2FIX(0666);
13589 dst_io = rb_class_new_instance(3, args, rb_cFile);
13590 stp->dst = dst_io;
13591 stp->close_dst = 1;
13592 }
13593 else {
13594 dst_io = GetWriteIO(dst_io);
13595 stp->dst = dst_io;
13596 }
13597 RB_IO_POINTER(dst_io, stp->dst_fptr);
13598 rb_io_check_writable(stp->dst_fptr);
13599
13600 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13601 if (stat_ret < 0) {
13602 stp->syserr = "fstat";
13603 stp->error_no = errno;
13604 return Qnil;
13605 }
13606 }
13607
13608#ifdef O_BINARY
13609 if (stp->src_fptr)
13610 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13611#endif
13612 if (stp->dst_fptr)
13613 io_ascii8bit_binmode(stp->dst_fptr);
13614
13615 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13616 size_t len = stp->src_fptr->rbuf.len;
13617 VALUE str;
13618 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13619 len = (size_t)stp->copy_length;
13620 }
13621 str = rb_str_buf_new(len);
13622 rb_str_resize(str,len);
13623 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13624 if (stp->dst_fptr) { /* IO or filename */
13625 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13626 rb_sys_fail_on_write(stp->dst_fptr);
13627 }
13628 else /* others such as StringIO */
13629 rb_io_write(dst_io, str);
13630 rb_str_resize(str, 0);
13631 stp->total += len;
13632 if (stp->copy_length >= (rb_off_t)0)
13633 stp->copy_length -= len;
13634 }
13635
13636 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13637 rb_raise(rb_eIOError, "flush failed");
13638 }
13639
13640 if (stp->copy_length == 0)
13641 return Qnil;
13642
13643 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13644 return copy_stream_fallback(stp);
13645 }
13646
13647 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13648 return Qnil;
13649}
13650
13651static VALUE
13652copy_stream_finalize(VALUE arg)
13653{
13654 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13655
13656#ifdef HAVE_FCOPYFILE
13657 if (stp->copyfile_state) {
13658 copyfile_state_free(stp->copyfile_state);
13659 }
13660#endif
13661
13662 if (stp->close_src) {
13663 rb_io_close_m(stp->src);
13664 }
13665 if (stp->close_dst) {
13666 rb_io_close_m(stp->dst);
13667 }
13668 if (stp->syserr) {
13669 rb_syserr_fail(stp->error_no, stp->syserr);
13670 }
13671 if (stp->notimp) {
13672 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13673 }
13674 return Qnil;
13675}
13676
13677/*
13678 * call-seq:
13679 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13680 *
13681 * Copies from the given +src+ to the given +dst+,
13682 * returning the number of bytes copied.
13683 *
13684 * - The given +src+ must be one of the following:
13685 *
13686 * - The path to a readable file, from which source data is to be read.
13687 * - An \IO-like object, opened for reading and capable of responding
13688 * to method +:readpartial+ or method +:read+.
13689 *
13690 * - The given +dst+ must be one of the following:
13691 *
13692 * - The path to a writable file, to which data is to be written.
13693 * - An \IO-like object, opened for writing and capable of responding
13694 * to method +:write+.
13695 *
13696 * The examples here use file <tt>t.txt</tt> as source:
13697 *
13698 * File.read('t.txt')
13699 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13700 * File.read('t.txt').size # => 47
13701 *
13702 * If only arguments +src+ and +dst+ are given,
13703 * the entire source stream is copied:
13704 *
13705 * # Paths.
13706 * IO.copy_stream('t.txt', 't.tmp') # => 47
13707 *
13708 * # IOs (recall that a File is also an IO).
13709 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13710 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13711 * IO.copy_stream(src_io, dst_io) # => 47
13712 * src_io.close
13713 * dst_io.close
13714 *
13715 * With argument +src_length+ a non-negative integer,
13716 * no more than that many bytes are copied:
13717 *
13718 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13719 * File.read('t.tmp') # => "First line"
13720 *
13721 * With argument +src_offset+ also given,
13722 * the source stream is read beginning at that offset:
13723 *
13724 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13725 * IO.read('t.tmp') # => "Second line"
13726 *
13727 */
13728static VALUE
13729rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13730{
13731 VALUE src, dst, length, src_offset;
13732 struct copy_stream_struct st;
13733
13734 MEMZERO(&st, struct copy_stream_struct, 1);
13735
13736 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13737
13738 st.src = src;
13739 st.dst = dst;
13740
13741 st.src_fptr = NULL;
13742 st.dst_fptr = NULL;
13743
13744 if (NIL_P(length))
13745 st.copy_length = (rb_off_t)-1;
13746 else
13747 st.copy_length = NUM2OFFT(length);
13748
13749 if (NIL_P(src_offset))
13750 st.src_offset = (rb_off_t)-1;
13751 else
13752 st.src_offset = NUM2OFFT(src_offset);
13753
13754 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13755
13756 return OFFT2NUM(st.total);
13757}
13758
13759/*
13760 * call-seq:
13761 * external_encoding -> encoding or nil
13762 *
13763 * Returns the Encoding object that represents the encoding of the stream,
13764 * or +nil+ if the stream is in write mode and no encoding is specified.
13765 *
13766 * See {Encodings}[rdoc-ref:File@Encodings].
13767 *
13768 */
13769
13770static VALUE
13771rb_io_external_encoding(VALUE io)
13772{
13773 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13774
13775 if (fptr->encs.enc2) {
13776 return rb_enc_from_encoding(fptr->encs.enc2);
13777 }
13778 if (fptr->mode & FMODE_WRITABLE) {
13779 if (fptr->encs.enc)
13780 return rb_enc_from_encoding(fptr->encs.enc);
13781 return Qnil;
13782 }
13783 return rb_enc_from_encoding(io_read_encoding(fptr));
13784}
13785
13786/*
13787 * call-seq:
13788 * internal_encoding -> encoding or nil
13789 *
13790 * Returns the Encoding object that represents the encoding of the internal string,
13791 * if conversion is specified,
13792 * or +nil+ otherwise.
13793 *
13794 * See {Encodings}[rdoc-ref:File@Encodings].
13795 *
13796 */
13797
13798static VALUE
13799rb_io_internal_encoding(VALUE io)
13800{
13801 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13802
13803 if (!fptr->encs.enc2) return Qnil;
13804 return rb_enc_from_encoding(io_read_encoding(fptr));
13805}
13806
13807/*
13808 * call-seq:
13809 * set_encoding(ext_enc) -> self
13810 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13811 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13812 *
13813 * See {Encodings}[rdoc-ref:File@Encodings].
13814 *
13815 * Argument +ext_enc+, if given, must be an Encoding object
13816 * or a String with the encoding name;
13817 * it is assigned as the encoding for the stream.
13818 *
13819 * Argument +int_enc+, if given, must be an Encoding object
13820 * or a String with the encoding name;
13821 * it is assigned as the encoding for the internal string.
13822 *
13823 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13824 * containing two colon-separated encoding names;
13825 * corresponding Encoding objects are assigned as the external
13826 * and internal encodings for the stream.
13827 *
13828 * If the external encoding of a string is binary/ASCII-8BIT,
13829 * the internal encoding of the string is set to nil, since no
13830 * transcoding is needed.
13831 *
13832 * Optional keyword arguments +enc_opts+ specify
13833 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13834 *
13835 */
13836
13837static VALUE
13838rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13839{
13840 rb_io_t *fptr;
13841 VALUE v1, v2, opt;
13842
13843 if (!RB_TYPE_P(io, T_FILE)) {
13844 return forward(io, id_set_encoding, argc, argv);
13845 }
13846
13847 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13848 GetOpenFile(io, fptr);
13849 io_encoding_set(fptr, v1, v2, opt);
13850 return io;
13851}
13852
13853void
13854rb_stdio_set_default_encoding(void)
13855{
13856 VALUE val = Qnil;
13857
13858#ifdef _WIN32
13859 if (isatty(fileno(stdin))) {
13860 rb_encoding *external = rb_locale_encoding();
13861 rb_encoding *internal = rb_default_internal_encoding();
13862 if (!internal) internal = rb_default_external_encoding();
13863 io_encoding_set(RFILE(rb_stdin)->fptr,
13864 rb_enc_from_encoding(external),
13865 rb_enc_from_encoding(internal),
13866 Qnil);
13867 }
13868 else
13869#endif
13870 rb_io_set_encoding(1, &val, rb_stdin);
13871 rb_io_set_encoding(1, &val, rb_stdout);
13872 rb_io_set_encoding(1, &val, rb_stderr);
13873}
13874
13875static inline int
13876global_argf_p(VALUE arg)
13877{
13878 return arg == argf;
13879}
13880
13881typedef VALUE (*argf_encoding_func)(VALUE io);
13882
13883static VALUE
13884argf_encoding(VALUE argf, argf_encoding_func func)
13885{
13886 if (!RTEST(ARGF.current_file)) {
13887 return rb_enc_default_external();
13888 }
13889 return func(rb_io_check_io(ARGF.current_file));
13890}
13891
13892/*
13893 * call-seq:
13894 * ARGF.external_encoding -> encoding
13895 *
13896 * Returns the external encoding for files read from ARGF as an Encoding
13897 * object. The external encoding is the encoding of the text as stored in a
13898 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13899 * represent this text within Ruby.
13900 *
13901 * To set the external encoding use ARGF.set_encoding.
13902 *
13903 * For example:
13904 *
13905 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13906 *
13907 */
13908static VALUE
13909argf_external_encoding(VALUE argf)
13910{
13911 return argf_encoding(argf, rb_io_external_encoding);
13912}
13913
13914/*
13915 * call-seq:
13916 * ARGF.internal_encoding -> encoding
13917 *
13918 * Returns the internal encoding for strings read from ARGF as an
13919 * Encoding object.
13920 *
13921 * If ARGF.set_encoding has been called with two encoding names, the second
13922 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13923 * value is returned. Failing that, if a default external encoding was
13924 * specified on the command-line, that value is used. If the encoding is
13925 * unknown, +nil+ is returned.
13926 */
13927static VALUE
13928argf_internal_encoding(VALUE argf)
13929{
13930 return argf_encoding(argf, rb_io_internal_encoding);
13931}
13932
13933/*
13934 * call-seq:
13935 * ARGF.set_encoding(ext_enc) -> ARGF
13936 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13937 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13938 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13939 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13940 *
13941 * If single argument is specified, strings read from ARGF are tagged with
13942 * the encoding specified.
13943 *
13944 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13945 * the read string is converted from the first encoding (external encoding)
13946 * to the second encoding (internal encoding), then tagged with the second
13947 * encoding.
13948 *
13949 * If two arguments are specified, they must be encoding objects or encoding
13950 * names. Again, the first specifies the external encoding; the second
13951 * specifies the internal encoding.
13952 *
13953 * If the external encoding and the internal encoding are specified, the
13954 * optional Hash argument can be used to adjust the conversion process. The
13955 * structure of this hash is explained in the String#encode documentation.
13956 *
13957 * For example:
13958 *
13959 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13960 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13961 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13962 * # to UTF-8.
13963 */
13964static VALUE
13965argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13966{
13967 rb_io_t *fptr;
13968
13969 if (!next_argv()) {
13970 rb_raise(rb_eArgError, "no stream to set encoding");
13971 }
13972 rb_io_set_encoding(argc, argv, ARGF.current_file);
13973 GetOpenFile(ARGF.current_file, fptr);
13974 ARGF.encs = fptr->encs;
13975 RB_OBJ_WRITTEN(argf, Qundef, ARGF.encs.ecopts);
13976 return argf;
13977}
13978
13979/*
13980 * call-seq:
13981 * ARGF.tell -> Integer
13982 * ARGF.pos -> Integer
13983 *
13984 * Returns the current offset (in bytes) of the current file in ARGF.
13985 *
13986 * ARGF.pos #=> 0
13987 * ARGF.gets #=> "This is line one\n"
13988 * ARGF.pos #=> 17
13989 *
13990 */
13991static VALUE
13992argf_tell(VALUE argf)
13993{
13994 if (!next_argv()) {
13995 rb_raise(rb_eArgError, "no stream to tell");
13996 }
13997 ARGF_FORWARD(0, 0);
13998 return rb_io_tell(ARGF.current_file);
13999}
14000
14001/*
14002 * call-seq:
14003 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
14004 *
14005 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
14006 * the value of _whence_. See IO#seek for further details.
14007 */
14008static VALUE
14009argf_seek_m(int argc, VALUE *argv, VALUE argf)
14010{
14011 if (!next_argv()) {
14012 rb_raise(rb_eArgError, "no stream to seek");
14013 }
14014 ARGF_FORWARD(argc, argv);
14015 return rb_io_seek_m(argc, argv, ARGF.current_file);
14016}
14017
14018/*
14019 * call-seq:
14020 * ARGF.pos = position -> Integer
14021 *
14022 * Seeks to the position given by _position_ (in bytes) in ARGF.
14023 *
14024 * For example:
14025 *
14026 * ARGF.pos = 17
14027 * ARGF.gets #=> "This is line two\n"
14028 */
14029static VALUE
14030argf_set_pos(VALUE argf, VALUE offset)
14031{
14032 if (!next_argv()) {
14033 rb_raise(rb_eArgError, "no stream to set position");
14034 }
14035 ARGF_FORWARD(1, &offset);
14036 return rb_io_set_pos(ARGF.current_file, offset);
14037}
14038
14039/*
14040 * call-seq:
14041 * ARGF.rewind -> 0
14042 *
14043 * Positions the current file to the beginning of input, resetting
14044 * ARGF.lineno to zero.
14045 *
14046 * ARGF.readline #=> "This is line one\n"
14047 * ARGF.rewind #=> 0
14048 * ARGF.lineno #=> 0
14049 * ARGF.readline #=> "This is line one\n"
14050 */
14051static VALUE
14052argf_rewind(VALUE argf)
14053{
14054 VALUE ret;
14055 int old_lineno;
14056
14057 if (!next_argv()) {
14058 rb_raise(rb_eArgError, "no stream to rewind");
14059 }
14060 ARGF_FORWARD(0, 0);
14061 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
14062 ret = rb_io_rewind(ARGF.current_file);
14063 if (!global_argf_p(argf)) {
14064 ARGF.last_lineno = ARGF.lineno -= old_lineno;
14065 }
14066 return ret;
14067}
14068
14069/*
14070 * call-seq:
14071 * ARGF.fileno -> integer
14072 * ARGF.to_i -> integer
14073 *
14074 * Returns an integer representing the numeric file descriptor for
14075 * the current file. Raises an ArgumentError if there isn't a current file.
14076 *
14077 * ARGF.fileno #=> 3
14078 */
14079static VALUE
14080argf_fileno(VALUE argf)
14081{
14082 if (!next_argv()) {
14083 rb_raise(rb_eArgError, "no stream");
14084 }
14085 ARGF_FORWARD(0, 0);
14086 return rb_io_fileno(ARGF.current_file);
14087}
14088
14089/*
14090 * call-seq:
14091 * ARGF.to_io -> IO
14092 *
14093 * Returns an IO object representing the current file. This will be a
14094 * File object unless the current file is a stream such as STDIN.
14095 *
14096 * For example:
14097 *
14098 * ARGF.to_io #=> #<File:glark.txt>
14099 * ARGF.to_io #=> #<IO:<STDIN>>
14100 */
14101static VALUE
14102argf_to_io(VALUE argf)
14103{
14104 next_argv();
14105 ARGF_FORWARD(0, 0);
14106 return ARGF.current_file;
14107}
14108
14109/*
14110 * call-seq:
14111 * ARGF.eof? -> true or false
14112 * ARGF.eof -> true or false
14113 *
14114 * Returns true if the current file in ARGF is at end of file, i.e. it has
14115 * no data to read. The stream must be opened for reading or an IOError
14116 * will be raised.
14117 *
14118 * $ echo "eof" | ruby argf.rb
14119 *
14120 * ARGF.eof? #=> false
14121 * 3.times { ARGF.readchar }
14122 * ARGF.eof? #=> false
14123 * ARGF.readchar #=> "\n"
14124 * ARGF.eof? #=> true
14125 */
14126
14127static VALUE
14128argf_eof(VALUE argf)
14129{
14130 next_argv();
14131 if (RTEST(ARGF.current_file)) {
14132 if (ARGF.init_p == 0) return Qtrue;
14133 next_argv();
14134 ARGF_FORWARD(0, 0);
14135 if (rb_io_eof(ARGF.current_file)) {
14136 return Qtrue;
14137 }
14138 }
14139 return Qfalse;
14140}
14141
14142/*
14143 * call-seq:
14144 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
14145 *
14146 * Reads _length_ bytes from ARGF. The files named on the command line
14147 * are concatenated and treated as a single file by this method, so when
14148 * called without arguments the contents of this pseudo file are returned in
14149 * their entirety.
14150 *
14151 * _length_ must be a non-negative integer or +nil+.
14152 *
14153 * If _length_ is a positive integer, +read+ tries to read
14154 * _length_ bytes without any conversion (binary mode).
14155 * It returns +nil+ if an EOF is encountered before anything can be read.
14156 * Fewer than _length_ bytes are returned if an EOF is encountered during
14157 * the read.
14158 * In the case of an integer _length_, the resulting string is always
14159 * in ASCII-8BIT encoding.
14160 *
14161 * If _length_ is omitted or is +nil+, it reads until EOF
14162 * and the encoding conversion is applied, if applicable.
14163 * A string is returned even if EOF is encountered before any data is read.
14164 *
14165 * If _length_ is zero, it returns an empty string (<code>""</code>).
14166 *
14167 * If the optional _outbuf_ argument is present,
14168 * it must reference a String, which will receive the data.
14169 * The _outbuf_ will contain only the received data after the method call
14170 * even if it is not empty at the beginning.
14171 *
14172 * For example:
14173 *
14174 * $ echo "small" > small.txt
14175 * $ echo "large" > large.txt
14176 * $ ./glark.rb small.txt large.txt
14177 *
14178 * ARGF.read #=> "small\nlarge"
14179 * ARGF.read(200) #=> "small\nlarge"
14180 * ARGF.read(2) #=> "sm"
14181 * ARGF.read(0) #=> ""
14182 *
14183 * Note that this method behaves like the fread() function in C.
14184 * This means it retries to invoke read(2) system calls to read data
14185 * with the specified length.
14186 * If you need the behavior like a single read(2) system call,
14187 * consider ARGF#readpartial or ARGF#read_nonblock.
14188 */
14189
14190static VALUE
14191argf_read(int argc, VALUE *argv, VALUE argf)
14192{
14193 VALUE tmp, str, length;
14194 long len = 0;
14195
14196 rb_scan_args(argc, argv, "02", &length, &str);
14197 if (!NIL_P(length)) {
14198 len = NUM2LONG(argv[0]);
14199 }
14200 if (!NIL_P(str)) {
14201 StringValue(str);
14202 rb_str_resize(str,0);
14203 argv[1] = Qnil;
14204 }
14205
14206 retry:
14207 if (!next_argv()) {
14208 return str;
14209 }
14210 if (ARGF_GENERIC_INPUT_P()) {
14211 tmp = argf_forward(argc, argv, argf);
14212 }
14213 else {
14214 tmp = io_read(argc, argv, ARGF.current_file);
14215 }
14216 if (NIL_P(str)) str = tmp;
14217 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
14218 if (NIL_P(tmp) || NIL_P(length)) {
14219 if (ARGF.next_p != -1) {
14220 argf_close(argf);
14221 ARGF.next_p = 1;
14222 goto retry;
14223 }
14224 }
14225 else if (argc >= 1) {
14226 long slen = RSTRING_LEN(str);
14227 if (slen < len) {
14228 argv[0] = LONG2NUM(len - slen);
14229 goto retry;
14230 }
14231 }
14232 return str;
14233}
14234
14236 int argc;
14237 VALUE *argv;
14238 VALUE argf;
14239};
14240
14241static VALUE
14242argf_forward_call(VALUE arg)
14243{
14244 struct argf_call_arg *p = (struct argf_call_arg *)arg;
14245 argf_forward(p->argc, p->argv, p->argf);
14246 return Qnil;
14247}
14248
14249static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
14250 int nonblock);
14251
14252/*
14253 * call-seq:
14254 * ARGF.readpartial(maxlen) -> string
14255 * ARGF.readpartial(maxlen, outbuf) -> outbuf
14256 *
14257 * Reads at most _maxlen_ bytes from the ARGF stream.
14258 *
14259 * If the optional _outbuf_ argument is present,
14260 * it must reference a String, which will receive the data.
14261 * The _outbuf_ will contain only the received data after the method call
14262 * even if it is not empty at the beginning.
14263 *
14264 * It raises EOFError on end of ARGF stream.
14265 * Since ARGF stream is a concatenation of multiple files,
14266 * internally EOF is occur for each file.
14267 * ARGF.readpartial returns empty strings for EOFs except the last one and
14268 * raises EOFError for the last one.
14269 *
14270 */
14271
14272static VALUE
14273argf_readpartial(int argc, VALUE *argv, VALUE argf)
14274{
14275 return argf_getpartial(argc, argv, argf, Qnil, 0);
14276}
14277
14278/*
14279 * call-seq:
14280 * ARGF.read_nonblock(maxlen[, options]) -> string
14281 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14282 *
14283 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14284 */
14285
14286static VALUE
14287argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14288{
14289 VALUE opts;
14290
14291 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14292
14293 if (!NIL_P(opts))
14294 argc--;
14295
14296 return argf_getpartial(argc, argv, argf, opts, 1);
14297}
14298
14299static VALUE
14300argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14301{
14302 VALUE tmp, str, length;
14303 int no_exception;
14304
14305 rb_scan_args(argc, argv, "11", &length, &str);
14306 if (!NIL_P(str)) {
14307 StringValue(str);
14308 argv[1] = str;
14309 }
14310 no_exception = no_exception_p(opts);
14311
14312 if (!next_argv()) {
14313 if (!NIL_P(str)) {
14314 rb_str_resize(str, 0);
14315 }
14316 rb_eof_error();
14317 }
14318 if (ARGF_GENERIC_INPUT_P()) {
14319 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14320 struct argf_call_arg arg;
14321 arg.argc = argc;
14322 arg.argv = argv;
14323 arg.argf = argf;
14324 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14325 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14326 }
14327 else {
14328 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14329 }
14330 if (NIL_P(tmp)) {
14331 if (ARGF.next_p == -1) {
14332 return io_nonblock_eof(no_exception);
14333 }
14334 argf_close(argf);
14335 ARGF.next_p = 1;
14336 if (RARRAY_LEN(ARGF.argv) == 0) {
14337 return io_nonblock_eof(no_exception);
14338 }
14339 if (NIL_P(str))
14340 str = rb_str_new(NULL, 0);
14341 return str;
14342 }
14343 return tmp;
14344}
14345
14346/*
14347 * call-seq:
14348 * ARGF.getc -> String or nil
14349 *
14350 * Reads the next character from ARGF and returns it as a String. Returns
14351 * +nil+ at the end of the stream.
14352 *
14353 * ARGF treats the files named on the command line as a single file created
14354 * by concatenating their contents. After returning the last character of the
14355 * first file, it returns the first character of the second file, and so on.
14356 *
14357 * For example:
14358 *
14359 * $ echo "foo" > file
14360 * $ ruby argf.rb file
14361 *
14362 * ARGF.getc #=> "f"
14363 * ARGF.getc #=> "o"
14364 * ARGF.getc #=> "o"
14365 * ARGF.getc #=> "\n"
14366 * ARGF.getc #=> nil
14367 * ARGF.getc #=> nil
14368 */
14369static VALUE
14370argf_getc(VALUE argf)
14371{
14372 VALUE ch;
14373
14374 retry:
14375 if (!next_argv()) return Qnil;
14376 if (ARGF_GENERIC_INPUT_P()) {
14377 ch = forward_current(rb_intern("getc"), 0, 0);
14378 }
14379 else {
14380 ch = rb_io_getc(ARGF.current_file);
14381 }
14382 if (NIL_P(ch) && ARGF.next_p != -1) {
14383 argf_close(argf);
14384 ARGF.next_p = 1;
14385 goto retry;
14386 }
14387
14388 return ch;
14389}
14390
14391/*
14392 * call-seq:
14393 * ARGF.getbyte -> Integer or nil
14394 *
14395 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14396 * the end of the stream.
14397 *
14398 * For example:
14399 *
14400 * $ echo "foo" > file
14401 * $ ruby argf.rb file
14402 *
14403 * ARGF.getbyte #=> 102
14404 * ARGF.getbyte #=> 111
14405 * ARGF.getbyte #=> 111
14406 * ARGF.getbyte #=> 10
14407 * ARGF.getbyte #=> nil
14408 */
14409static VALUE
14410argf_getbyte(VALUE argf)
14411{
14412 VALUE ch;
14413
14414 retry:
14415 if (!next_argv()) return Qnil;
14416 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14417 ch = forward_current(rb_intern("getbyte"), 0, 0);
14418 }
14419 else {
14420 ch = rb_io_getbyte(ARGF.current_file);
14421 }
14422 if (NIL_P(ch) && ARGF.next_p != -1) {
14423 argf_close(argf);
14424 ARGF.next_p = 1;
14425 goto retry;
14426 }
14427
14428 return ch;
14429}
14430
14431/*
14432 * call-seq:
14433 * ARGF.readchar -> String or nil
14434 *
14435 * Reads the next character from ARGF and returns it as a String. Raises
14436 * an EOFError after the last character of the last file has been read.
14437 *
14438 * For example:
14439 *
14440 * $ echo "foo" > file
14441 * $ ruby argf.rb file
14442 *
14443 * ARGF.readchar #=> "f"
14444 * ARGF.readchar #=> "o"
14445 * ARGF.readchar #=> "o"
14446 * ARGF.readchar #=> "\n"
14447 * ARGF.readchar #=> end of file reached (EOFError)
14448 */
14449static VALUE
14450argf_readchar(VALUE argf)
14451{
14452 VALUE ch;
14453
14454 retry:
14455 if (!next_argv()) rb_eof_error();
14456 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14457 ch = forward_current(rb_intern("getc"), 0, 0);
14458 }
14459 else {
14460 ch = rb_io_getc(ARGF.current_file);
14461 }
14462 if (NIL_P(ch) && ARGF.next_p != -1) {
14463 argf_close(argf);
14464 ARGF.next_p = 1;
14465 goto retry;
14466 }
14467
14468 return ch;
14469}
14470
14471/*
14472 * call-seq:
14473 * ARGF.readbyte -> Integer
14474 *
14475 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14476 * an EOFError after the last byte of the last file has been read.
14477 *
14478 * For example:
14479 *
14480 * $ echo "foo" > file
14481 * $ ruby argf.rb file
14482 *
14483 * ARGF.readbyte #=> 102
14484 * ARGF.readbyte #=> 111
14485 * ARGF.readbyte #=> 111
14486 * ARGF.readbyte #=> 10
14487 * ARGF.readbyte #=> end of file reached (EOFError)
14488 */
14489static VALUE
14490argf_readbyte(VALUE argf)
14491{
14492 VALUE c;
14493
14494 NEXT_ARGF_FORWARD(0, 0);
14495 c = argf_getbyte(argf);
14496 if (NIL_P(c)) {
14497 rb_eof_error();
14498 }
14499 return c;
14500}
14501
14502#define FOREACH_ARGF() while (next_argv())
14503
14504static VALUE
14505argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14506{
14507 const VALUE current = ARGF.current_file;
14508 rb_yield_values2(argc, argv);
14509 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14511 }
14512 return Qnil;
14513}
14514
14515#define ARGF_block_call(mid, argc, argv, func, argf) \
14516 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14517 func, argf, rb_keyword_given_p())
14518
14519static void
14520argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14521{
14522 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14523 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14524}
14525
14526static VALUE
14527argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14528{
14529 if (!global_argf_p(argf)) {
14530 ARGF.last_lineno = ++ARGF.lineno;
14531 }
14532 return argf_block_call_i(i, argf, argc, argv, blockarg);
14533}
14534
14535static void
14536argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14537{
14538 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14539 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14540}
14541
14542/*
14543 * call-seq:
14544 * ARGF.each(sep=$/) {|line| block } -> ARGF
14545 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14546 * ARGF.each(...) -> an_enumerator
14547 *
14548 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14549 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14550 * ARGF.each_line(...) -> an_enumerator
14551 *
14552 * Returns an enumerator which iterates over each line (separated by _sep_,
14553 * which defaults to your platform's newline character) of each file in
14554 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14555 * block, otherwise an enumerator is returned.
14556 * The optional _limit_ argument is an Integer specifying the maximum
14557 * length of each line; longer lines will be split according to this limit.
14558 *
14559 * This method allows you to treat the files supplied on the command line as
14560 * a single file consisting of the concatenation of each named file. After
14561 * the last line of the first file has been returned, the first line of the
14562 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14563 * used to determine the filename of the current line and line number of the
14564 * whole input, respectively.
14565 *
14566 * For example, the following code prints out each line of each named file
14567 * prefixed with its line number, displaying the filename once per file:
14568 *
14569 * ARGF.each_line do |line|
14570 * puts ARGF.filename if ARGF.file.lineno == 1
14571 * puts "#{ARGF.file.lineno}: #{line}"
14572 * end
14573 *
14574 * While the following code prints only the first file's name at first, and
14575 * the contents with line number counted through all named files.
14576 *
14577 * ARGF.each_line do |line|
14578 * puts ARGF.filename if ARGF.lineno == 1
14579 * puts "#{ARGF.lineno}: #{line}"
14580 * end
14581 */
14582static VALUE
14583argf_each_line(int argc, VALUE *argv, VALUE argf)
14584{
14585 RETURN_ENUMERATOR(argf, argc, argv);
14586 FOREACH_ARGF() {
14587 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14588 }
14589 return argf;
14590}
14591
14592/*
14593 * call-seq:
14594 * ARGF.each_byte {|byte| block } -> ARGF
14595 * ARGF.each_byte -> an_enumerator
14596 *
14597 * Iterates over each byte of each file in +ARGV+.
14598 * A byte is returned as an Integer in the range 0..255.
14599 *
14600 * This method allows you to treat the files supplied on the command line as
14601 * a single file consisting of the concatenation of each named file. After
14602 * the last byte of the first file has been returned, the first byte of the
14603 * second file is returned. The ARGF.filename method can be used to
14604 * determine the filename of the current byte.
14605 *
14606 * If no block is given, an enumerator is returned instead.
14607 *
14608 * For example:
14609 *
14610 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14611 *
14612 */
14613static VALUE
14614argf_each_byte(VALUE argf)
14615{
14616 RETURN_ENUMERATOR(argf, 0, 0);
14617 FOREACH_ARGF() {
14618 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14619 }
14620 return argf;
14621}
14622
14623/*
14624 * call-seq:
14625 * ARGF.each_char {|char| block } -> ARGF
14626 * ARGF.each_char -> an_enumerator
14627 *
14628 * Iterates over each character of each file in ARGF.
14629 *
14630 * This method allows you to treat the files supplied on the command line as
14631 * a single file consisting of the concatenation of each named file. After
14632 * the last character of the first file has been returned, the first
14633 * character of the second file is returned. The ARGF.filename method can
14634 * be used to determine the name of the file in which the current character
14635 * appears.
14636 *
14637 * If no block is given, an enumerator is returned instead.
14638 */
14639static VALUE
14640argf_each_char(VALUE argf)
14641{
14642 RETURN_ENUMERATOR(argf, 0, 0);
14643 FOREACH_ARGF() {
14644 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14645 }
14646 return argf;
14647}
14648
14649/*
14650 * call-seq:
14651 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14652 * ARGF.each_codepoint -> an_enumerator
14653 *
14654 * Iterates over each codepoint of each file in ARGF.
14655 *
14656 * This method allows you to treat the files supplied on the command line as
14657 * a single file consisting of the concatenation of each named file. After
14658 * the last codepoint of the first file has been returned, the first
14659 * codepoint of the second file is returned. The ARGF.filename method can
14660 * be used to determine the name of the file in which the current codepoint
14661 * appears.
14662 *
14663 * If no block is given, an enumerator is returned instead.
14664 */
14665static VALUE
14666argf_each_codepoint(VALUE argf)
14667{
14668 RETURN_ENUMERATOR(argf, 0, 0);
14669 FOREACH_ARGF() {
14670 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14671 }
14672 return argf;
14673}
14674
14675/*
14676 * call-seq:
14677 * ARGF.filename -> String
14678 * ARGF.path -> String
14679 *
14680 * Returns the current filename. "-" is returned when the current file is
14681 * STDIN.
14682 *
14683 * For example:
14684 *
14685 * $ echo "foo" > foo
14686 * $ echo "bar" > bar
14687 * $ echo "glark" > glark
14688 *
14689 * $ ruby argf.rb foo bar glark
14690 *
14691 * ARGF.filename #=> "foo"
14692 * ARGF.read(5) #=> "foo\nb"
14693 * ARGF.filename #=> "bar"
14694 * ARGF.skip
14695 * ARGF.filename #=> "glark"
14696 */
14697static VALUE
14698argf_filename(VALUE argf)
14699{
14700 next_argv();
14701 return ARGF.filename;
14702}
14703
14704static VALUE
14705argf_filename_getter(ID id, VALUE *var)
14706{
14707 return argf_filename(*var);
14708}
14709
14710/*
14711 * call-seq:
14712 * ARGF.file -> IO or File object
14713 *
14714 * Returns the current file as an IO or File object.
14715 * <code>$stdin</code> is returned when the current file is STDIN.
14716 *
14717 * For example:
14718 *
14719 * $ echo "foo" > foo
14720 * $ echo "bar" > bar
14721 *
14722 * $ ruby argf.rb foo bar
14723 *
14724 * ARGF.file #=> #<File:foo>
14725 * ARGF.read(5) #=> "foo\nb"
14726 * ARGF.file #=> #<File:bar>
14727 */
14728static VALUE
14729argf_file(VALUE argf)
14730{
14731 next_argv();
14732 return ARGF.current_file;
14733}
14734
14735/*
14736 * call-seq:
14737 * ARGF.binmode -> ARGF
14738 *
14739 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14740 * be reset to non-binary mode. This option has the following effects:
14741 *
14742 * * Newline conversion is disabled.
14743 * * Encoding conversion is disabled.
14744 * * Content is treated as ASCII-8BIT.
14745 */
14746static VALUE
14747argf_binmode_m(VALUE argf)
14748{
14749 ARGF.binmode = 1;
14750 next_argv();
14751 ARGF_FORWARD(0, 0);
14752 rb_io_ascii8bit_binmode(ARGF.current_file);
14753 return argf;
14754}
14755
14756/*
14757 * call-seq:
14758 * ARGF.binmode? -> true or false
14759 *
14760 * Returns true if ARGF is being read in binary mode; false otherwise.
14761 * To enable binary mode use ARGF.binmode.
14762 *
14763 * For example:
14764 *
14765 * ARGF.binmode? #=> false
14766 * ARGF.binmode
14767 * ARGF.binmode? #=> true
14768 */
14769static VALUE
14770argf_binmode_p(VALUE argf)
14771{
14772 return RBOOL(ARGF.binmode);
14773}
14774
14775/*
14776 * call-seq:
14777 * ARGF.skip -> ARGF
14778 *
14779 * Sets the current file to the next file in ARGV. If there aren't any more
14780 * files it has no effect.
14781 *
14782 * For example:
14783 *
14784 * $ ruby argf.rb foo bar
14785 * ARGF.filename #=> "foo"
14786 * ARGF.skip
14787 * ARGF.filename #=> "bar"
14788 */
14789static VALUE
14790argf_skip(VALUE argf)
14791{
14792 if (ARGF.init_p && ARGF.next_p == 0) {
14793 argf_close(argf);
14794 ARGF.next_p = 1;
14795 }
14796 return argf;
14797}
14798
14799/*
14800 * call-seq:
14801 * ARGF.close -> ARGF
14802 *
14803 * Closes the current file and skips to the next file in ARGV. If there are
14804 * no more files to open, just closes the current file. STDIN will not be
14805 * closed.
14806 *
14807 * For example:
14808 *
14809 * $ ruby argf.rb foo bar
14810 *
14811 * ARGF.filename #=> "foo"
14812 * ARGF.close
14813 * ARGF.filename #=> "bar"
14814 * ARGF.close
14815 */
14816static VALUE
14817argf_close_m(VALUE argf)
14818{
14819 next_argv();
14820 argf_close(argf);
14821 if (ARGF.next_p != -1) {
14822 ARGF.next_p = 1;
14823 }
14824 ARGF.lineno = 0;
14825 return argf;
14826}
14827
14828/*
14829 * call-seq:
14830 * ARGF.closed? -> true or false
14831 *
14832 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14833 * ARGF.close to actually close the current file.
14834 */
14835static VALUE
14836argf_closed(VALUE argf)
14837{
14838 next_argv();
14839 ARGF_FORWARD(0, 0);
14840 return rb_io_closed_p(ARGF.current_file);
14841}
14842
14843/*
14844 * call-seq:
14845 * ARGF.to_s -> String
14846 *
14847 * Returns "ARGF".
14848 */
14849static VALUE
14850argf_to_s(VALUE argf)
14851{
14852 return rb_str_new2("ARGF");
14853}
14854
14855/*
14856 * call-seq:
14857 * ARGF.inplace_mode -> String
14858 *
14859 * Returns the file extension appended to the names of backup copies of
14860 * modified files under in-place edit mode. This value can be set using
14861 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14862 */
14863static VALUE
14864argf_inplace_mode_get(VALUE argf)
14865{
14866 if (!ARGF.inplace) return Qnil;
14867 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14868 return rb_str_dup(ARGF.inplace);
14869}
14870
14871static VALUE
14872opt_i_get(ID id, VALUE *var)
14873{
14874 return argf_inplace_mode_get(*var);
14875}
14876
14877/*
14878 * call-seq:
14879 * ARGF.inplace_mode = ext -> ARGF
14880 *
14881 * Sets the filename extension for in-place editing mode to the given String.
14882 * The backup copy of each file being edited has this value appended to its
14883 * filename.
14884 *
14885 * For example:
14886 *
14887 * $ ruby argf.rb file.txt
14888 *
14889 * ARGF.inplace_mode = '.bak'
14890 * ARGF.each_line do |line|
14891 * print line.sub("foo","bar")
14892 * end
14893 *
14894 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14895 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14896 * "bar".
14897 */
14898static VALUE
14899argf_inplace_mode_set(VALUE argf, VALUE val)
14900{
14901 if (!RTEST(val)) {
14902 ARGF.inplace = Qfalse;
14903 }
14904 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14905 ARGF.inplace = Qnil;
14906 }
14907 else {
14908 ARGF_SET(inplace, rb_str_new_frozen(val));
14909 }
14910 return argf;
14911}
14912
14913static void
14914opt_i_set(VALUE val, ID id, VALUE *var)
14915{
14916 argf_inplace_mode_set(*var, val);
14917}
14918
14919void
14920ruby_set_inplace_mode(const char *suffix)
14921{
14922 ARGF_SET(inplace, !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix)));
14923}
14924
14925/*
14926 * call-seq:
14927 * ARGF.argv -> ARGV
14928 *
14929 * Returns the +ARGV+ array, which contains the arguments passed to your
14930 * script, one per element.
14931 *
14932 * For example:
14933 *
14934 * $ ruby argf.rb -v glark.txt
14935 *
14936 * ARGF.argv #=> ["-v", "glark.txt"]
14937 *
14938 */
14939static VALUE
14940argf_argv(VALUE argf)
14941{
14942 return ARGF.argv;
14943}
14944
14945static VALUE
14946argf_argv_getter(ID id, VALUE *var)
14947{
14948 return argf_argv(*var);
14949}
14950
14951VALUE
14953{
14954 return ARGF.argv;
14955}
14956
14957/*
14958 * call-seq:
14959 * ARGF.to_write_io -> io
14960 *
14961 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14962 * enabled.
14963 */
14964static VALUE
14965argf_write_io(VALUE argf)
14966{
14967 if (!RTEST(ARGF.current_file)) {
14968 rb_raise(rb_eIOError, "not opened for writing");
14969 }
14970 return GetWriteIO(ARGF.current_file);
14971}
14972
14973/*
14974 * call-seq:
14975 * ARGF.write(*objects) -> integer
14976 *
14977 * Writes each of the given +objects+ if inplace mode.
14978 */
14979static VALUE
14980argf_write(int argc, VALUE *argv, VALUE argf)
14981{
14982 return rb_io_writev(argf_write_io(argf), argc, argv);
14983}
14984
14985void
14986rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14987{
14988 rb_readwrite_syserr_fail(waiting, errno, mesg);
14989}
14990
14991void
14992rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14993{
14994 VALUE arg, c = Qnil;
14995 arg = mesg ? rb_str_new2(mesg) : Qnil;
14996 switch (waiting) {
14997 case RB_IO_WAIT_WRITABLE:
14998 switch (n) {
14999 case EAGAIN:
15000 c = rb_eEAGAINWaitWritable;
15001 break;
15002#if EAGAIN != EWOULDBLOCK
15003 case EWOULDBLOCK:
15004 c = rb_eEWOULDBLOCKWaitWritable;
15005 break;
15006#endif
15007 case EINPROGRESS:
15008 c = rb_eEINPROGRESSWaitWritable;
15009 break;
15010 default:
15012 }
15013 break;
15014 case RB_IO_WAIT_READABLE:
15015 switch (n) {
15016 case EAGAIN:
15017 c = rb_eEAGAINWaitReadable;
15018 break;
15019#if EAGAIN != EWOULDBLOCK
15020 case EWOULDBLOCK:
15021 c = rb_eEWOULDBLOCKWaitReadable;
15022 break;
15023#endif
15024 case EINPROGRESS:
15025 c = rb_eEINPROGRESSWaitReadable;
15026 break;
15027 default:
15029 }
15030 break;
15031 default:
15032 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
15033 }
15035}
15036
15037static VALUE
15038get_LAST_READ_LINE(ID _x, VALUE *_y)
15039{
15040 return rb_lastline_get();
15041}
15042
15043static void
15044set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
15045{
15046 rb_lastline_set(val);
15047}
15048
15049/*
15050 * Document-class: IOError
15051 *
15052 * Raised when an IO operation fails.
15053 *
15054 * File.open("/etc/hosts") {|f| f << "example"}
15055 * #=> IOError: not opened for writing
15056 *
15057 * File.open("/etc/hosts") {|f| f.close; f.read }
15058 * #=> IOError: closed stream
15059 *
15060 * Note that some IO failures raise <code>SystemCallError</code>s
15061 * and these are not subclasses of IOError:
15062 *
15063 * File.open("does/not/exist")
15064 * #=> Errno::ENOENT: No such file or directory - does/not/exist
15065 */
15066
15067/*
15068 * Document-class: EOFError
15069 *
15070 * Raised by some IO operations when reaching the end of file. Many IO
15071 * methods exist in two forms,
15072 *
15073 * one that returns +nil+ when the end of file is reached, the other
15074 * raises EOFError.
15075 *
15076 * EOFError is a subclass of IOError.
15077 *
15078 * file = File.open("/etc/hosts")
15079 * file.read
15080 * file.gets #=> nil
15081 * file.readline #=> EOFError: end of file reached
15082 * file.close
15083 */
15084
15085/*
15086 * Document-class: ARGF
15087 *
15088 * == \ARGF and +ARGV+
15089 *
15090 * The \ARGF object works with the array at global variable +ARGV+
15091 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
15092 *
15093 * - **ARGV** may be thought of as the <b>argument vector</b> array.
15094 *
15095 * Initially, it contains the command-line arguments and options
15096 * that are passed to the Ruby program;
15097 * the program can modify that array as it likes.
15098 *
15099 * - **ARGF** may be thought of as the <b>argument files</b> object.
15100 *
15101 * It can access file streams and/or the <tt>$stdin</tt> stream,
15102 * based on what it finds in +ARGV+.
15103 * This provides a convenient way for the command line
15104 * to specify streams for a Ruby program to read.
15105 *
15106 * == Reading
15107 *
15108 * \ARGF may read from _source_ streams,
15109 * which at any particular time are determined by the content of +ARGV+.
15110 *
15111 * === Simplest Case
15112 *
15113 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
15114 * the source is <tt>$stdin</tt>:
15115 *
15116 * - \File +t.rb+:
15117 *
15118 * p ['ARGV', ARGV]
15119 * p ['ARGF.read', ARGF.read]
15120 *
15121 * - Commands and outputs
15122 * (see below for the content of files +foo.txt+ and +bar.txt+):
15123 *
15124 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
15125 * ["ARGV", []]
15126 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15127 *
15128 * $ cat foo.txt bar.txt | ruby t.rb
15129 * ["ARGV", []]
15130 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
15131 *
15132 * === About the Examples
15133 *
15134 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
15135 *
15136 * $ cat foo.txt
15137 * Foo 0
15138 * Foo 1
15139 * $ cat bar.txt
15140 * Bar 0
15141 * Bar 1
15142 * Bar 2
15143 * Bar 3
15144 *
15145 * === Sources in +ARGV+
15146 *
15147 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
15148 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
15149 * the sources are found in +ARGV+.
15150 *
15151 * \ARGF assumes that each element in array +ARGV+ is a potential source,
15152 * and is one of:
15153 *
15154 * - The string path to a file that may be opened as a stream.
15155 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
15156 *
15157 * Each element that is _not_ one of these
15158 * should be removed from +ARGV+ before \ARGF accesses that source.
15159 *
15160 * In the following example:
15161 *
15162 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
15163 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
15164 *
15165 * Example:
15166 *
15167 * - \File +t.rb+:
15168 *
15169 * # Print arguments (and options, if any) found on command line.
15170 * p ['ARGV', ARGV]
15171 *
15172 * - Command and output:
15173 *
15174 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
15175 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
15176 *
15177 * \ARGF's stream access considers the elements of +ARGV+, left to right:
15178 *
15179 * - \File +t.rb+:
15180 *
15181 * p "ARGV: #{ARGV}"
15182 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
15183 *
15184 * - Command and output:
15185 *
15186 * $ ruby t.rb foo.txt bar.txt
15187 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15188 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15189 *
15190 * Because the value at +ARGV+ is an ordinary array,
15191 * you can manipulate it to control which sources \ARGF considers:
15192 *
15193 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
15194 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
15195 *
15196 * Each element in +ARGV+ is removed when its corresponding source is accessed;
15197 * when all sources have been accessed, the array is empty:
15198 *
15199 * - \File +t.rb+:
15200 *
15201 * until ARGV.empty? && ARGF.eof?
15202 * p "ARGV: #{ARGV}"
15203 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
15204 * end
15205 *
15206 * - Command and output:
15207 *
15208 * $ ruby t.rb foo.txt bar.txt
15209 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15210 * "Line: Foo 0\n"
15211 * "ARGV: [\"bar.txt\"]"
15212 * "Line: Foo 1\n"
15213 * "ARGV: [\"bar.txt\"]"
15214 * "Line: Bar 0\n"
15215 * "ARGV: []"
15216 * "Line: Bar 1\n"
15217 * "ARGV: []"
15218 * "Line: Bar 2\n"
15219 * "ARGV: []"
15220 * "Line: Bar 3\n"
15221 *
15222 * ==== Filepaths in +ARGV+
15223 *
15224 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
15225 *
15226 * This program prints what it reads from files at the paths specified
15227 * on the command line:
15228 *
15229 * - \File +t.rb+:
15230 *
15231 * p ['ARGV', ARGV]
15232 * # Read and print all content from the specified sources.
15233 * p ['ARGF.read', ARGF.read]
15234 *
15235 * - Command and output:
15236 *
15237 * $ ruby t.rb foo.txt bar.txt
15238 * ["ARGV", [foo.txt, bar.txt]
15239 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
15240 *
15241 * ==== Specifying <tt>$stdin</tt> in +ARGV+
15242 *
15243 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
15244 *
15245 * - \File +t.rb+:
15246 *
15247 * p ['ARGV', ARGV]
15248 * p ['ARGF.read', ARGF.read]
15249 *
15250 * - Command and output:
15251 *
15252 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
15253 * ["ARGV", ["-"]]
15254 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15255 *
15256 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored.
15257 *
15258 * - Command and output:
15259 *
15260 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
15261 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15262 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15263 *
15264 * ==== Mixtures and Repetitions in +ARGV+
15265 *
15266 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
15267 * and character <tt>'-'</tt>, including repetitions.
15268 *
15269 * ==== Modifications to +ARGV+
15270 *
15271 * The running Ruby program may make any modifications to the +ARGV+ array;
15272 * the current value of +ARGV+ affects \ARGF reading.
15273 *
15274 * ==== Empty +ARGV+
15275 *
15276 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15277 * or raises an exception, depending on the specific method.
15278 *
15279 * === More Read Methods
15280 *
15281 * As seen above, method ARGF#read reads the content of all sources
15282 * into a single string.
15283 * Other \ARGF methods provide other ways to access that content;
15284 * these include:
15285 *
15286 * - Byte access: #each_byte, #getbyte, #readbyte.
15287 * - Character access: #each_char, #getc, #readchar.
15288 * - Codepoint access: #each_codepoint.
15289 * - Line access: #each_line, #gets, #readline, #readlines.
15290 * - Source access: #read, #read_nonblock, #readpartial.
15291 *
15292 * === About \Enumerable
15293 *
15294 * \ARGF includes module Enumerable.
15295 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15296 *
15297 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15298 * _not_ from +ARGV+;
15299 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15300 * not an array of the strings from +ARGV+:
15301 *
15302 * - \File +t.rb+:
15303 *
15304 * p ['ARGV', ARGV]
15305 * p ['ARGF.entries', ARGF.entries]
15306 *
15307 * - Command and output:
15308 *
15309 * $ ruby t.rb foo.txt bar.txt
15310 * ["ARGV", ["foo.txt", "bar.txt"]]
15311 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15312 *
15313 * == Writing
15314 *
15315 * If <i>inplace mode</i> is in effect,
15316 * \ARGF may write to target streams,
15317 * which at any particular time are determined by the content of ARGV.
15318 *
15319 * Methods about inplace mode:
15320 *
15321 * - #inplace_mode
15322 * - #inplace_mode=
15323 * - #to_write_io
15324 *
15325 * Methods for writing:
15326 *
15327 * - #print
15328 * - #printf
15329 * - #putc
15330 * - #puts
15331 * - #write
15332 *
15333 */
15334
15335/*
15336 * An instance of class \IO (commonly called a _stream_)
15337 * represents an input/output stream in the underlying operating system.
15338 * Class \IO is the basis for input and output in Ruby.
15339 *
15340 * Class File is the only class in the Ruby core that is a subclass of \IO.
15341 * Some classes in the Ruby standard library are also subclasses of \IO;
15342 * these include TCPSocket and UDPSocket.
15343 *
15344 * The global constant ARGF (also accessible as <tt>$<</tt>)
15345 * provides an IO-like stream that allows access to all file paths
15346 * found in ARGV (or found in STDIN if ARGV is empty).
15347 * ARGF is not itself a subclass of \IO.
15348 *
15349 * Class StringIO provides an IO-like stream that handles a String.
15350 * StringIO is not itself a subclass of \IO.
15351 *
15352 * Important objects based on \IO include:
15353 *
15354 * - $stdin.
15355 * - $stdout.
15356 * - $stderr.
15357 * - Instances of class File.
15358 *
15359 * An instance of \IO may be created using:
15360 *
15361 * - IO.new: returns a new \IO object for the given integer file descriptor.
15362 * - IO.open: passes a new \IO object to the given block.
15363 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15364 * of a newly-launched subprocess.
15365 * - Kernel#open: Returns a new \IO object connected to a given source:
15366 * stream, file, or subprocess.
15367 *
15368 * Like a File stream, an \IO stream has:
15369 *
15370 * - A read/write mode, which may be read-only, write-only, or read/write;
15371 * see {Read/Write Mode}[rdoc-ref:File@ReadWrite+Mode].
15372 * - A data mode, which may be text-only or binary;
15373 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15374 * - Internal and external encodings;
15375 * see {Encodings}[rdoc-ref:File@Encodings].
15376 *
15377 * And like other \IO streams, it has:
15378 *
15379 * - A position, which determines where in the stream the next
15380 * read or write is to occur;
15381 * see {Position}[rdoc-ref:IO@Position].
15382 * - A line number, which is a special, line-oriented, "position"
15383 * (different from the position mentioned above);
15384 * see {Line Number}[rdoc-ref:IO@Line+Number].
15385 *
15386 * == Extension <tt>io/console</tt>
15387 *
15388 * Extension <tt>io/console</tt> provides numerous methods
15389 * for interacting with the console;
15390 * requiring it adds numerous methods to class \IO.
15391 *
15392 * == Example Files
15393 *
15394 * Many examples here use these variables:
15395 *
15396 * :include: doc/examples/files.rdoc
15397 *
15398 * == Open Options
15399 *
15400 * A number of \IO methods accept optional keyword arguments
15401 * that determine how a new stream is to be opened:
15402 *
15403 * - +:mode+: Stream mode.
15404 * - +:flags+: Integer file open flags;
15405 * If +mode+ is also given, the two are bitwise-ORed.
15406 * - +:external_encoding+: External encoding for the stream.
15407 * - +:internal_encoding+: Internal encoding for the stream.
15408 * <tt>'-'</tt> is a synonym for the default internal encoding.
15409 * If the value is +nil+ no conversion occurs.
15410 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15411 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15412 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15413 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15414 * when the stream closes; otherwise it remains open.
15415 * - +:path+: If a string value is provided, it is used in #inspect and is available as
15416 * #path method.
15417 *
15418 * Also available are the options offered in String#encode,
15419 * which may control conversion between external and internal encoding.
15420 *
15421 * == Basic \IO
15422 *
15423 * You can perform basic stream \IO with these methods,
15424 * which typically operate on multi-byte strings:
15425 *
15426 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15427 * - IO#write: Writes zero or more strings to the stream;
15428 * each given object that is not already a string is converted via +to_s+.
15429 *
15430 * === Position
15431 *
15432 * An \IO stream has a nonnegative integer _position_,
15433 * which is the byte offset at which the next read or write is to occur.
15434 * A new stream has position zero (and line number zero);
15435 * method +rewind+ resets the position (and line number) to zero.
15436 *
15437 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15438 * Encoding::Converter instances used for that \IO.
15439 *
15440 * The relevant methods:
15441 *
15442 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15443 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15444 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15445 * relative to a given position +whence+
15446 * (indicating the beginning, end, or current position).
15447 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15448 *
15449 * === Open and Closed Streams
15450 *
15451 * A new \IO stream may be open for reading, open for writing, or both.
15452 *
15453 * A stream is automatically closed when claimed by the garbage collector.
15454 *
15455 * Attempted reading or writing on a closed stream raises an exception.
15456 *
15457 * The relevant methods:
15458 *
15459 * - IO#close: Closes the stream for both reading and writing.
15460 * - IO#close_read: Closes the stream for reading.
15461 * - IO#close_write: Closes the stream for writing.
15462 * - IO#closed?: Returns whether the stream is closed.
15463 *
15464 * === End-of-Stream
15465 *
15466 * You can query whether a stream is positioned at its end:
15467 *
15468 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15469 *
15470 * You can reposition to end-of-stream by using method IO#seek:
15471 *
15472 * f = File.new('t.txt')
15473 * f.eof? # => false
15474 * f.seek(0, :END)
15475 * f.eof? # => true
15476 * f.close
15477 *
15478 * Or by reading all stream content (which is slower than using IO#seek):
15479 *
15480 * f.rewind
15481 * f.eof? # => false
15482 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15483 * f.eof? # => true
15484 *
15485 * == Line \IO
15486 *
15487 * Class \IO supports line-oriented
15488 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15489 *
15490 * === Line Input
15491 *
15492 * Class \IO supports line-oriented input for
15493 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input].
15494 *
15495 * ==== Line Input Options
15496 *
15497 * Optional keyword argument +chomp+ (default: +false+)
15498 * specifies whether line separators are to be excluded from the result of a read.
15499 *
15500 * ==== \File Line Input
15501 *
15502 * You can read lines from a file using these methods:
15503 *
15504 * - IO.foreach: Reads each line and passes it to the given block.
15505 * - IO.readlines: Reads and returns all lines in an array.
15506 *
15507 * For each of these methods:
15508 *
15509 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15510 * - Line parsing depends on the effective <i>line separator</i>;
15511 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15512 * - The length of each returned line depends on the effective <i>line limit</i>;
15513 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15514 *
15515 * ==== Stream Line Input
15516 *
15517 * You can read lines from an \IO stream using these methods:
15518 *
15519 * - IO#each_line: Reads each remaining line, passing it to the given block.
15520 * - IO#gets: Returns the next line.
15521 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15522 * - IO#readlines: Returns all remaining lines in an array.
15523 *
15524 * For each of these methods:
15525 *
15526 * - Reading may begin mid-line,
15527 * depending on the stream's _position_;
15528 * see {Position}[rdoc-ref:IO@Position].
15529 * - Line parsing depends on the effective <i>line separator</i>;
15530 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15531 * - The length of each returned line depends on the effective <i>line limit</i>;
15532 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15533 *
15534 * ===== Line Separator
15535 *
15536 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15537 * the string that determines what is considered a line;
15538 * it is sometimes called the <i>input record separator</i>.
15539 *
15540 * The default line separator is taken from global variable <tt>$/</tt>,
15541 * whose initial value is <tt>"\n"</tt>.
15542 *
15543 * Generally, the line to be read next is all data
15544 * from the current {position}[rdoc-ref:IO@Position]
15545 * to the next line separator
15546 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15547 *
15548 * f = File.new('t.txt')
15549 * # Method gets with no sep argument returns the next line, according to $/.
15550 * f.gets # => "First line\n"
15551 * f.gets # => "Second line\n"
15552 * f.gets # => "\n"
15553 * f.gets # => "Fourth line\n"
15554 * f.gets # => "Fifth line\n"
15555 * f.close
15556 *
15557 * You can use a different line separator by passing argument +sep+:
15558 *
15559 * f = File.new('t.txt')
15560 * f.gets('l') # => "First l"
15561 * f.gets('li') # => "ine\nSecond li"
15562 * f.gets('lin') # => "ne\n\nFourth lin"
15563 * f.gets # => "e\n"
15564 * f.close
15565 *
15566 * Or by setting global variable <tt>$/</tt>:
15567 *
15568 * f = File.new('t.txt')
15569 * $/ = 'l'
15570 * f.gets # => "First l"
15571 * f.gets # => "ine\nSecond l"
15572 * f.gets # => "ine\n\nFourth l"
15573 * f.close
15574 *
15575 * ===== Special Line Separator Values
15576 *
15577 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15578 * accepts two special values for parameter +sep+:
15579 *
15580 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15581 *
15582 * f = File.new('t.txt')
15583 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15584 * f.close
15585 *
15586 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15587 * (paragraphs being separated by two consecutive line separators):
15588 *
15589 * f = File.new('t.txt')
15590 * f.gets('') # => "First line\nSecond line\n\n"
15591 * f.gets('') # => "Fourth line\nFifth line\n"
15592 * f.close
15593 *
15594 * ===== Line Limit
15595 *
15596 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15597 * uses an integer <i>line limit</i>,
15598 * which restricts the number of bytes that may be returned.
15599 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15600 * than the limit).
15601 *
15602 * The default limit value is <tt>-1</tt>;
15603 * any negative limit value means that there is no limit.
15604 *
15605 * If there is no limit, the line is determined only by +sep+.
15606 *
15607 * # Text with 1-byte characters.
15608 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15609 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15610 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15611 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15612 * # No more than one line.
15613 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15614 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15615 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15616 *
15617 * # Text with 3-byte characters, which will not be split.
15618 * File.read('t.ja') # => "こんにちは"
15619 * File.open('t.ja') {|f| f.gets(1).size } # => 1
15620 * File.open('t.ja') {|f| f.gets(2).size } # => 1
15621 * File.open('t.ja') {|f| f.gets(3).size } # => 1
15622 * File.open('t.ja') {|f| f.gets(4).size } # => 2
15623 * File.open('t.ja') {|f| f.gets(5).size } # => 2
15624 *
15625 * ===== Line Separator and Line Limit
15626 *
15627 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15628 *
15629 * - Returns the next line as determined by line separator +sep+.
15630 * - But returns no more bytes than are allowed by the limit +limit+.
15631 *
15632 * Example:
15633 *
15634 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15635 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15636 *
15637 * ===== Line Number
15638 *
15639 * A readable \IO stream has a non-negative integer <i>line number</i>:
15640 *
15641 * - IO#lineno: Returns the line number.
15642 * - IO#lineno=: Resets and returns the line number.
15643 *
15644 * Unless modified by a call to method IO#lineno=,
15645 * the line number is the number of lines read
15646 * by certain line-oriented methods,
15647 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15648 *
15649 * - IO.foreach: Increments the line number on each call to the block.
15650 * - IO#each_line: Increments the line number on each call to the block.
15651 * - IO#gets: Increments the line number.
15652 * - IO#readline: Increments the line number.
15653 * - IO#readlines: Increments the line number for each line read.
15654 *
15655 * A new stream is initially has line number zero (and position zero);
15656 * method +rewind+ resets the line number (and position) to zero:
15657 *
15658 * f = File.new('t.txt')
15659 * f.lineno # => 0
15660 * f.gets # => "First line\n"
15661 * f.lineno # => 1
15662 * f.rewind
15663 * f.lineno # => 0
15664 * f.close
15665 *
15666 * Reading lines from a stream usually changes its line number:
15667 *
15668 * f = File.new('t.txt', 'r')
15669 * f.lineno # => 0
15670 * f.readline # => "This is line one.\n"
15671 * f.lineno # => 1
15672 * f.readline # => "This is the second line.\n"
15673 * f.lineno # => 2
15674 * f.readline # => "Here's the third line.\n"
15675 * f.lineno # => 3
15676 * f.eof? # => true
15677 * f.close
15678 *
15679 * Iterating over lines in a stream usually changes its line number:
15680 *
15681 * File.open('t.txt') do |f|
15682 * f.each_line do |line|
15683 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15684 * end
15685 * end
15686 *
15687 * Output:
15688 *
15689 * "position=11 eof?=false lineno=1"
15690 * "position=23 eof?=false lineno=2"
15691 * "position=24 eof?=false lineno=3"
15692 * "position=36 eof?=false lineno=4"
15693 * "position=47 eof?=true lineno=5"
15694 *
15695 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15696 * the line number does not affect where the next read or write will occur:
15697 *
15698 * f = File.new('t.txt')
15699 * f.lineno = 1000
15700 * f.lineno # => 1000
15701 * f.gets # => "First line\n"
15702 * f.lineno # => 1001
15703 * f.close
15704 *
15705 * Associated with the line number is the global variable <tt>$.</tt>:
15706 *
15707 * - When a stream is opened, <tt>$.</tt> is not set;
15708 * its value is left over from previous activity in the process:
15709 *
15710 * $. = 41
15711 * f = File.new('t.txt')
15712 * $. = 41
15713 * # => 41
15714 * f.close
15715 *
15716 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15717 *
15718 * f0 = File.new('t.txt')
15719 * f1 = File.new('t.dat')
15720 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15721 * $. # => 5
15722 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15723 * $. # => 1
15724 * f0.close
15725 * f1.close
15726 *
15727 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15728 *
15729 * f = File.new('t.txt')
15730 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15731 * $. # => 5
15732 * f.rewind
15733 * f.seek(0, :SET)
15734 * $. # => 5
15735 * f.close
15736 *
15737 * === Line Output
15738 *
15739 * You can write to an \IO stream line-by-line using this method:
15740 *
15741 * - IO#puts: Writes objects to the stream.
15742 *
15743 * == Character \IO
15744 *
15745 * You can process an \IO stream character-by-character using these methods:
15746 *
15747 * - IO#getc: Reads and returns the next character from the stream.
15748 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15749 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15750 * - IO#putc: Writes a character to the stream.
15751 * - IO#each_char: Reads each remaining character in the stream,
15752 * passing the character to the given block.
15753 *
15754 * == Byte \IO
15755 *
15756 * You can process an \IO stream byte-by-byte using these methods:
15757 *
15758 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15759 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15760 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15761 * - IO#each_byte: Reads each remaining byte in the stream,
15762 * passing the byte to the given block.
15763 *
15764 * == Codepoint \IO
15765 *
15766 * You can process an \IO stream codepoint-by-codepoint:
15767 *
15768 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15769 *
15770 * == What's Here
15771 *
15772 * First, what's elsewhere. Class \IO:
15773 *
15774 * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
15775 * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
15776 * which provides dozens of additional methods.
15777 *
15778 * Here, class \IO provides methods that are useful for:
15779 *
15780 * - {Creating}[rdoc-ref:IO@Creating]
15781 * - {Reading}[rdoc-ref:IO@Reading]
15782 * - {Writing}[rdoc-ref:IO@Writing]
15783 * - {Positioning}[rdoc-ref:IO@Positioning]
15784 * - {Iterating}[rdoc-ref:IO@Iterating]
15785 * - {Settings}[rdoc-ref:IO@Settings]
15786 * - {Querying}[rdoc-ref:IO@Querying]
15787 * - {Buffering}[rdoc-ref:IO@Buffering]
15788 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15789 * - {Other}[rdoc-ref:IO@Other]
15790 *
15791 * === Creating
15792 *
15793 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15794 * integer file descriptor.
15795 * - ::open: Creates a new \IO object.
15796 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15797 * - ::popen: Creates an \IO object to interact with a subprocess.
15798 * - ::select: Selects which given \IO instances are ready for reading,
15799 * writing, or have pending exceptions.
15800 *
15801 * === Reading
15802 *
15803 * - ::binread: Returns a binary string with all or a subset of bytes
15804 * from the given file.
15805 * - ::read: Returns a string with all or a subset of bytes from the given file.
15806 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15807 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15808 * - #getc: Returns the next character read from +self+ as a string.
15809 * - #gets: Returns the line read from +self+.
15810 * - #pread: Returns all or the next _n_ bytes read from +self+,
15811 * not updating the receiver's offset.
15812 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15813 * for a given _n_.
15814 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15815 * in non-block mode.
15816 * - #readbyte: Returns the next byte read from +self+;
15817 * same as #getbyte, but raises an exception on end-of-stream.
15818 * - #readchar: Returns the next character read from +self+;
15819 * same as #getc, but raises an exception on end-of-stream.
15820 * - #readline: Returns the next line read from +self+;
15821 * same as #getline, but raises an exception of end-of-stream.
15822 * - #readlines: Returns an array of all lines read read from +self+.
15823 * - #readpartial: Returns up to the given number of bytes from +self+.
15824 *
15825 * === Writing
15826 *
15827 * - ::binwrite: Writes the given string to the file at the given filepath,
15828 * in binary mode.
15829 * - ::write: Writes the given string to +self+.
15830 * - #<<: Appends the given string to +self+.
15831 * - #print: Prints last read line or given objects to +self+.
15832 * - #printf: Writes to +self+ based on the given format string and objects.
15833 * - #putc: Writes a character to +self+.
15834 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15835 * - #pwrite: Writes the given string at the given offset,
15836 * not updating the receiver's offset.
15837 * - #write: Writes one or more given strings to +self+.
15838 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15839 *
15840 * === Positioning
15841 *
15842 * - #lineno: Returns the current line number in +self+.
15843 * - #lineno=: Sets the line number is +self+.
15844 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15845 * - #pos=: Sets the byte offset in +self+.
15846 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15847 * - #rewind: Positions +self+ to the beginning of input.
15848 * - #seek: Sets the offset for +self+ relative to given position.
15849 *
15850 * === Iterating
15851 *
15852 * - ::foreach: Yields each line of given file to the block.
15853 * - #each (aliased as #each_line): Calls the given block
15854 * with each successive line in +self+.
15855 * - #each_byte: Calls the given block with each successive byte in +self+
15856 * as an integer.
15857 * - #each_char: Calls the given block with each successive character in +self+
15858 * as a string.
15859 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15860 * as an integer.
15861 *
15862 * === Settings
15863 *
15864 * - #autoclose=: Sets whether +self+ auto-closes.
15865 * - #binmode: Sets +self+ to binary mode.
15866 * - #close: Closes +self+.
15867 * - #close_on_exec=: Sets the close-on-exec flag.
15868 * - #close_read: Closes +self+ for reading.
15869 * - #close_write: Closes +self+ for writing.
15870 * - #set_encoding: Sets the encoding for +self+.
15871 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15872 * Unicode byte-order-mark.
15873 * - #sync=: Sets the sync-mode to the given value.
15874 *
15875 * === Querying
15876 *
15877 * - #autoclose?: Returns whether +self+ auto-closes.
15878 * - #binmode?: Returns whether +self+ is in binary mode.
15879 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15880 * - #closed?: Returns whether +self+ is closed.
15881 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15882 * - #external_encoding: Returns the external encoding object for +self+.
15883 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15884 * - #internal_encoding: Returns the internal encoding object for +self+.
15885 * - #pid: Returns the process ID of a child process associated with +self+,
15886 * if +self+ was created by ::popen.
15887 * - #stat: Returns the File::Stat object containing status information for +self+.
15888 * - #sync: Returns whether +self+ is in sync-mode.
15889 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15890 *
15891 * === Buffering
15892 *
15893 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15894 * - #flush: Flushes any buffered data within +self+ to the underlying
15895 * operating system.
15896 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15897 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15898 * - #ungetc: Prepends buffer for +self+ with given string.
15899 *
15900 * === Low-Level Access
15901 *
15902 * - ::sysopen: Opens the file given by its path,
15903 * returning the integer file descriptor.
15904 * - #advise: Announces the intention to access data from +self+ in a specific way.
15905 * - #fcntl: Passes a low-level command to the file specified
15906 * by the given file descriptor.
15907 * - #ioctl: Passes a low-level command to the device specified
15908 * by the given file descriptor.
15909 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15910 * - #sysseek: Sets the offset for +self+.
15911 * - #syswrite: Writes the given string to +self+ using a low-level write.
15912 *
15913 * === Other
15914 *
15915 * - ::copy_stream: Copies data from a source to a destination,
15916 * each of which is a filepath or an \IO-like object.
15917 * - ::try_convert: Returns a new \IO object resulting from converting
15918 * the given object.
15919 * - #inspect: Returns the string representation of +self+.
15920 *
15921 */
15922
15923void
15924Init_IO(void)
15925{
15926 VALUE rb_cARGF;
15927#ifdef __CYGWIN__
15928#include <sys/cygwin.h>
15929 static struct __cygwin_perfile pf[] =
15930 {
15931 {"", O_RDONLY | O_BINARY},
15932 {"", O_WRONLY | O_BINARY},
15933 {"", O_RDWR | O_BINARY},
15934 {"", O_APPEND | O_BINARY},
15935 {NULL, 0}
15936 };
15937 cygwin_internal(CW_PERFILE, pf);
15938#endif
15939
15940 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
15941 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
15942
15943 id_write = rb_intern_const("write");
15944 id_read = rb_intern_const("read");
15945 id_flush = rb_intern_const("flush");
15946 id_readpartial = rb_intern_const("readpartial");
15947 id_set_encoding = rb_intern_const("set_encoding");
15948 id_fileno = rb_intern_const("fileno");
15949
15950 rb_define_global_function("syscall", rb_f_syscall, -1);
15951
15952 rb_define_global_function("open", rb_f_open, -1);
15953 rb_define_global_function("printf", rb_f_printf, -1);
15954 rb_define_global_function("print", rb_f_print, -1);
15955 rb_define_global_function("putc", rb_f_putc, 1);
15956 rb_define_global_function("puts", rb_f_puts, -1);
15957 rb_define_global_function("gets", rb_f_gets, -1);
15958 rb_define_global_function("readline", rb_f_readline, -1);
15959 rb_define_global_function("select", rb_f_select, -1);
15960
15961 rb_define_global_function("readlines", rb_f_readlines, -1);
15962
15963 rb_define_global_function("`", rb_f_backquote, 1);
15964
15965 rb_define_global_function("p", rb_f_p, -1);
15966 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15967
15968 rb_cIO = rb_define_class("IO", rb_cObject);
15970
15971 /* Can be raised by IO operations when IO#timeout= is set. */
15972 rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
15973
15974 /* Readable event mask for IO#wait. */
15975 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15976 /* Writable event mask for IO#wait. */
15977 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15978 /* Priority event mask for IO#wait. */
15979 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15980
15981 /* exception to wait for reading. see IO.select. */
15982 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
15983 /* exception to wait for writing. see IO.select. */
15984 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
15985 /* exception to wait for reading by EAGAIN. see IO.select. */
15986 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15987 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15988 /* exception to wait for writing by EAGAIN. see IO.select. */
15989 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15990 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15991#if EAGAIN == EWOULDBLOCK
15992 /* same as IO::EAGAINWaitReadable */
15993 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15994 /* same as IO::EAGAINWaitWritable */
15995 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15996#else
15997 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15998 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15999 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
16000 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
16001 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
16002 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
16003#endif
16004 /* exception to wait for reading by EINPROGRESS. see IO.select. */
16005 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
16006 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
16007 /* exception to wait for writing by EINPROGRESS. see IO.select. */
16008 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
16009 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
16010
16011#if 0
16012 /* This is necessary only for forcing rdoc handle File::open */
16013 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
16014#endif
16015
16016 rb_define_alloc_func(rb_cIO, io_alloc);
16017 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
16018 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
16019 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
16020 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
16021 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
16022 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
16023 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
16024 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
16025 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
16026 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
16027 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
16028 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
16029 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
16030 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
16031 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
16032
16033 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
16034
16036 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
16037
16038 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
16039 rb_vm_register_global_object(rb_default_rs);
16040 rb_rs = rb_default_rs;
16042 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
16043 rb_gvar_ractor_local("$/"); // not local but ractor safe
16044 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
16045 rb_gvar_ractor_local("$-0"); // not local but ractor safe
16046 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
16047
16048 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
16049 rb_gvar_ractor_local("$_");
16050 rb_gvar_box_dynamic("$_");
16051
16052 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
16053 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
16054
16055 rb_define_method(rb_cIO, "print", rb_io_print, -1);
16056 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
16057 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
16058 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
16059
16060 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
16061 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
16062 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
16063 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
16064 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
16065
16066 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
16067 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
16068
16069 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
16070 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
16071
16072 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
16073 rb_define_alias(rb_cIO, "to_i", "fileno");
16074 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
16075
16076 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
16077 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
16078
16079 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
16080 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
16081 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
16082 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
16083
16084 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
16085 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
16086
16087 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
16088
16089 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
16090 rb_define_method(rb_cIO, "read", io_read, -1);
16091 rb_define_method(rb_cIO, "write", io_write_m, -1);
16092 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
16093 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
16094 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
16095 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
16096 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
16097 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
16098 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
16100 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
16101 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
16102 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
16103 /* Set I/O position from the beginning */
16104 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
16105 /* Set I/O position from the current position */
16106 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
16107 /* Set I/O position from the end */
16108 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
16109#ifdef SEEK_DATA
16110 /* Set I/O position to the next location containing data */
16111 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
16112#endif
16113#ifdef SEEK_HOLE
16114 /* Set I/O position to the next hole */
16115 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
16116#endif
16117 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
16118 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
16119 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
16120 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
16121 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
16122
16123 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
16124 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
16125
16126 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
16127 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
16128 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
16129 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
16130
16131 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
16132 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
16133 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
16134 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
16135 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
16136 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
16137
16138 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
16139 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
16140 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
16141
16142 rb_define_method(rb_cIO, "path", rb_io_path, 0);
16143 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
16144
16145 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
16146
16147 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
16148 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
16149 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
16150 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
16151
16152 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
16153 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
16154
16155 rb_define_method(rb_cIO, "wait", io_wait, -1);
16156
16157 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
16158 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
16159 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
16160
16161 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
16162 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
16163 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
16164 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
16165
16166 rb_gvar_ractor_local("$stdin");
16167 rb_gvar_ractor_local("$stdout");
16168 rb_gvar_ractor_local("$>");
16169 rb_gvar_ractor_local("$stderr");
16170
16171 rb_gvar_box_dynamic("$stdin");
16172 rb_gvar_box_dynamic("$stdout");
16173 rb_gvar_box_dynamic("$>");
16174 rb_gvar_box_dynamic("$stderr");
16175
16177 rb_stdin = rb_io_prep_stdin();
16179 rb_stdout = rb_io_prep_stdout();
16181 rb_stderr = rb_io_prep_stderr();
16182
16183 orig_stdout = rb_stdout;
16184 orig_stderr = rb_stderr;
16185
16186 /* Holds the original stdin */
16188 /* Holds the original stdout */
16190 /* Holds the original stderr */
16192
16193#if 0
16194 /* Hack to get rdoc to regard ARGF as a class: */
16195 rb_cARGF = rb_define_class("ARGF", rb_cObject);
16196#endif
16197
16198 rb_cARGF = rb_class_new(rb_cObject);
16199 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
16200 rb_define_alloc_func(rb_cARGF, argf_alloc);
16201
16203
16204 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
16205 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
16206 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
16207 rb_define_alias(rb_cARGF, "inspect", "to_s");
16208 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
16209
16210 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
16211 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
16212 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
16213 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
16214 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
16215 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
16216 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
16217 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
16218 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
16219
16220 rb_define_method(rb_cARGF, "read", argf_read, -1);
16221 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
16222 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
16223 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
16224 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
16225 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
16226 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
16227 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
16228 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
16229 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
16230 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
16231 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
16232 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
16233 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
16234 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
16235 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
16236 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
16237 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
16238 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
16239 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
16240
16241 rb_define_method(rb_cARGF, "write", argf_write, -1);
16242 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
16243 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
16244 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
16245 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
16246
16247 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
16248 rb_define_method(rb_cARGF, "path", argf_filename, 0);
16249 rb_define_method(rb_cARGF, "file", argf_file, 0);
16250 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
16251 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
16252 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
16253
16254 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
16255 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
16256
16257 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
16258 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
16259
16260 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
16261 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
16262 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
16263
16264 argf = rb_class_new_instance(0, 0, rb_cARGF);
16265
16267 /*
16268 * ARGF is a stream designed for use in scripts that process files given
16269 * as command-line arguments or passed in via STDIN.
16270 *
16271 * See ARGF (the class) for more details.
16272 */
16274
16275 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
16276 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
16277 ARGF_SET(filename, rb_str_new2("-"));
16278
16279 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
16280 rb_gvar_ractor_local("$-i");
16281
16282 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16283
16284#if defined (_WIN32) || defined(__CYGWIN__)
16285 atexit(pipe_atexit);
16286#endif
16287
16288 Init_File();
16289
16290 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16291
16292 sym_mode = ID2SYM(rb_intern_const("mode"));
16293 sym_perm = ID2SYM(rb_intern_const("perm"));
16294 sym_flags = ID2SYM(rb_intern_const("flags"));
16295 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16296 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16297 sym_encoding = ID2SYM(rb_id_encoding());
16298 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16299 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16300 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16301 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16302 sym_normal = ID2SYM(rb_intern_const("normal"));
16303 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16304 sym_random = ID2SYM(rb_intern_const("random"));
16305 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16306 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16307 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16308 sym_SET = ID2SYM(rb_intern_const("SET"));
16309 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16310 sym_END = ID2SYM(rb_intern_const("END"));
16311#ifdef SEEK_DATA
16312 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16313#endif
16314#ifdef SEEK_HOLE
16315 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16316#endif
16317 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16318 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16319}
16320
16321static void init_builtin_io(void);
16322#define Init_builtin_io init_builtin_io
16323#include "io.rbinc"
16324#undef Init_builtin_io
16325
16326void
16327Init_builtin_io(void)
16328{
16329 init_builtin_io();
16330
16331 /* Init_IO is called earlier than `loaded_features` is initialized */
16332 rb_provide("io/wait.rb");
16333 rb_provide("io/wait.so");
16334}
#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:1769
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:853
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:3094
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:3397
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:3384
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:3173
#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 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 ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:111
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:520
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:109
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition ctype.h:103
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:518
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition transcode.h:538
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:519
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h: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:478
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:510
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1483
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:678
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:4084
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
Definition io.c:14992
VALUE rb_eIOError
IOError exception.
Definition io.c:189
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1470
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:4174
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:4090
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:476
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1473
VALUE rb_eEOFError
EOFError exception.
Definition io.c:188
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14986
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2395
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1471
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:468
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1493
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:59
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3334
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:2252
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2293
VALUE rb_cIO
IO class.
Definition io.c:187
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:2281
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:28
VALUE rb_stdin
STDIN constant.
Definition io.c:203
VALUE rb_stderr
STDERR constant.
Definition io.c:203
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:191
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:192
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:3315
VALUE rb_cFile
File class.
Definition file.c:175
VALUE rb_stdout
STDOUT constant.
Definition io.c:203
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3328
#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
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3946
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c:844
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
Definition transcode.c:2679
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
Definition transcode.c:2126
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
Definition transcode.c:1487
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
Definition transcode.h:69
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
Definition transcode.h:41
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1783
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1827
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
Definition transcode.c:1962
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
Definition transcode.c:2730
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
Definition transcode.c:2025
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
Definition transcode.c:2993
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4359
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4365
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1744
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1794
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1123
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
Definition vm_eval.c:1090
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
Definition vm_eval.c:1081
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:242
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8873
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4558
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:487
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:9006
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2438
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9435
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:5430
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5335
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:385
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:9616
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:283
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:346
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:208
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2780
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
Definition io.c:9415
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:333
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6673
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6627
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5494
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7674
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10704
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:493
VALUE rb_output_fs
The field separator character for outputs, or the $,.
Definition io.c:206
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:7558
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:378
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7565
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:6030
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:209
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:2157
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:2151
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
Definition proc.c:3761
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1161
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:676
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3913
#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
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:2038
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3681
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:4382
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
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3500
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:3855
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:3047
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3363
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3482
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2816
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1769
#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:1678
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:1672
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1668
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2984
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:459
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:2141
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:518
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3693
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:3571
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
Definition vm_eval.c:691
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:285
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
Definition variable.c:4095
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
Definition variable.c:890
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:162
enum rb_io_mode rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
Definition io.c:6759
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:828
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:874
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:798
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1112
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:6892
#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:1058
#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:1067
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:1664
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:7375
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:7041
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2979
#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:9662
#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:1731
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:1684
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:190
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:3058
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:7166
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:805
#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:5941
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:834
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:6138
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:903
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:2095
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:1039
#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:840
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3545
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1620
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:9528
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:851
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1091
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:1746
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:813
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1585
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7666
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1525
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:14952
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9314
#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:238
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
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.